您的位置:首页 > 移动开发 > Android开发

Activity的启动与任务栈学习笔记

2017-03-23 16:38 246 查看
看《Android第一行代码》第二版的读书笔记系列

上一篇记录了 activity 生命周期的那点事,这一篇小结一下 activity 的四种不同模式的任务栈,以及启动 activity 的一些技巧。

返回栈(Back Stack)

返回栈,或者叫任务栈(Task Stack),是一种后进先出的数据结构,在 android 中被用来保存 activity 的引用,我们可以通过按下返回键或者调用 finish 方法,来把栈顶的 activity 移除出任务栈,注意在移出任务栈时,都会调用 onDestroy() 方法。任务栈,有四种模式,分别是 standar 、singleTop、singleTask、singleInstance 。

standar 是默认的启动模式,每启动一个 activity 就会创建 activity 对象并把它压入任务栈,当销毁一个 activity 就会弹出任务栈,不管任务栈有没有已经存在这个 activity。

singleTop ,在启动一个 activity 时,先会检查一下栈顶元素,发现已经存在这个 activity,则不会再创建 activity 对象,如果栈顶元素不是要启动的 activity ,就会创建 activity 对象并入栈,这就防止了不断连续重复创建 相同的 activity 对象,注意这只是检查栈顶的元素,保证不与栈顶的 activity重复。

singleTask,在启动一个 activity 时,会检查栈内所有元素,如果发现已经存在有相应的 activity,就会把栈里 activity 以上的元素全都出栈,把这个相应的 activity 提升到栈顶,也就是说,在栈里的 activity 都是不同的 activity。

singleInstance,一个任务栈只保存一个 activity ,每启动一个 activity 都会启动一个新的任务栈管理这个 activity。

那么我们如何来给 activity 指定启动模式呢,可以在 AndroidManifest 文件中的 activity 标签中指定 android:launchMode 属性,如 android:launchMode = “singleTop”。

注意:在一个 app 会有多个 activity , 而 acticity 可以设为不同的启动模式,也就是说在程序中会同时存在不同的任务栈,以上的四种启动模式,检查栈元素,都只是检查对应的栈的栈元素,我们可以创建几个 activity ,在跳转的时候分别打印输出一下当前 activity 的信息(this.toString())和 当前 activity 的任务栈 id(this.getTaskId()) ,即可发现不同的启动模式的区别了。

Intent

intent 是意图的意思,可以用来传递数据,启动活动,启动服务,发送广播,用来启动 activity,有两种方式,显式Intent和隐式Intent启动 activity。

显式Intent启动 activity

Intent intent = new Intent(FirstActivity.this,SecondActivity.class);
//  一般启动方式
startActivity(intent);

//  当需要从 SecondActivity 返回 FirstActivity 回传一些数据时使用,
//  requestCode 就是请求码,用来确定数据来源
startActivityForResult(intent,requestCode);


当你使用 startActivityForResult 启动活动,当返回上一个活动时,会自动回掉上一个活动的 onActivityResult 方法,在这处理活动回传的数据。

//  requestCode 是你启动 SecondActivity 时传过去的请求码,resultCode
//  是响应结果码,data 就是回传的数据,通过调用intent的方法获取出数据
onActivityResult(int requestCode, int resultCode, Intent data)


注意:当你从 SecondActivity 返回 FirstActivity,在返回前必须调用 setResult 方法来设置回传数据,否则 data 为 null 。

backBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//  这里的 intent 仅仅用来传递数据
Intent intent = new Intent();
intent.putExtra("data","hello,i am SecondActivity");
setResult(RESULT_OK,intent);
finish();
}
});


可能有些活动是通过按返回键来返回上一个活动的,此时你可以重写 activity 中的 onBackPress 方法

@Override
public void onBackPressed() {
//  请注释掉 super.onBackPressed 或者放到方法尾部,因为这方法                          最终会调用 finish 方法,而 setResult 必须放在 finish 方法前调用
// super.onBackPressed();
Intent intent = new Intent();
intent.putExtra("data","hello,i am SecondActivity");
setResult(RESULT_OK,intent);
finish();
}

