日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android之Launcher分析和修改4——初始化加载数据

發布時間:2023/12/4 Android 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android之Launcher分析和修改4——初始化加载数据 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

上面一篇文章說了Launcher是如何被啟動的,Launcher啟動的過程主要是加載界面數據然后顯示出來,

界面數據都是系統APP有關的數據,都是從Launcher的數據庫讀取,下面我們詳細分析Launcher如何加載數據。

在Launcher.java的onCreate()方法里面,調用了開始加載數據接口:

//Edited by mythou //http://www.cnblogs.com/mythou/ //加載啟動數據 if (!mRestoring) {mModel.startLoader(this, true); }

mModel是LauncherModel的對象,由此可見,數據加載主要是在LauncherModel類里面實現的。

?

1、Callbacks接口

LauncherModel里面,需要先分析一個Callbacks接口。

//Edited by mythou //http://www.cnblogs.com/mythou/public interface Callbacks {public boolean setLoadOnResume();public int getCurrentWorkspaceScreen();public void startBinding();public void bindItems(ArrayList<ItemInfo> shortcuts, int start, int end);public void bindFolders(HashMap<Long,FolderInfo> folders);public void finishBindingItems();public void bindAppWidget(LauncherAppWidgetInfo info);public void bindAllApplications(ArrayList<ApplicationInfo> apps);public void bindAppsAdded(ArrayList<ApplicationInfo> apps);public void bindAppsUpdated(ArrayList<ApplicationInfo> apps);public void bindAppsRemoved(ArrayList<ApplicationInfo> apps, boolean permanent);public void bindPackagesUpdated();public boolean isAllAppsVisible();public void bindSearchablesChanged();} 復制代碼

Callbacks接口提供了很多接口,用于返回相關的數據給Launcher模塊,下面我們對每個接口作用做個闡釋。

setLoadOnResume()?:當Launcher.java類的Activity處于onPause的時候,如果重新恢復,需要調用onResume,此時需要在onResume調用這個接口,恢復Launcher數據。

getCurrentWorkspace():獲取屏幕序號(0~4)

startBinding():通知Launcher開始加載數據。清空容器數據,重新加載

bindItems(ArrayList<ItemInfo> shortcuts, int start, int end):加載App shortcut、Live Folder、widget到Launcher相關容器。

bindFolders(HashMap<Long, FolderInfo> folders):加載folder的內容

finishBindingItems():數據加載完成。

bindAppWidget(LauncherAppWidgetInfo item):workspace加載APP 快捷方式

bindAllApplications(final ArrayList<ApplicationInfo> apps):所有應用列表接著APP圖標數據

bindAppsAdded(ArrayList<ApplicationInfo> apps):通知Launcher新安裝了一個APP,更新數據。

bindAppsUpdated(ArrayList<ApplicationInfo> apps):通知Launcher一個APP更新了。(覆蓋安裝)

bindAppsRemoved(ArrayList<ApplicationInfo> apps, boolean permanent):通知Launcher,應用被刪除

bindPackagesUpdated():多個應用更新。

isAllAppsVisible():返回所有應用列表是否可見狀態。

bindSearchablesChanged():Google搜索欄或者刪除區域發生變化時通知Launcher

?

2、數據加載流程

Launcher.java類繼承了Callbacks接口,并實現了該接口。LauncherModel里面會調用這些接口,反饋數據和狀態給Launcher。數據加載總體分為兩部分,一部分是加載workspace的數據,另一部分是加載All APP界面的數據。

下面是一個加載數據流程圖:


3、startLoader()

下面我們先分析startLoader()接口,startLoader主要是啟動了一個線程,用于加載數據。

//Edited by mythou //http://www.cnblogs.com/mythou/ public void startLoader(Context context, boolean isLaunching) {synchronized (mLock) {//...............if (mCallbacks != null && mCallbacks.get() != null) {isLaunching = isLaunching || stopLoaderLocked();mLoaderTask = new LoaderTask(context, isLaunching);sWorkerThread.setPriority(Thread.NORM_PRIORITY);sWorker.post(mLoaderTask); }}}

