赞
踩
有这样的场景:
- //重写返回按键事件
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) {
- // 这里重写返回键
- return true;
- }
- return false;
- }
- //调用相机
- private void openCamera() {
- Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
- uri = PhotoUtil.createImageFile();
- if (takePictureIntent.resolveActivity(mContext.getPackageManager()) != null) {// 相机被卸载时不会崩溃
- takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
- startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAMERA);
- }
- }
任务栈Task,是一种用来放置Activity实例的容器,他是以栈的形式进行盛放,也就是所谓的先进后出,主要有2个基本操作:压栈和出栈,其所存放的Activity是不支持重新排序的,只能根据压栈和出栈操作更改Activity的顺序。
启动一个Application的时候,系统会为它默认创建一个对应的Task,用来放置根Activity。默认启动Activity会放在同一个Task中,新启动的Activity会被压入启动它的那个Activity的栈中,并且显示它。当用户按下回退键时,这个Activity就会被弹出栈,按下Home键回到桌面,再启动另一个应用,这时候之前那个Task就被移到后台,成为后台任务栈,而刚启动的那个Task就被调到前台,成为前台任务栈,手机页面显示的就是前台任务栈中的栈顶元素。
Activity默认模式,所有的Activity遵循元素进栈出栈的特性,例如进栈序列为A->B->C->D,D呈现在页面上,按返回键出栈顺序久违D->C->B->A.
在
栈顶复用模式,如果要开启的activity在任务栈的顶部已经存在,就不会创建新的实例,而是调用 onNewIntent() 方法。避免栈顶的activity被重复的创建。
在开始处,我们提到的2个Bug,可以用这种模式解决
通知栏弹出Notification,点击Notification跳转到指定Activity,但是如果我现在页面就停留在那个指定的Activity,会再次打开我当前的Activity,这样返回的时候回退的页面和当前页面一样,感官上就会很奇怪。
- btnNotification.setOnClickListener(new OnClickListener() {
-
- @Override
- public void onClick(View v) {
- NoticationUtil.sendNotication(mContext);
- }
- });
- public class NoticationUtil {
-
- @SuppressLint("NewApi")
- public static void sendNotication(Context context) {
- // 在Android进行通知处理,首先需要重系统哪里获得通知管理器NotificationManager,它是一个系统Service。
- NotificationManager manager = (NotificationManager) context
- .getSystemService(Context.NOTIFICATION_SERVICE);
- PendingIntent pendingIntent = PendingIntent.getActivity(context, 0,
- new Intent(context, MainActivity.class), 0);
- // 通过Notification.Builder来创建通知,注意API Level
- // API16之后才支持
- Notification notify = new Notification.Builder(context)
- .setSmallIcon(R.drawable.ic_launcher)
- .setTicker("您有新短消息,请注意查收!").setContentTitle("我是标题")
- .setContentText("点我打开主页").setContentIntent(pendingIntent)
- .setNumber(1).build();
-
- notify.flags |= Notification.FLAG_AUTO_CANCEL; // FLAG_AUTO_CANCEL表明当通知被用户点击时,通知将被清除。
- manager.notify(1, notify);
- }
- }
- <activity
- android:name=".aty.MainActivity"
- android:launchMode="standard" >
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
修改为:
- <activity
- android:name=".aty.MainActivity"
- android:launchMode="singleTop" >
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
登录成功跳转到主页,按下两次登录按钮,生成了两个主页。一些有启动延迟的页面(往往是动画,网络造成)也会有这样的情况。
- btnLogin.setOnClickListener(new OnClickListener() {
-
- @Override
- public void onClick(View v) {
- // 延迟1000秒,模拟网络超时
- v.getHandler().postDelayed(new Runnable() {
-
- @Override
- public void run() {
- // 登录成功,跳转到主页
- LoginSuccessActivity.actionStart(mContext);
- }
- }, 3000);
-
- }
- });
XML清单配置
<activity android:name=".aty.LoginSuccessActivity" />
把他修改为singleTop
- <activity
- android:name=".aty.LoginSuccessActivity"
- android:launchMode="singleTop" />
还有一种场景 从activity A启动了个service进行耗时操作,或者某种监听,这个时候你home键了,service收集到信息,要返回activityA了,就用singleTop启动,实际不会创建新的activityA,只是resume了。不过使用standard又会创造2个A的实例。
- <activity android:name=".aty.MainActivity" >
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- <activity
- android:name=".aty.Test1Activity"
- android:launchMode="singleTask" />
- <activity android:name=".aty.Test2Activity" />
android:taskAffinity="新的包名"
,因为android:taskAffinity
这个字段默认指定的包名为本应用的包名,表示在本应用包名的任务栈内创建应用。如果设置了这个字段,而且还和本应用包名不同,就会在新的任务栈创建任务。例如,修改刚才的代码Test1Activity的配置清单:- <activity
- android:name=".aty.Test1Activity"
- android:launchMode="singleTask"
- android:taskAffinity="com.test.newlaunch" />
指定android:taskAffinity
包名为com.test.newlaunch
- 06-03 14:47:46.556: D/displayTask(22127): id:--69
- 06-03 14:47:46.556: D/displayTask(22127): numActivities:--1
- 06-03 14:47:46.556: D/displayTask(22127): topActivity:--com.example.testlaunch.aty.MainActivity
- 06-03 14:47:46.556: D/displayTask(22127): baseActivity:--com.example.testlaunch.aty.MainActivity
- 06-03 14:47:48.428: D/displayTask(22127): id:--69
- 06-03 14:47:48.428: D/displayTask(22127): numActivities:--2
- 06-03 14:47:48.428: D/displayTask(22127): topActivity:--com.example.testlaunch.aty.Test2Activity
- 06-03 14:47:48.428: D/displayTask(22127): baseActivity:--com.example.testlaunch.aty.MainActivity
- 06-03 14:47:50.080: D/displayTask(22127): id:--69
- 06-03 14:47:50.080: D/displayTask(22127): numActivities:--3
- 06-03 14:47:50.080: D/displayTask(22127): topActivity:--com.example.testlaunch.aty.MainActivity
- 06-03 14:47:50.080: D/displayTask(22127): baseActivity:--com.example.testlaunch.aty.MainActivity
- 06-03 14:47:55.164: D/displayTask(22127): id:--71
- 06-03 14:47:55.164: D/displayTask(22127): numActivities:--1
- 06-03 14:47:55.164: D/displayTask(22127): topActivity:--com.example.testlaunch.aty.Test1Activity
- 06-03 14:47:55.164: D/displayTask(22127): baseActivity:--com.example.testlaunch.aty.Test1Activity
- 06-03 14:47:56.688: D/displayTask(22127): id:--71
- 06-03 14:47:56.688: D/displayTask(22127): numActivities:--2
- 06-03 14:47:56.688: D/displayTask(22127): topActivity:--com.example.testlaunch.aty.Test2Activity
- 06-03 14:47:56.688: D/displayTask(22127): baseActivity:--com.example.testlaunch.aty.Test1Activity
- 06-03 14:47:58.140: D/displayTask(22127): id:--71
- 06-03 14:47:58.140: D/displayTask(22127): numActivities:--3
- 06-03 14:47:58.140: D/displayTask(22127): topActivity:--com.example.testlaunch.aty.MainActivity
- 06-03 14:47:58.140: D/displayTask(22127): baseActivity:--com.example.testlaunch.aty.Test1Activity
最开始的栈id为69,然后在06-03 14:47:55.164: D/displayTask(22127): topActivity:--com.example.testlaunch.aty.Test1Activity
Test1Activity启动的时候又新建了一个栈id为71.同时在查看后台程序,看到出现了2个后台任务都是我们的应用—TestLanuch。
singleTask
模式,保证他只有一个唯一实例,节约内存同时按下返回键后的感官也更顺畅。但是需要注意,提供给人调用的页面最好是栈底元素。因为,如果自己的客户端处于运行状态,按下Home键后台挂起。此时如果使用如果其他应用(比如说QQ)调起自己的客户端某个页面,不做任何处理的情况下,按下回退或者当前 Activity.finish(),页面都会停留在自己的客户端(因为自己的Application回 退栈不为空),这明显不符合逻辑的。 - <activity android:name=".aty.MainActivity" >
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
-
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- <activity
- android:name=".aty.Test1Activity"
- android:launchMode="singleTask" >
- <intent-filter>
- <action android:name=".aty.Test1Activity" />
-
- <category android:name="android.intent.category.DEFAULT" />
- </intent-filter>
- </activity>
- <activity android:name=".aty.Test2Activity" />
在其他应用 “我是QQ”中打开指定页面Test1Activity
- btnSkip.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- Intent intent = new Intent();
- intent.setAction(".aty.Test1Activity");
- try {
- startActivity(intent);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- });
a. 模拟操作TestLanuch
b. 使用我是QQ打开TestLanuch的Test1Activity,然后按返回键退栈
要解决这个问题有两种方式:
singleTask
清除这个activity任务栈上面所有的activity特性我们提供的分享页面始终是我们栈底的元素,只要他一启动就会清空任务栈内其他Activity,保证只有他一个实例。
例如在本应用真就设置:
- <activity
- android:name=".MainActivity"
- android:label="@string/app_name"
- android:taskAffinity="com.test.newlaunch" >
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
这样在Test1Activity启动的时候,如果com.test.newlaunch
没启动就新建一个任务栈,如果com.test.newlaunch
启动了就直接加入它的任务栈。
单一实例模式,整个手机操作系统里面只有一个实例存在。不同的应用去打开这个activity 共享公用的同一个activity。他会运行在自己单独,独立的任务栈里面,并且任务栈里面只有他一个实例存在。应用场景:呼叫来电界面。这种模式的使用情况比较罕见,在Launcher中可能使用。或者你确定你需要使Activity只有一个实例。
可以得出以下结论:
1. 以singleInstance模式启动的Activity具有全局唯一性,即整个系统中只会存在一个这样的实例。
2. 以singleInstance模式启动的Activity在整个系统中是单例的,如果在启动这样的Activiyt时,已经存在了一个实例,那么会把它所在的任务调度到前台,重用这个实例。
3. 以singleInstance模式启动的Activity具有独占性,即它会独自占用一个任务,被他开启的任何activity都会运行在其他任务中。
4. 被singleInstance模式的Activity开启的其他activity,能够在新的任务中启动,但不一定开启新的任务,也可能在已有的一个任务中开启。
换句话说,其实SingleInstance就是我们刚才分析的SingleTask中,分享Activity为栈底元素的情况。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。