一、从父Activity启动子Activity并传递数据
Intent的中文意思是“意图,目的”的意思,可以理解为不同组件之间通信的“媒介”或者“信使”。 Intent由以下几个部分组成:动作(action),数据(data),分类(Category),类型(Type),组件(Component),和扩展信息(Extra)。
Intent应该算是Android中特有的东西。你可以在Intent中指定程序要执行的动作(比如:view,edit,dial),以及程序执行到该动作时所需要的资料。都指定好后,只要调用startActivity(),Android系统会自动寻找最符合你指定要求的应用程序,并执行该程序。
四大组件中的Activity、Services、BroadCastProvider都是通过Intent传递数据。
Activity 的 Intent 用到的 Action 主要有以下几种:
android.intent.action.MAIN 应用程序入口
android.intent.action.VIEW 显示数据给用户
android.intent.action.DIAL 直接打电话
android.intent.action.SEND 直接发短信
android.intent.action.RUN 运行数据
android.intent.action.SEARCH 搜索
在本例中,父Activity:BasicActivity 子Activity:SubActivity
(1) 显式Intent
1、在BasicActivity中启动SubActivity,并携带信息
BasicActivity.java
//用Intent绑定两个Activity
Intent intent = new Intent(BasicActivity.this,SubActivity.class);
intent.putExtra("data_tag","hello sub activity");//用Extra携带信息
startActivity(intent);//从BasicActivity启动SubActivity
2、从SubActivity中读取上面来自BasicActivity的信息
利用标签 "data_tag"传递数据。
SubActivity.java
Intent intent = getIntent();
String msg = intent.getStringExtra("data_tag");//从intent中读取信息
Log.d(TAG,"msg from parent: " + msg);
显式Intent 是通过BasicActivity.this对象和SubActivity.class来将两个Activity关联起来的。
(2) 隐式Intent
1、 隐式Intent需要去AndroidManifest.xml文件中对Intent进行配置,注册SubActivity并定义intent-filter的Action(行为)和Category(种类)对intent进行过滤,只有一个intent的action和category都匹配,才能启动这个Activity。
<activity android:name=".SubActivity">
<intent-filter>
<!-- 下述定义用于隐式intent,自定义了action和category -->
<action android:name="com.example.yy.ACTION_START_SUB"/>
<category android:name="com.example.yy.MY_CATEGORY"/>
</intent-filter>
</activity>
然后在BasicActivity中以下列方式创建Intent并用其启动intent,系统会进行action和category的匹配,最后选择启动SubActivity,因为SubActivity中的action和category与这个intent完全匹配。
BasicActivity.java
//利用xml中的配置信息关联BasicActivity和SubActivity
Intent intent = new Intent("com.example.yy.ACTION_START_SUB");
intent.addCategory("com.example.yy.MY_CATEGORY");
intent.putExtra("data_tag","hello sub activity");//用Extra携带信息
startActivity(intent);
隐式Intent 是通过xml文件中的配置将两个Activity关联起来的。
2、从SubActivity中读取上面来自BasicActivity的信息
接收信息与显式Intent相同
SubActivity.java
Intent intent = getIntent();
String msg = intent.getStringExtra("data_tag");//从intent中读取信息
Log.d(TAG,"msg from parent: " + msg);
(3) 其他隐式Intent
想在app中展示网页的时候,可以用下列方式,app会调用操作系统的浏览器去访问指定网页,系统浏览器中的intent-filter的action就是Intent.ACTION_VIEW。
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("http://www.baidu.com"));
intent.putExtra("extra","subActivity");
startActivity(intent);
如果自定义一个Activity,让其intent-filter的action也为Intent.ACTION_VIEW,那么启动该intent的时候,就会同时匹配系统浏览器和自定义的这个Activity,系统会弹出选择框,让用户选择打开方式。
二、子Activity被启动后如何返回数据给父Activity
1、 首先,要想让子Activity被启动之后能够反馈数据给父Activity,那么父Activity在启动子Activity的时候,必须使用startActivityForResult()方法,而不是前面的startActivity()方法。将前面的startActivity(intent)替换成下列代码即可:
BasicActivity.java
startActivityForResult(intent,REQUEST_CODE_SUB);
//REQUEST_CODE_SUB是一个整型常量,是一个与子Activity通信的标识
2、 同时,在接收端SubActivity也需要有一定的修改,SubActivity不仅要接收来自BasicActivity的数据,还要反馈数据给BasicActivity:
SubActivity.java
//在SubActivity中创建一个Intent,并绑定反馈信息
Intent intent = new Intent();
intent.putExtra("data_return_tag","the echoed message");
//设置ResultCode,成功就是RESULT_OK,失败就是RESULT_CANCELED
setResult(RESULT_OK,intent);
//终止SubActivity
finish();
3、最后,BasicActivity必须在 onActivityResult()方法 中接收来自SubActivity的反馈数据
在BasicActivity中重写onActivityResult()方法,添加接收反馈数据的逻辑:
BasicActivity.java
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
switch (requestCode){
case REQUEST_CODE_SUB:
if (resultCode == RESULT_OK){
String msgFromSub = data.getStringExtra("data_return_tag");
Log.d("Basic","msg echoed from sub: " + msgFromSub);
}
break;
default:
}
}
三、返回栈
Android中的Activity是可以层叠的,每启动一个新的Activity,它会叠放在父Activity之上,是以栈的形式存放Activity,每个栈由一个Task去管理,用户点击back按钮的时候会销毁栈顶的Activity,下面的那个Activity就会显示出来。
Activity的状态有下面几种:
(1) 运行
处于栈顶的Activity是运行状体,系统不会轻易清理运行时的Activity
(2) 暂停
不处于栈顶但是仍然可见的Activity处于暂停状态,如对话框形式的DialogActivity,当MainActivity启动一个DialogActivity后,MainActivity虽然不在栈顶,但是依然可见(没有被DialogActivity完全挡住),只有在内存极低的情况下,系统才会去清理这种状态的Activity
(3) 停止
Activity不处于栈顶,并且完全不可见,那么它就处于停止状态,虽然系统会为它们保存状态和成员变量,但是这并不靠谱,它们随时会被系统回收
(4) 销毁
当一个Activity从栈中移除后,就处于销毁状态,系统最倾向于将它们回收
四、Activity的生命周期方法
onCreate()
activity在第一次被创建的时候调用,该方法中通常完成一些初始化操作,如加载布局和绑定事件等
onStart()
当Activity从不可见变为可见的时候调用
onResume()
当activity处于运行状态的时候调用,这时activity位于栈顶
onPause()
当系统准备启动或者回复另一个Activity的时候调用,通常在该方法中释放一些资源和保存关键数据。
onStop()
当Activity变得完全不可见的时候调用
onDestroy()
当Activity被销毁之前调用,调用之后,Activity就被销毁了
onRestart()
当Activity从停止状态变为运行状态的时刻调用,也就是Activity被重新启动了
完整生存期 onCreate()和onDestroy()
这两个方法之间是Activity的完整生命期,从onCreate()创建,从onDestroy()销毁
可见生存期 onStart()和onStop()
这两个方法之间是Activity的可见时间,在这段时间,Activity虽然可能与用户无法交互,但是对用户是可见的。我们可以通过这两个方法合理地管理用户可见的资源。通常在onStart中对资源进行加载,在onStop中对资源进行释放。
前台生存期 onResume()和onPause()
这两个方法之间是Activity的前台生存期,在这段时间,Activity是可见的,并且可以与用户交互。
五、Activity的启动模式
1、standard
这种模式下,如果多次启动FirstActivity,栈中就会出现三个FirstActivity,要想退出应用,得按下3次back才行。
2、singleTop
这种模式下,可以解决重复创建栈顶Activity的问题,如果连续创建两个FirstActivity,那么只会产生一个。但是如果中间隔了一个SecondActivity,那么再次启动的FirstActivity就又会是新的,换句话说,这种模式只会保证栈顶Activity的创建不会重复。
3、singleTask
这种模式下,可以保证每种Activity只会创建一次。
4、singleInstance
这种模式下,会使用两个返回栈,假设我们要实现当前app和其他app共享某个Activity,就必须用这种模式,在SecondActivity的注册代码中加上启动模式:
android:launchMode="singleInstance"
这样的话,secondActivity启动之后就会被放在第二个返回栈里面,它的taskId是不同于其他两个的。
六、Activity被回收之后,数据怎么保存( onSaveInstanceState() )
假设现在有一个Activity A,用户在A的基础上启动了Activity B,那么A就进入了停止状态,如果这时系统内存不足,就会将A回收掉,那么用户按下back键返回A,会出现什么情况呢?答案是执行A的onCreate()方法,而不是onRestart()
在这种情况下,就必须利用 onSaveInstanceState()方法 保存好A之前的数据,onSaveInstanceState()方法会携带一个Bundle类型的参数,bundle可以用putString、putInt等方法保存数据。
利用这个方法将数据保存之后,Activity A下次通过onCreate()方法启动的时候,就会从Bundle中取出数据,从而防止数据丢失
七、一些Activity相关技巧
1、启动子Activity的最佳方式
在子Activity中定义一个activityStart()方法,然后在BasicActivity利用类名调用即可启动子Activity。
SubActivity.java
public static void actionStart(Context context , String data , int requestCode){
Intent intent = new Intent(context,SubActivity.class);
intent.putExtra("param1",data);
context.startActivityForResult(intent,requestCode);
}
BasicActivity.java
SubActivity.actionStart(BasicActivity.this,"message",requestCode);
2、自定义Activity管理器来管理Activity
public class ActivityManager{
public static List<Activity> activities = new ArrayList<>();
public static void addActivity(Activity activity){
activities.add(activity);
}
public static void removeActivity(Activity activity){
activities.remove(activity);
}
public static void finishAll(){
for(Activity activity : activities){
if(!activity.isFinishing()){
activity.finish();
}
}
}
}
如果想在某个时刻直接退出app,而不是慢慢的去销毁栈中的所有Activity,就可以直接调用finishAll()方法。