關於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

相關文章
相關標籤/搜索