startLoader主要是啟動LoaderTask線程里面的run方法。sWorker是一個Handle對象,用于啟動線程的run方法。

?

?4、LoaderTask的run()方法

//Edited by mythou //http://www.cnblogs.com/mythou/public void run() {//............keep_running: {//...............//加載當前頁面的數據,先把一頁的數據加載完成,//主要是為了增加程序流暢性,提高用戶體驗if (loadWorkspaceFirst) {if (DEBUG_LOADERS) Log.d(TAG, "step 1: loading workspace");loadAndBindWorkspace();} else {if (DEBUG_LOADERS) Log.d(TAG, "step 1: special: loading all apps");loadAndBindAllApps();}if (mStopped) {break keep_running;}// THREAD_PRIORITY_BACKGROUND設置線程優先級為后臺,//這樣當多個線程并發后很多無關緊要的線程分配的CPU時間將會減少,有利于主線程的處理synchronized (mLock) {if (mIsLaunching) {if (DEBUG_LOADERS) Log.d(TAG, "Setting thread priority to BACKGROUND");android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);}}//等待線程空閑的時候,繼續加載其他頁面數據waitForIdle();//加載剩余頁面的數據,包含workspace和all app頁面if (loadWorkspaceFirst) {if (DEBUG_LOADERS) Log.d(TAG, "step 2: loading all apps");loadAndBindAllApps();} else {if (DEBUG_LOADERS) Log.d(TAG, "step 2: special: loading workspace");loadAndBindWorkspace();}// Restore the default thread priority after we are done loading itemssynchronized (mLock) {android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);}}} 復制代碼

上面是經過簡化的LoaderTask的run方法代碼,其實主要就兩部分操作,第一部分操作,加載當前頁面的數據

(當前workspace頁面或者當前All APP頁面的數據)然后等待線程空閑的時候,再加載剩余的頁面數據。

代碼上面加了關鍵注釋,可以結合代碼分析。這樣做主要目的是增加Launcher啟動的速度,讓用戶覺得系統初始化速度

較快,有較好的用戶體驗。先把用戶看見的界面初始化完畢,然后再開一個后臺線程慢慢加載其他的數據。

下面我們分別分析workspace和All APP加載和綁定。

?

5、workspace加載數據

loadAndBindWorkspace()方法主要就是執行loadWorkspace()和 bindWorkspace()方法。 下面分別對這兩個方法進行分析。 //Edited by mythou //http://www.cnblogs.com/mythou/ private void loadWorkspace() {//..........//清空容器,存放界面不同的元素,App快捷方式、widget、foldersynchronized (sBgLock) {sBgWorkspaceItems.clear();sBgAppWidgets.clear();sBgFolders.clear();sBgItemsIdMap.clear();sBgDbIconCache.clear();final ArrayList<Long> itemsToRemove = new ArrayList<Long>();final Cursor c = contentResolver.query(LauncherSettings.Favorites.CONTENT_URI, null, null, null, null);// +1 for the hotseat (it can be larger than the workspace)// Load workspace in reverse order to ensure that latest items are loaded first (and// before any earlier duplicates)//表示屏幕上的位置,//第一維表示分屏的序號,其中最后一個代表Hotseat //第二維表示x方向方格的序號 //第三維表示y方向方格的序號final ItemInfo occupied[][][] =new ItemInfo[Launcher.SCREEN_COUNT + 1][mCellCountX + 1][mCellCountY + 1];//讀取數據庫響應鍵值列序號try {final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites._ID);final int intentIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.INTENT);final int titleIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE);final int iconTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_TYPE);//...........while (!mStopped && c.moveToNext()) {try {int itemType = c.getInt(itemTypeIndex);switch (itemType) {//item類型為ITEM_TYPE_APPLICATION或者ITEM_TYPE_SHORTCUT //container為CONTAINER_DESKTOP或者CONTAINER_HOTSEAT//把當前的item添加到sWorkspaceItems中case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:emType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {info = getShortcutInfo(manager, intent, context, c, iconIndex,titleIndex, mLabelCache);} else {info = getShortcutInfo(c, context, iconTypeIndex,iconPackageIndex, iconResourceIndex, iconIndex,titleIndex);switch (container) {case LauncherSettings.Favorites.CONTAINER_DESKTOP:case LauncherSettings.Favorites.CONTAINER_HOTSEAT://添加數據sBgWorkspaceItems.add(info);break;default://如果item的屬性是folder,添加到folder,創建forderFolderInfo folderInfo =findOrMakeFolder(sBgFolders, container);folderInfo.add(info);break;}sBgItemsIdMap.put(info.id, info);} else {}break;//item類型為文件夾,添加case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:id = c.getLong(idIndex);FolderInfo folderInfo = findOrMakeFolder(sBgFolders, id);//.........sBgItemsIdMap.put(folderInfo.id, folderInfo);sBgFolders.put(folderInfo.id, folderInfo);break;//Widget添加case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:// Read all Launcher-specific widget detailsint appWidgetId = c.getInt(appWidgetIdIndex);id = c.getLong(idIndex);//...........sBgItemsIdMap.put(appWidgetInfo.id, appWidgetInfo);sBgAppWidgets.add(appWidgetInfo);break;}} catch (Exception e) {Log.w(TAG, "Desktop items loading interrupted:", e);}}} finally {c.close();}}}

