关于Android TaskAffinity的那些事儿

正常状况下,若是应用已经启动,并将应用切到后台,在通知栏中调起页面时,该应用的Task首先会被调起,而后会将咱们的Activity显示在这个Task的顶端。手机百度的通知栏里面有一个快速搜索栏,不管什么状况下,点击以后都会直接弹出搜索页面,透明背景后显示的是桌面。怎么来实现这个功能呢?这就要提到咱们的主角TaskAffinity了。android

什么是affinity?

  affinity是指Activity的归属,Activity与Task的吸附关系,也就是该Activity属于哪一个Task。通常状况下在同一个应用中,启动的Activity都在同一个Task中,它们在该Task中度过本身的生命。每一个Activity都有taskAffinity属性,这个属性指出了它但愿进入的Task。若是一个Activity没有显式的指明taskAffinity,那么它的这个属性就等于Application指明的taskAffinity,若是Application也没有指明,那么该taskAffinity的值就等于应用的包名。咱们能够经过在元素中增长taskAffinity属性来为某一个Activity指定单独的affinity。这个属性的值是一个字符串,能够指定为任意字符串,可是必须至少包含一个”.”,不然会报错。app

affinity在什么场合应用呢?

1.根据affinity从新为Activity选择宿主task(与allowTaskReparenting属性配合使用)

  allowTaskReparenting用来标记Activity可否从启动的Task移动到taskAffinity指定的Task,当把Activity的allowTaskReparenting属性设置成true时,Activity就拥有了一个转移所在Task的能力。具体点来讲,就是一个Activity如今是处于某个Task当中的,可是它与另一个Task具备相同的affinity值,那么当另外这个任务切换到前台的时候,该Activity就能够转移到如今的这个任务当中。allowTaskReparenting默认是继承至application中的allowTaskReparenting=false,若是为true,则表示能够更换;false表示不能够。
  举一个形象点的例子,好比有一个天气预报程序,它有一个用于显示天气信息的Activity,allowTaskReparenting属性设置成true,这个Activity和天气预报程序的全部其它Activity具体相同的affinity值。这个时候,你本身的应用程序经过Intent去启动了这个用于显示天气信息的Activity,那么此时这个Activity应该是和你的应用程序是在同一个任务当中的。可是当把天气预报程序切换到前台的时候,这个Activity会被转移到天气预报程序的任务当中,并显示出来。若是将你本身的应用切换到前台,发现你本身应用Task里的那个Activity消失了。.net

2.启动一个Activity过程当中Intent使用了FLAG_ACTIVITY_NEW_TASK标记,根据affinity查找或建立一个新的具备对应affinity的task。

  当调用startActivity()方法来启动一个Activity时,默认是将它放入到当前的任务当中。可是,若是在Intent中加入了FLAG_ACTIVITY_NEW_TASK flag的话,状况就会变的复杂起来。首先,系统会去检查这个Activity的affinity是否与当前Task的affinity相同。若是相同的话就会把它放入到当前Task当中,若是不一样则会先去检查是否已经有一个名字与该Activity的affinity相同的Task,若是有,这个Task将被调到前台,同时这个Activity将显示在这个Task的顶端;若是没有的话,系统将会尝试为这个Activity建立一个新的Task。须要注意的是,若是一个Activity在manifest文件中声明的启动模式是”singleTask”,那么他被启动的时候,行为模式会和前面提到的指定FLAG_ACTIVITY_NEW_TASK同样。
  那么,有了上面的知识,咱们应该能够实现开头提到的功能了。code

功能的实现

  首先,在mainifest中配置咱们的Activity,继承

<activity
        android:name="com.test.TestActivity"
        android:configChanges="orientation|keyboard|keyboardHidden"
        android:exported="true"
        android:taskAffinity="com.test.TestActivity"
        android:screenOrientation="portrait"/>

  而后增长通知栏的逻辑字符串

NotificationManager mNotifManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
  Notification notification = new Notification();
  notification.icon = R.drawable.icon;
  notification.flags = Notification.FLAG_ONGOING_EVENT;
  notification.flags = Notification.FLAG_AUTO_CANCEL;
  notification.flags = Notification.FLAG_NO_CLEAR;
  RemoteViews mContentView = new RemoteViews(mContext.getPackageName(), 
  R.layout.notification_test);
  notification.contentView = mContentView;

  Intent intent = new Intent();
  intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  intent.setClass(mContext, TestActivity.class);
  PendingIntent pendingIntent =PendingIntent.getActivity(mContext, 0, intent, 
  PendingIntent.FLAG_UPDATE_CURRENT);                     
     notification.contentView.setOnClickPendingIntent(R.id.rl_notification, 
  pendingIntent);

  mNotifManager.notify(NOTIFYID, notification);

  如今咱们能够实现开头提到的那种效果了。可是,我发现最近任务中会有两个咱们应用的图标,看起来像是启动了两个咱们的应用,很是奇怪,而其实是由于咱们的应用启动了两个Task。咱们能够经过在manifest此Activity的属性中增长Android:excludeFromRecents=”true”。这属性用于设置由该Activity所启动的任务是否应该被排除在最近使用的应用程序列表以外。也就是说,当这个Activity是一个新任务的根节点时,这个属性决定了这个任务是否会显示在用户最近使用的应用程序列表中。若是设置为true,则这个任务会被排除在列表以外,为false,则表示会包含在最近使用的应用列表中。默认值是false。get

场景验证

  前提:将页面背景设置为半透明。
  一、未使用affinity
若是应用没有启动,点击通知栏,当前Activity被调起,透明背景后显示为桌面。
若是应用已经启动,点击通知栏,应用的Task调到前台,当前Activy显示在该Task的顶端。
  二、使用affinity
不管应用是否已经启动,点击通知栏,当前Activity都会被调起,透明背景后显示为桌面。
  两种状况下,看最近任务栏,都只显示一个应用图标。
  这样就实现了咱们想要的效果。it

相关文章
相关标签/搜索