// super.onBackPressed 方法源码
public void onBackPressed() {
if (mActionBar != null && mActionBar.collapseActionView()) {
return;
}
if (!mFragments.getFragmentManager().popBackStackImmediate()) {
finishAfterTransition();
}
}

public void finishAfterTransition() {
if (!mActivityTransitionState.startExitBackTransition(this)) {
finish();
}
}


上面主要小结了利用显式 Intent 启动,所谓显式就是在创建 intent 对象时,直接传入当前 activity 对象,可要启动的 activity 的 class 对象,其中 intent 对象是可以带有数据的,通过 intent.PutExtra() 重载方法,可以传递 String、int 、float 、甚至 object 等数据,传递 object 需要进行 Serializable 或者 Parcelable。

隐式 Intent 启动 activity

使用隐式 intent 启动 activity,通常用于启动一些其他应用程序,例如启动系统浏览器,启动摄像头,相册,拨打电话等。

// 通过在 as 中敲入 Intent. 可以看到有很多系统 activity 可以启动
// 因为启动一些系统的 activity ,需要传入一些数据,已达到一些目的,例如
// 调用相机拍照,可以指定保存到那个地方
Intent intent = new Intent(Intent.ACTION_VIEW);
// 传入访问的页面uri
intent.setData(Uri.parse("http://blog.csdn.net/qq_34228690"));
startActivity(intent);


效果



所谓隐式 intent 启动一个 activity,就是在创建 intent 时仅仅指定 action,然后再添加 category(可多个),这样启动 activity 时就会匹配同时满足 action 和 category 的 activity,如果满足条件的 activity 有两个,会让你选择的。在上面的代码中并没向 Intent 加入 category ,那是因为会默认帮你加入默认的 category,一般其他被允许调用的 activity 配置都是默认 category。

如:自己创建一个 ThirdActivity,并做如下配置



就可以这样启动了

Intent intent = new Intent("android.intent.action.MyAction");                  intent.addCategory("android.intent.category.DEFAULT");
startActivity(intent);


注意: 在配置 activity 的 intent-filter 标签时,还可已加入其他属性,如 data 标签,用来约定传入的数据类型,满足类型才响应。

技巧

在要启动的 activity 写一个静态方法

public static void actionStart(Context context,Stringdata1,String data2){
Intent intent = new Intent(context,TargetActivity.class);
intent.putExtra("data1",data1);
intent.putExtra("data2",data2);
context.startActivity(intent);
}


只要调用 TargetActivity.sctionStart() 方法即可启动 activity,这样做的好处是,当 TargetActivity 不是你自己写的,你要启动的话,如果要传入一些数据,你不用看 TargetActivity 的具体代码,直接看 sctionStart 的参数即可

利用自定义BaseActivity

如果你要维护一个项目,里面有很多 activity,如何才能在运行时知道现在在跑哪一个 activity 呢,这是你可以让所有 activity 继承自 BaseActivity ,而我们自定义的 BaseActivity 继承自 AppCompatActivity ,则不会影响运行了。

因此我们可以:

@Override
protected void onCreate(Bundle savedInstanceState) {
//打印当前 activity 的类名
Log.i("BaseActivity",getClass().getSimpleName());
}


当我们需要一步退出程序,不要一个 activity 返回,最后退出,我们可以自定义一个 ActivityCollector 类:

public class ActivityCollector {
private static List<Activity> activityList = new ArrayList<>();
public static void addActivity(Activity activity){
if(activity != null) {
activityList.add(activity);
}
}
public static void removeActivity(Activity activity){
activityList.remove(activity);
}
public static void finishAll(){
for(Activity activity :activityList){
if(!activity.isFinishing()){
activity.finish();
}
activityList.remove(activity);
}
}
}


然后再 BaseActivity 中的 onCreate 、onDestroy 方法中分别把 activity 加入和移除 activityList,这样 activityList 就持有所有 activity 的引用了,你需要 finishAll 即可直接退出程序了。

注意:如果你要真正彻底退出程序,还要调用 android.os.Process.killProcess(android.os.Process.myPid());
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android 读书笔记