workspace的數據加載總的來說也是按照元素屬性來區分加載,分為App快捷方式、Widget、Folder元素。

這幾個元素分別加載到不同的容器里面。其中sItemsIdMap保存所有元素的id和ItemInfo組成的映射。其他

元素分別加載到3個不同的容器里面,用于后面綁定數據用。這里只給出了loadWorkspace的流程代碼,詳細代碼,

需要看源碼,還有很多細節。不過剛開始分析Launcher,我的原則是先把握整體流程和知道改動代碼,需要在哪里查找。

?

6、workspace綁定數據

Launcher的內容綁定分為五步:分別對應著startBinding()、bindItems()、bindFolders()、?bindAppWidgets()、

finishBindingItems()的調用。下面針對bindWorkspace做個簡單的流程分析。

//Edited by mythou //http://www.cnblogs.com/mythou/ private void bindWorkspace() {//通知Launcher開始綁定數據mHandler.post(new Runnable() {public void run() {Callbacks callbacks = tryGetCallbacks(oldCallbacks);if (callbacks != null) {//綁定數據到launcher,Launcher回調,清空相關容器 OWLcallbacks.startBinding();}}});//添加元素到workspace,主要是添加APP快捷方式N = workspaceItems.size();for (int i=0; i<N; i+=ITEMS_CHUNK) {final int start = i;final int chunkSize = (i+ITEMS_CHUNK <= N) ? ITEMS_CHUNK : (N-i);mHandler.post(new Runnable() {public void run() {Callbacks callbacks = tryGetCallbacks(oldCallbacks);if (callbacks != null) {callbacks.bindItems(workspaceItems, start, start+chunkSize);}}});}//文件夾綁定final HashMap<Long, FolderInfo> folders = new HashMap<Long, FolderInfo>(sFolders);mHandler.post(new Runnable() {public void run() {Callbacks callbacks = tryGetCallbacks(oldCallbacks);if (callbacks != null) {callbacks.bindFolders(folders);}}});//分兩次加載widget ,當前界面和其他界面,增強用戶體驗OWL//其他頁面widget會在后臺線程再次加載final int currentScreen = oldCallbacks.getCurrentWorkspaceScreen();N = sAppWidgets.size();// once for the current screenfor (int i=0; i<N; i++) {final LauncherAppWidgetInfo widget = sAppWidgets.get(i);if (widget.screen == currentScreen) {mHandler.post(new Runnable() {public void run() {Callbacks callbacks = tryGetCallbacks(oldCallbacks);if (callbacks != null) {callbacks.bindAppWidget(widget);}}});}}//加載其他看不見的屏幕widgetfor (int i=0; i<N; i++) {final LauncherAppWidgetInfo widget = sAppWidgets.get(i);if (widget.screen != currentScreen) {mHandler.post(new Runnable() {public void run() {Callbacks callbacks = tryGetCallbacks(oldCallbacks);if (callbacks != null) {callbacks.bindAppWidget(widget);}}});}}//加載完成,通知Launcher,已經完成數據加載mHandler.post(new Runnable() {public void run() {Callbacks callbacks = tryGetCallbacks(oldCallbacks);if (callbacks != null) {callbacks.finishBindingItems();}}});}

