今天被小程序刷屏了^^ 我也來(lái)湊湊熱鬧.

談?wù)勎⑿攀窃趺磳?shí)現在任務(wù)列表中顯示"小程序"的.

效果

微信中打開(kāi)了"滴滴(小程序)"后,

可以看到,任務(wù)列表不僅顯示了"微信", 還顯示了"滴滴(小程序)"的人口.

通過(guò)這個(gè)入口,就可以很方面的切換小程序了, 體驗和原生程序也一樣一樣的.

分析

下面簡(jiǎn)單分析一下他的實(shí)現.

1.Android系統中,顯示最近程序列表的View是 RecentsPanelView .

他通過(guò) refreshRecentTasksList() 加載程序列表,我們來(lái)看看代碼:

可以看到 RecentTasksLoader mRecentTasksLoader 負責真正處理數據加載.

RecentsPanelView.java

private RecentTasksLoader mRecentTasksLoader;  

* * *  

private void refreshRecentTasksList(
    ArrayList<TaskDescription> recentTasksList, boolean firstScreenful) {
    if (mRecentTaskDescriptions == null && recentTasksList != null){
      onTasksLoaded(recentTasksList, firstScreenful);
    } else {
      //加載最近的列表
      mRecentTasksLoader.loadTasksInBackground();
    }
  }

2.順著(zhù)看看RecentTasksLoader的實(shí)現:

這里可以清楚看到,加載的數據是 ActivityManager.getRecentTasks() .

也就是說(shuō)顯示的是Task列表.

RecentTasksLoader.java

ArrayList<TaskDescription>  getRecentTasks() {
       cancelLoadingThumbnails();

       ArrayList<TaskDescription> tasks = new ArrayList<TaskDescription>();
       final PackageManager pm = mContext.getPackageManager();
       final ActivityManager am = (ActivityManager)
               mContext.getSystemService(Context.ACTIVITY_SERVICE);

       //獲取最近的Task
       final List<ActivityManager.RecentTaskInfo> recentTasks =
               am.getRecentTasks(MAX_TASKS, ActivityManager.RECENT_IGNORE_UNAVAILABLE);

      * * *  
       return tasks;
   }

到這里,已經(jīng)很清楚了. 要顯示"小程序"入口, 只需要新建一個(gè)Task啟動(dòng)就好了~
是不是很簡(jiǎn)單啊.

來(lái)來(lái)來(lái)驗證一下我們的想法.

這里使用 adb shell dumpsys activity activities 查看一下Task狀態(tài)

1. 只開(kāi)啟微信

2. 開(kāi)啟小程序

如下圖所示, 微信新開(kāi)啟了一個(gè).AppBrandUI的task棧

實(shí)現

知道原理,實(shí)現就很簡(jiǎn)單了.

假設小程序的Activity是 TaskTestActivity,整個(gè)實(shí)現分兩步:

1. AndroidManifest.xml中為Activity設置taskAffinity

<activity
        android:icon="@drawable/didi"
        android:name=".TaskTestActivity"
        android:label="小程序測試"
        android:taskAffinity=".NewTask" />

2. 以NEW_TASK方式啟動(dòng)Activity

//以Intent.FLAG_ACTIVITY_NEW_TASK方式啟動(dòng)Activity
    Intent intent = new Intent(this, TaskTestActivity.class);
    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    startActivity(intent);

為什么要設置taskAffinity呢,

這和 FLAG_ACTIVITY_NEW_TASK 的特性有關(guān):

FLAG_ACTIVITY_NEW_TASK:設置此狀態(tài),首先會(huì )查找是否存在和被啟動(dòng)的Activity具有相同的taskAffinity的task(注意同一個(gè)應用程序中默認所有activity 的taskAffinity是一樣的),如果有,剛直接把這個(gè)棧整體移動(dòng)到前臺,并保持棧中的狀態(tài)不變,即棧中的activity順序不變,如果沒(méi)有,則新建一個(gè)棧來(lái)存放被啟動(dòng)的activity.

也就是說(shuō),如果App已經(jīng)啟動(dòng),即使用 FLAG_ACTIVITY_NEW_TASK 新起Activity, 因為taskAffinity相同,也會(huì )被壓到一個(gè)task中, 自然recent panel 就看不到兩個(gè)入口了.

所以我們需要為小程序設置一個(gè)新的taskAffinity

下面是demo效果

拓展

讓自己的程序不顯示在任務(wù)列表中

有時(shí)候我們做一個(gè)工具, 或者后臺界面, 不希望顯示在程序列表中.

也很簡(jiǎn)單,只要設置task的屬性就好了

方法1:

在A(yíng)ndroidManifest.xml設置Activity的 android:excludeFromRecents 為true

<activity
      android:excludeFromRecents="true"
      android:icon="@drawable/didi"
      android:name=".TaskTestActivity"
      android:label="小程序測試" />

方法2:

在啟動(dòng)Activity的時(shí)候加上 Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS FLAG

//Activity不顯示在recent列表中.
Intent intent = new Intent(this, TaskTestActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
startActivity(intent);