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



 
  
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,任务被移除。如下图所示:
Android 彻底弄懂Activity四大启动模式 和taskAffinity属性详解 intentFlag 图文解析_第1张图片



 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种情况

  1. 当前栈中已有该Activity的实例并且该实例位于栈顶时,不会新建实例,而是复用栈顶的实例,并且会将Intent对象传入,回调onNewIntent方法
  2. 当前栈中已有该Activity的实例但是该实例不在栈顶时,其行为和standard启动模式一样,依然会创建一个新的实例
  3. 当前栈中不存在该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,那么当闹铃响了的时候,按返回键应该进入闹铃设置界面。

实例:
 
   
activityA
service
ActivityB
回答:
现在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
 
   
  1. taskAffinity表示当前activity具有亲和力的一个任务(翻译不是很准确,原句为The task that the activity has an affinity for.), 大致可以这样理解,这个 taskAffinity表示一个任务,这个任务就是当前activity所在的任务。
  1. <activity android:name="com.jg.zhang.androidtasktest.SecondActivity"  
  2.     android:launchMode="singleTask"  
  3.     android:taskAffinity="com.jg.zhang.androidtasktest.second">  
  4.    <intent-filter >  
  5.        <action android:name="com.jg.zhang.androidtasktest.SecondActivity"/>  
  6.        <category android:name="android.intent.category.DEFAULT"/>  
  7.    intent-filter>  
  8. 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种情况

  1. 当前栈中已有该Activity的实例并且该实例位于栈顶时,不会新建实例,而是复用栈顶的实例,并且会将Intent对象传入,回调onNewIntent方法
  2. 当前栈中已有该Activity的实例但是该实例不在栈顶时,其行为和standard启动模式一样,依然会创建一个新的实例
  3. 当前栈中不存在该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,那么当闹铃响了的时候,按返回键应该进入闹铃设置界面。

实例:
 
    
activityA
service
ActivityB
回答:
现在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
 
    
  1. taskAffinity表示当前activity具有亲和力的一个任务(翻译不是很准确,原句为The task that the activity has an affinity for.), 大致可以这样理解,这个 taskAffinity表示一个任务,这个任务就是当前activity所在的任务。
  1. <activity android:name="com.jg.zhang.androidtasktest.SecondActivity"  
  2.     android:launchMode="singleTask"  
  3.     android:taskAffinity="com.jg.zhang.androidtasktest.second">  
  4.    <intent-filter >  
  5.        <action android:name="com.jg.zhang.androidtasktest.SecondActivity"/>  
  6.        <category android:name="android.intent.category.DEFAULT"/>  
  7.    intent-filter>  
  8. 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

你可能感兴趣的:(android)