?上面就是Launcher的workspace綁定數據的過程,跟加載數據過程很相似,也是區分3中類型的元素進行加載。

下面我們總結一下,workspace的加載和綁定數據的過程。我們現在回頭看,可以發現,其實workspace里面就是

存放了3中數據ItemInfo、FolderInfo、LauncherAppWidgetInfo。分別對應我們的APP快捷方式、文件夾、Widget

數據。其中FolderInfo、LauncherAppWidgetInfo都是繼承了ItemInfo。數據加載過程,就是從Launcher的數據庫

讀取數據然后按元素屬性分別放到3個ArrayList里面。綁定數據過程就是把3個ArrayList的隊列關聯到Launcher界面里面。

?7、ALL APP數據加載綁定

//Edited by mythou //http://www.cnblogs.com/mythou/ private void loadAllAppsByBatch() {//只有這兩個標記才需要顯示在所有程序列表 OWLfinal Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);final PackageManager packageManager = mContext.getPackageManager();List<ResolveInfo> apps = null;int N = Integer.MAX_VALUE;int startIndex;int i=0;int batchSize = -1;while (i < N && !mStopped) {if (i == 0) {mAllAppsList.clear();final long qiaTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;//過濾需要顯示的appapps = packageManager.queryIntentActivities(mainIntent, 0);if (DEBUG_LOADERS) {Log.d(TAG, "queryIntentActivities took "+ (SystemClock.uptimeMillis()-qiaTime) + "ms");}if (apps == null) {return;}N = apps.size();if (DEBUG_LOADERS) {Log.d(TAG, "queryIntentActivities got " + N + " apps");}if (N == 0) {// There are no apps?!?return;}//mBatchSize==0表示一次性加載所有的應用 if (mBatchSize == 0) {batchSize = N;} else {batchSize = mBatchSize;}}final boolean first = i <= batchSize;final Callbacks callbacks = tryGetCallbacks(oldCallbacks);final ArrayList<ApplicationInfo> added = mAllAppsList.added;mAllAppsList.added = new ArrayList<ApplicationInfo>();//綁定加載所有的APP數據mHandler.post(new Runnable() {public void run() {final long t = SystemClock.uptimeMillis();if (callbacks != null) {if (first) {//一次性加載所以app,返回數據到launchercallbacks.bindAllApplications(added);} else {callbacks.bindAppsAdded(added);}if (DEBUG_LOADERS) {Log.d(TAG, "bound " + added.size() + " apps in "+ (SystemClock.uptimeMillis() - t) + "ms");}} else {Log.i(TAG, "not binding apps: no Launcher activity");}}}); }

AllAPP的數據加載和綁定跟workspace的差不多,也是先加載數據然后綁定數據,通知Launcher。加載數據的時候

PackageManager獲取所有已經安裝的APK包信息,然后過濾只包含需要顯示在所有應用列表的應用,需要包含

ACTION_MAIN和CATEGORY_LAUNCHER兩個屬性。這個我們在編寫應用程序的時候都應該知道。

AllAPP加載跟workspace不同的地方是加載的同時,完成數據綁定的操作,也就是說第一次加載AllAPP頁面的數據,

會同時綁定數據到Launcher。第二次需要加載的時候,只會把數據直接綁定到Launcher,而不會重新搜索加載數據。

Launcher啟動加載和綁定數據就是這樣完成。綁定完數據,Launcher就可以運行。





總結

以上是生活随笔為你收集整理的Android之Launcher分析和修改4——初始化加载数据的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。