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

Android 彻底弄懂Activity四大启动模式 和taskAffinity属性详解 intentFlag 图文解析

2017-08-01 20:57 465 查看
task是在程序运行时,只针对activity的概念。说白了,task是一组相互关联的activity的集合,它是存在于framework层的一个概念,控制界面的跳转和返回。这个task存在于一个称为back stack的数据结构中,也就是说,framework是以栈的形式管理用户开启的activity。这个栈的基本行为是,当用户在多个activity之间跳转时,执行压栈操作,当用户按返回键时,执行出栈操作。举例来说,如果应用程序中存在A,B,C三个activity,当用户在Launcher或Home Screen点击应用程序图标时,启动主Activity A,接着A开启B,B开启C,这时栈中有三个Activity,并且这三个Activity默认在同一个任务(task)中,当用户按返回时,弹出C,栈中只剩A和B,再按返回键,弹出B,栈中只剩A,再继续按返回键,弹出A,任务被移除。如下图所示:
 task是可以跨应用的,这正是task存在的一个重要原因。有的Activity,虽然不在同一个app中,但为了保持用户操作的连贯性,把他们放在同一个任务中。例如,在我们的应用中的一个Activity A中点击发送邮件,会启动邮件程序的一个Activity B来发送邮件,这两个activity是存在于不同app中的,但是被系统放在一个任务中,这样当发送完邮件后,用户按back键返回,可以返回到原来的Activity A中,这样就确保了用户体验。总的来说:一个task可以再同一个应用里面,还可以是不同的应用是一个task
singlerInstance其效果相当于多个应用共享一个应用,不管谁激活该 Activity 都会进入同一个应用中。
SingleInstance模式启动的Activity在系统中具有全局唯一性。就是单列的效果
1.MediamainActivity 被重新创建了oncreate方法,前面的所有的activity都没有销毁
standard----每次点击图标或home键的时候重新创建MediamainActivity , MediamainActivity 有多个OnCreate方法执行
2.singleTask:
先进入了MediamainActivity ,再进入了Videoplay的话,点击图标
MediamainActivity 在顶,显示顶端的!
singleTask和其他所有的区别在于:Mediamain只有一个,销毁前面的所有的activity
有一个Mediamain只,执行onNewIntent()和singleInstance一样!
就重用该实例(会调用实例的onNewIntent())。重用时,会让该实例回到栈顶,因此在它上面的实例将会被移除栈
其他的videoPlay,audioplay,imagePlay都销毁了
3.先进入了MediamainActivity ,再进入了Videoplay的话,点击图标
MediamainActivity 在顶,显示顶端的!和Stander不一样
singleInstance和其他所有的区别在于:Mediamain只有一个,前面的所有的activity都没有销毁
singleInstance(多个应用程序共享一个应用)===比如说:在语音中调用多媒体程序!!
singleTop  ,这个模式下,如果新的activity已经位于栈顶,那么这个Activity不会被重写创建,同时它的onNewIntent方法会被调用,通过此方法的参数我们可以去除当前请求的信息。
如果栈顶不存在该Activity的实例,则情况与standard模式相同
singleTop模式分3种情况当前栈中已有该Activity的实例并且该实例位于栈顶时,不会新建实例,而是复用栈顶的实例,并且会将Intent对象传入,回调onNewIntent方法当前栈中已有该Activity的实例但是该实例不在栈顶时,其行为和standard启动模式一样,依然会创建一个新的实例当前栈中不存在该Activity的实例时,其行为同standard启动模式
是不是同一个实例:hashcode值
案例分析:
         standard,创建一个新的Activity。        singleTop,栈顶不是该类型的Activity,创建一个新的Activity。否则,onNewIntent。        singleTask,回退栈中没有该类型的Activity,创建Activity,否则,onNewIntent+ClearTop。                注意: 1.设置了"singleTask"启动模式的Activity,它在启动的时候,会先在系统中查找属性值affinity等于它的属性值taskAffinity的Task存在; 如果存在这样的Task,它就会在这个Task中启动,否则就会在新的任务栈中启动。 因此, 如果我们想要设置了"singleTask"启动模式的Activity在新的任务中启动,就要为它设置一个独立的taskAffinity属性值。 2.如果设置了"singleTask"启动模式的Activity不是在新的任务中启动时,它会在已有的任务中查看是否已经存在相应的Activity实例, 如果存在,就会把位于这个Activity实例上面的Activity全部结束掉,即最终这个Activity 实例会位于任务的Stack顶端中。 3.在一个任务栈中只有一个”singleTask”启动模式的Activity存在。他的上面可以有其他的Activity。这点与singleInstance是有区别的。                singleInstance,回退栈中,只有这一个Activity,没有其他Activity。                singleTop适合接收通知启动的内容显示页面。 例如,某个新闻客户端的新闻内容页面,如果收到10个新闻推送,每次都打开一个新闻内容页面是很烦人的。 singleTask适合作为程序入口点。 例如浏览器的主界面。不管从多少个应用启动浏览器,只会启动主界面一次,其余情况都会走onNewIntent,并且会清空主界面上面的其他页面。 singleInstance应用场景:闹铃的响铃界面。 你以前设置了一个闹铃:上午6点。在上午5点58分,你启动了闹铃设置界面,并按 Home 键回桌面;在上午5点59分时,你在微信和朋友聊天; 在6点时,闹铃响了,并且弹出了一个对话框形式的 Activity(名为 AlarmAlertActivity) 提示你到6点了(这个 Activity 就是以 SingleInstance 加载模式打开的),你按返回键,回到的是微信的聊天界面,这是因为 AlarmAlertActivity 所在的 Task 的栈只有他一个元素, 因此退出之后这个 Task 的栈空了。如果是以 SingleTask 打开 AlarmAlertActivity,那么当闹铃响了的时候,按返回键应该进入闹铃设置界面。
