在1月9號晚體驗了小程序之後,我使用魅族手機清除當前已經開啓的應用(多任務列表)的時候,我驚奇發現小程序居然“獨立”於微信有自己的“生命週期”。
如下:
圖中的 查地鐵,摩拜單車 都是開啓的小程序。這樣的效果是不是和獨立的app一樣呢!我是覺得簡直一模一樣!
出於好奇,查閱相關資料(見文末參考文獻)
初步分析如下:
小程序和微信就是顯示在系統的任務列表也就是開啓的任務縮略圖那裏,如上圖列出的就是最近啓動過的任務縮略圖。那麼研究思路就有了:找出這個縮略圖的形成過程就能找到答案了。其中有兩個重要的類如下:
// Recent apps
private RecentsPanelView mRecentsPanel;
private RecentTasksLoader mRecentTasksLoader;
RecentTasksLoader.java 部份代碼如下
// return a snapshot of the current list of recent apps
ArrayList<TaskDescription> getRecentTasks() {
cancelLoadingThumbnails();
ArrayList<TaskDescription> tasks = new ArrayList<TaskDescription>();
final PackageManager pm = mContext.getPackageManager();
final ActivityManager am = (ActivityManager)
mContext.getSystemService(Context.ACTIVITY_SERVICE);
final List<ActivityManager.RecentTaskInfo> recentTasks =
am.getRecentTasks(MAX_TASKS, ActivityManager.RECENT_IGNORE_UNAVAILABLE);
ActivityInfo homeInfo = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME)
.resolveActivityInfo(pm, 0);
HashSet<Integer> recentTasksToKeepInCache = new HashSet<Integer>();
int numTasks = recentTasks.size();
// skip the first task - assume it's either the home screen or the current activity.
final int first = 1;
recentTasksToKeepInCache.add(recentTasks.get(0).persistentId);
for (int i = first, index = 0; i < numTasks && (index < MAX_TASKS); ++i) {
final ActivityManager.RecentTaskInfo recentInfo = recentTasks.get(i);
TaskDescription item = createTaskDescription(recentInfo.id,
recentInfo.persistentId, recentInfo.baseIntent,
recentInfo.origActivity, recentInfo.description, homeInfo);
if (item != null) {
tasks.add(item);
++index;
}
}
// when we're not using the TaskDescription cache, we load the thumbnails in the
// background
loadThumbnailsInBackground(new ArrayList<TaskDescription>(tasks));
return tasks;
}
縮略圖的核心獲取方法:
RecentsPanelView.java 中 調用
refreshRecentTasksList(recentTaskDescriptions);
而最終得調用getRecentTasks()方法
mRecentTaskDescriptions = mRecentTasksLoader.getRecentTasks();
通過源碼分析,不難得出Android系統中,顯示最近程序列表的View是 RecentsPanelView類,通過refreshRecentTasksList()方法加載程序列表,其中RecentTasksLoader 負責最後的加載.
分析到這裏,已經明白是怎麼回事了,小程序並不是完全和微信獨立(只是看起來獨立了).”小程序”要實現和獨立app那樣有獨立的任務縮略圖(也就是入口), 只需要把目標activity設置爲 新Task 方式啓動就可以了。
演示demo
點擊“開啓一個小程序吧”按鈕,就打開了新activity(小程序),去任務列表中查看,果然設想如下圖所示。
如何實現:
實現上面的效果,只是需要兩步:
1. AndroidManifest.xml中爲 目標Activity 設置taskAffinity
<activity android:name=".MiniActivity"
android:label="小程序"
android:taskAffinity=".NewTask">
</activity>
2.以NEW_TASK方式啓動Activity
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this,MiniActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
ps:原來開啓的小程序都在新的task裏面而已
FLAG_ACTIVITY_NEW_TASK的介紹:
設置此狀態,首先會查找是否存在和被啓動的Activity具有相同的taskAffinity的task(注意同一個應用程序中默認所有activity 的taskAffinity是一樣的)。如果有,就直接把這個棧整體移動到前臺,並保持棧中的狀態不變,即棧中的activity順序不變,如果沒有,則新建一個棧來存放被啓動的activity.
也就是說,如果App已經啓動,即使用FLAG_ACTIVITY_NEW_TASK新啓動一個Activity, 因爲taskAffinity默認相同,也會被壓到一個task中, 自然recent panel 就看不到兩個入口了.
要實現預設的效果還需要爲目標activity設置一個參數taskAffinity=“.NewTask”,簡單的說就是設置(新建)該activity自己的啓動方式。
如何讓你的程序不出現在任務列表呢?
目前有兩種方式:
1.在AndroidManifest.xml目標Activity添加 android:excludeFromRecents屬性:
android:excludeFromRecents="true"
2.在啓動Activity的時候設置FLAG: Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
intent.setFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);