实例:
activityAserviceActivityB回答:现在activityB,点击返回退到哪呢A,跟Service没有半点关系的activity有启动模式,service有启动模式吗没有的
Intent flag的重要标志之一:      FLAG_ACTIVITY_NEW_TASK
    在Activity上下文之外启动Activity需要给Intent设置FLAG_ACTIVITY_NEW_TASK标志,不然会报异常。
在安装应该的时候,不需要这个标准也可以,奇怪
 private void NotifBar(File myTempFile) {if (notifiManager == null) {notifiManager = (NotificationManager) this.getSystemService(NOTIFICATION_SERVICE);}notifiManager.cancel(UpdateNotifId);if (notif != null) {notif = null;}NotificationCompat.Builder builder = new NotificationCompat.Builder(mContext);RemoteViews contentView = new RemoteViews(this.getPackageName(), R.layout.base_download_act);contentView.setTextViewText(R.id.down_tx, this.getString(R.string.downloadDone));builder.setContentTitle(this.getString(R.string.downloadDone));builder.setContentText(this.getString(R.string.setUp));builder.setSmallIcon(R.drawable.ic_launcher);builder.setOnlyAlertOnce(true);builder.setAutoCancel(true);//notif = new Notification(R.drawable.ic_launcher, this.getString(R.string.downloadDone), System.currentTimeMillis());//notif.flags = Notification.FLAG_ONLY_ALERT_ONCE | Notification.FLAG_AUTO_CANCEL;try {Intent intent = new Intent();//        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);intent.setAction(Intent.ACTION_VIEW);Uri url;if (Build.VERSION.SDK_INT >= 24){CXLog.e(TAG,"getPackageName()=="+mContext.getApplicationContext().getPackageName()+"//path=="+myTempFile.getAbsolutePath().toString());url = FileProvider.getUriForFile(mContext, mContext.getApplicationContext().getPackageName() + ".provider", myTempFile);intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);//对目标应用临时授权该Uri所代表的文件}else{url =Uri.fromFile(myTempFile);}intent.setDataAndType(url, "application/vnd.android.package-archive");PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);builder.setContentIntent(pendingIntent);notif = builder.build();} catch (Exception e) {e.printStackTrace();}//notif.setLatestEventInfo(this, this.getString(R.string.downloadDone), this.getString(R.string.setUp), pendingIntent);notifiManager.notify(UpdateNotifId, notif);
taskAffinity
taskAffinity表示当前activity具有亲和力的一个任务(翻译不是很准确,原句为The task that the activity has an affinity for.), 大致可以这样理解,这个 taskAffinity表示一个任务,这个任务就是当前activity所在的任务。<activity android:name="com.jg.zhang.androidtasktest.SecondActivity"      android:launchMode="singleTask"      android:taskAffinity="com.jg.zhang.androidtasktest.second">     <intent-filter >         <action android:name="com.jg.zhang.androidtasktest.SecondActivity"/>         <category android:name="android.intent.category.DEFAULT"/>     </intent-filter>  lt;/activity>  task是一个具有栈结构的容器,基本是task和栈是同一个概念
taskAffinity总结:是否是同一个任务,如果想在不同任务,可以用这个。
其实framework中对任务和activity‘的调度是很复杂的,尤其是把启动模式设为singleTask或者以FLAG_ACTIVITY_NEW_TASK标志启动时。所以,在使用singleTask和FLAG_ACTIVITY_NEW_TASK时,要仔细测试应用程序。这也是官方文档上的建议。参考:我的书籍参考博客:http://blog.csdn.net/zhangjg_blog/article/details/10923643
task是在程序运行时,只针对activity的概念。说白了,task是一组相互关联的activity的集合,它是存在于framework层的一个概念,控制界面的跳转和返回。这个task存在于一个称为back stack的数据结构中,也就是说,framework是以栈的形式管理用户开启的activity。这个栈的基本行为是,当用户在多个activity之间跳转时,执行压栈操作,当用户按返回键时,执行出栈操作。举例来说,如果应用程序中存在A,B,C三个activity,当用户在Launcher或Home Screen点击应用程序图标时,启动主Activity A,接着A开启B,B开启C,这时栈中有三个Activity,并且这三个Activity默认在同一个任务(task)中,当用户按返回时,弹出C,栈中只剩A和B,再按返回键,弹出B,栈中只剩A,再继续按返回键,弹出A,任务被移除。如下图所示:
 task是可以跨应用的,这正是task存在的一个重要原因。有的Activity,虽然不在同一个app中,但为了保持用户操作的连贯性,把他们放在同一个任务中。例如,在我们的应用中的一个Activity A中点击发送邮件,会启动邮件程序的一个Activity B来发送邮件,这两个activity是存在于不同app中的,但是被系统放在一个任务中,这样当发送完邮件后,用户按back键返回,可以返回到原来的Activity A中,这样就确保了用户体验。总的来说:一个task可以再同一个应用里面,还可以是不同的应用是一个task
singlerInstance其效果相当于多个应用共享一个应用,不管谁激活该 Activity 都会进入同一个应用中。
SingleInstance模式启动的Activity在系统中具有全局唯一性。就是单列的效果
1.MediamainActivity 被重新创建了oncreate方法,前面的所有的activity都没有销毁
standard----每次点击图标或home键的时候重新创建MediamainActivity , MediamainActivity 有多个OnCreate方法执行
2.singleTask:
先进入了MediamainActivity ,再进入了Videoplay的话,点击图标
MediamainActivity 在顶,显示顶端的!
singleTask和其他所有的区别在于:Mediamain只有一个,销毁前面的所有的activity
有一个Mediamain只,执行onNewIntent()和singleInstance一样!
就重用该实例(会调用实例的onNewIntent())。重用时,会让该实例回到栈顶,因此在它上面的实例将会被移除栈
其他的videoPlay,audioplay,imagePlay都销毁了
3.先进入了MediamainActivity ,再进入了Videoplay的话,点击图标
MediamainActivity 在顶,显示顶端的!和Stander不一样
singleInstance和其他所有的区别在于:Mediamain只有一个,前面的所有的activity都没有销毁
singleInstance(多个应用程序共享一个应用)===比如说:在语音中调用多媒体程序!!
singleTop  ,这个模式下,如果新的activity已经位于栈顶,那么这个Activity不会被重写创建,同时它的onNewIntent方法会被调用,通过此方法的参数我们可以去除当前请求的信息。
如果栈顶不存在该Activity的实例,则情况与standard模式相同
singleTop模式分3种情况当前栈中已有该Activity的实例并且该实例位于栈顶时,不会新建实例,而是复用栈顶的实例,并且会将Intent对象传入,回调onNewIntent方法当前栈中已有该Activity的实例但是该实例不在栈顶时,其行为和standard启动模式一样,依然会创建一个新的实例当前栈中不存在该Activity的实例时,其行为同standard启动模式
是不是同一个实例:hashcode值
案例分析:
         standard,创建一个新的Activity。        singleTop,栈顶不是该类型的Activity,创建一个新的Activity。否则,onNewIntent。        singleTask,回退栈中没有该类型的Activity,创建Activity,否则,onNewIntent+ClearTop。                注意: 1.设置了"singleTask"启动模式的Activity,它在启动的时候,会先在系统中查找属性值affinity等于它的属性值taskAffinity的Task存在; 如果存在这样的Task,它就会在这个Task中启动,否则就会在新的任务栈中启动。 因此, 如果我们想要设置了"singleTask"启动模式的Activity在新的任务中启动,就要为它设置一个独立的taskAffinity属性值。 2.如果设置了"singleTask"启动模式的Activity不是在新的任务中启动时,它会在已有的任务中查看是否已经存在相应的Activity实例, 如果存在,就会把位于这个Activity实例上面的Activity全部结束掉,即最终这个Activity 实例会位于任务的Stack顶端中。 3.在一个任务栈中只有一个”singleTask”启动模式的Activity存在。他的上面可以有其他的Activity。这点与singleInstance是有区别的。                singleInstance,回退栈中,只有这一个Activity,没有其他Activity。                singleTop适合接收通知启动的内容显示页面。 例如,某个新闻客户端的新闻内容页面,如果收到10个新闻推送,每次都打开一个新闻内容页面是很烦人的。 singleTask适合作为程序入口点。 例如浏览器的主界面。不管从多少个应用启动浏览器,只会启动主界面一次,其余情况都会走onNewIntent,并且会清空主界面上面的其他页面。 singleInstance应用场景:闹铃的响铃界面。 你以前设置了一个闹铃:上午6点。在上午5点58分,你启动了闹铃设置界面,并按 Home 键回桌面;在上午5点59分时,你在微信和朋友聊天; 在6点时,闹铃响了,并且弹出了一个对话框形式的 Activity(名为 AlarmAlertActivity) 提示你到6点了(这个 Activity 就是以 SingleInstance 加载模式打开的),你按返回键,回到的是微信的聊天界面,这是因为 AlarmAlertActivity 所在的 Task 的栈只有他一个元素, 因此退出之后这个 Task 的栈空了。如果是以 SingleTask 打开 AlarmAlertActivity,那么当闹铃响了的时候,按返回键应该进入闹铃设置界面。
实例:
activityAserviceActivityB回答:现在activityB,点击返回退到哪呢A,跟Service没有半点关系的activity有启动模式,service有启动模式吗没有的
Intent flag的重要标志之一:      FLAG_ACTIVITY_NEW_TASK
    在Activity上下文之外启动Activity需要给Intent设置FLAG_ACTIVITY_NEW_TASK标志,不然会报异常。
在安装应该的时候,不需要这个标准也可以,奇怪
 private void NotifBar(File myTempFile) {if (notifiManager == null) {notifiManager = (NotificationManager) this.getSystemService(NOTIFICATION_SERVICE);}notifiManager.cancel(UpdateNotifId);if (notif != null) {notif = null;}NotificationCompat.Builder builder = new NotificationCompat.Builder(mContext);RemoteViews contentView = new RemoteViews(this.getPackageName(), R.layout.base_download_act);contentView.setTextViewText(R.id.down_tx, this.getString(R.string.downloadDone));builder.setContentTitle(this.getString(R.string.downloadDone));builder.setContentText(this.getString(R.string.setUp));builder.setSmallIcon(R.drawable.ic_launcher);builder.setOnlyAlertOnce(true);builder.setAutoCancel(true);//notif = new Notification(R.drawable.ic_launcher, this.getString(R.string.downloadDone), System.currentTimeMillis());//notif.flags = Notification.FLAG_ONLY_ALERT_ONCE | Notification.FLAG_AUTO_CANCEL;try {Intent intent = new Intent();//        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);intent.setAction(Intent.ACTION_VIEW);Uri url;if (Build.VERSION.SDK_INT >= 24){CXLog.e(TAG,"getPackageName()=="+mContext.getApplicationContext().getPackageName()+"//path=="+myTempFile.getAbsolutePath().toString());url = FileProvider.getUriForFile(mContext, mContext.getApplicationContext().getPackageName() + ".provider", myTempFile);intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);//对目标应用临时授权该Uri所代表的文件}else{url =Uri.fromFile(myTempFile);}intent.setDataAndType(url, "application/vnd.android.package-archive");PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);builder.setContentIntent(pendingIntent);notif = builder.build();} catch (Exception e) {e.printStackTrace();}//notif.setLatestEventInfo(this, this.getString(R.string.downloadDone), this.getString(R.string.setUp), pendingIntent);notifiManager.notify(UpdateNotifId, notif);
taskAffinity
taskAffinity表示当前activity具有亲和力的一个任务(翻译不是很准确,原句为The task that the activity has an affinity for.), 大致可以这样理解,这个 taskAffinity表示一个任务,这个任务就是当前activity所在的任务。<activity android:name="com.jg.zhang.androidtasktest.SecondActivity"      android:launchMode="singleTask"      android:taskAffinity="com.jg.zhang.androidtasktest.second">     <intent-filter >         <action android:name="com.jg.zhang.androidtasktest.SecondActivity"/>         <category android:name="android.intent.category.DEFAULT"/>     </intent-filter>  lt;/activity>  task是一个具有栈结构的容器,基本是task和栈是同一个概念
taskAffinity总结:是否是同一个任务,如果想在不同任务,可以用这个。
其实framework中对任务和activity‘的调度是很复杂的,尤其是把启动模式设为singleTask或者以FLAG_ACTIVITY_NEW_TASK标志启动时。所以,在使用singleTask和FLAG_ACTIVITY_NEW_TASK时,要仔细测试应用程序。这也是官方文档上的建议。参考:我的书籍参考博客:http://blog.csdn.net/zhangjg_blog/article/details/10923643

                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: