Launcher Series Catalogue:
First, android7.x Launcher3 source Parsing (1)-Start process
Second, android7.x Launcher3 source Code Analysis (2)-Frame structure
Third, android7.x Launcher3 source Code Analysis (3)-workspace and AllApps loading process
The first two blogs analyze the Lancher's start-up and launcher frame structure, which will focus on analyzing the loading process of the interface.
1. Overall process
Let's start with a whole flowchart. (The picture can not be seen in the download or right click on the new page to view the picture)
Start with the Launcher.java OnCreate method,
protected void onCreate(Bundle savedinstancestate) { ......//Establish Launcherappstate objectLauncherappstate.setapplicationcontext (Getapplicationcontext ()); Launcherappstate app = Launcherappstate.getinstance (); ......//Establish Launchermodel objectMmodel = App.setlauncher ( This);//Some other object initialization... setcontentview (r.layout.launcher); Setupviews ();if(!mrestoring) {if(Disable_synchronous_binding_current_page) {//If The user leaves launcher, then we should just load items asynchronously when //They return.Mmodel.startloader (Pagedview.invalid_restore_page); }Else{//We only load the page synchronously if the user rotates (or triggers a //configuration Change) while Launcher are in the foregroundMmodel.startloader (Mworkspace.getrestorepage ()); } } ......}
The focus calls the Startloader method of Launchermodel, Startloader inside, the most important thing is to start the Loadertask,mLoaderTask = new LoaderTask(mApp.getContext(), synchronousBindPage);
We then analyze the Loadertask run method.
Public voidRun () {......Keep_running: {if(debug_loaders)Log.DTAG,"Step 1:loading Workspace"); Loadandbindworkspace ();if(mstopped) {Break keep_running; } waitforidle ();//Second step if(debug_loaders)Log.DTAG,"Step 2:loading all Apps"); Loadandbindallapps (); Waitforidle ();//Third step if(debug_loaders)Log.DTAG,"Step 3:loading Deep Shortcuts"); Loadandbinddeepshortcuts (); }......}
Here are a few steps, loadAndBindWorkspace
–> waitForIdle()
, loadAndBindAllApps()
waitForIdle()
loadAndBindDeepShortcuts()
3 Step loading process inside are interspersed with waitforidle, this method is why?
Private void Waitforidle() { ......synchronized(Loadertask. This) {Final LongWorkspacewaittime = debug_loaders? Systemclock.uptimemillis ():0; Mhandler.postidle (NewRunnable () { Public void Run() {synchronized(Loadertask. This) {mloadandbindstepfinished =true;if(debug_loaders) {LOG.D (TAG,"Done with previous binding step"); } loadertask. This. Notify (); } } }); while(!mstopped &&!mloadandbindstepfinished) {Try{//Just in case mflushingworkerthread changes and we aren ' t woken up, //Wait no longer than 1sec at a time This. Wait ( +); }Catch(Interruptedexception ex) {//Ignore} } ...... } }
The load data is handled in the UI thread, and the UI thread is normally not blocked, otherwise it is possible to generate ANR, which can seriously affect the user experience. All here Loadertask after the result is sent to the UI thread, in order to ensure that the interface binding task can be completed efficiently, it often pauses its own task and waits for the UI thread to finish processing.
Analysis of this method:
First, create a task that the UI thread performs at leisure, which is responsible for setting some key control flags and adding them to the processor's message queue via the Postidle method. Once the task is executed, the mloadandbindstepfinished is set to true to control the impending conditional infinite wait. Finally, set a conditional infinite wait, waiting for instructions from the UI thread.
2. Workspace loading Process
As can be seen from the general flowchart, the loading process of workspace is mainly divided into loadWorkspace();
bindWorkspace(mPageToBindFirst);
A, Loadworkspace ()
Loadworkspace () The code is too much, here is not all out, the main function is responsible for reading data from the database table and translated into the data structure of the launcher desktop items.
Here are the steps:
1, carry out some pretreatment
2. Load Default values
LauncherAppState.getLauncherProvider().loadDefaultFavoritesIfNecessary()
Before Launcher2 loadDefaultFavoritesIfNecessary
This method, this is the way to load the default layout:
workspaceResId = sp.getInt(DEFAULT_WORKSPACE_RESOURCE_ID, R.xml.default_workspace);
But in Launcher3 , that's how it's loaded:
int workspaceResId = partnerRes.getIdentifier(Partner.RES_DEFAULT_LAYOUT, "xml", partner.getPackageName());
This place, I don't understand for the time being, which is the default layout?
3. Initialize data
Empty the previous memory data
/** Clears all the sBg data structures */ privatevoidclearSBgDataStructures() { synchronized (sBgLock) { sBgWorkspaceItems.clear(); sBgAppWidgets.clear(); sBgFolders.clear(); sBgItemsIdMap.clear(); sBgWorkspaceScreens.clear(); } }
4, Query ContentProvider, return the result set of Favorites table
Finalhashmap<string, integer> installingpkgs = Packageinstallercompat. getinstance (mContext). Updat Eandgetactivesessioncache ();FinalArraylist<long> Itemstoremove =NewArraylist<long> ();FinalArraylist<long> restoredrows =NewArraylist<long> ();FinalUri Contenturi = LauncherSettings.Favorites.CONTENT_URI;if(debug_loaders) LOG.D (TAG,"Loading model from"+ Contenturi);FinalCursor C = contentresolver.query (Contenturi,NULL,NULL,NULL,NULL);
5, according to different types, the data is saved to the corresponding ArrayList.
Types include the following:
ITEM_TYPE_APPLICATIONITEM_TYPE_SHORTCUTITEM_TYPE_FOLDERITEM_TYPE_APPWIDGETITEM_TYPE_CUSTOM_APPWIDGET
Save the data to a global variable based on the above types
Sbgitemsidmap,sbgworkspaceitemsm,sbgappwidgets,sbgfolders
In addition, if there are empty folders, empty screen, also delete, and finally, all the screen loaded into the global variable Sbgworkspacescreens.
......//Remove any empty folder for(LongFolderId:LauncherAppState.getLauncherProvider (). Deleteemptyfolders ()) { Sbgworkspaceitems.remove (Sbgfolders.get (FolderID)); Sbgfolders.remove (FolderID); Sbgitemsidmap.remove (FolderID); } ... sbgworkspacescreens.addall (Loadworkspacescreensdb (Mcontext));//Remove any empty screensArraylist<long> Unusedscreens =NewArraylist<long> (Sbgworkspacescreens); for(ItemInfo Item:sbgitemsidmap) {LongScreenid = Item.screenid;if(Item.container = = LauncherSettings.Favorites.CONTAINER_DESKTOP && Unusedscreens.contai NS (Screenid)) {unusedscreens.remove (Screenid); } }//If There is any empty screens remove them, and update. if(Unusedscreens.size ()! =0) {Sbgworkspacescreens.removeall (unusedscreens); Updateworkspacescreenorder (context, sbgworkspacescreens); }
B, Bindworkspace
The function of Bindworkspace is to display the data obtained above by launcher.
Steps:
1. Copy the data first:
synchronized (sBgLock) { workspaceItems.addAll(sBgWorkspaceItems); appWidgets.addAll(sBgAppWidgets); orderedScreenIds.addAll(sBgWorkspaceScreens); folders = sBgFolders.clone(); itemsIdMap = sBgItemsIdMap.clone(); }
2. Loading data and sorting
//装载桌面项数据 filterCurrentWorkspaceItems(currentScreenId, workspaceItems, currentWorkspaceItems, otherWorkspaceItems); //装载widget filterCurrentAppWidgets(currentScreenId, appWidgets, currentAppWidgets, otherAppWidgets); //装载文件夹 filterCurrentFolders(currentScreenId, itemsIdMap, folders, currentFolders, otherFolders); //排序 sortWorkspaceItemsSpatially(currentWorkspaceItems); sortWorkspaceItemsSpatially(otherWorkspaceItems);
3. Start binding
Just the last flowchart.
3. Loading of application Apps
Load the main process of the app, the top of the flowchart has been given, if all the apps are not loaded, then loadAllApps();
, or directlyonlyBindAllApps();
1, Loadallapps ()
According to the code, draw a flowchart, but I do not understand userprofile is a what ghost?
2, Onlybindallapps ()
The function here is much simpler than binding workspace, and notifies launcher binding directly
Runnable r =NewRunnable () { Public void Run() {Final Longt = Systemclock.uptimemillis ();FinalCallbacks callbacks = Trygetcallbacks (oldcallbacks);if(Callbacks! =NULL) {callbacks.bindallapplications (list); Callbacks.bindallpackages (widgetlist); }if(debug_loaders) {LOG.D (TAG,"Bound All"+ list.size () +"Apps from the cache in"+ (Systemclock.uptimemillis ()-T) +"MS"); } } };
Take a look at the function of launcher bindAllApplications
, of course, this function is also in the Loadallapps function, that is, how to bind the data to display it?
The Launcher.java bindAllApplications
function will set the data to Allappscontainerview.
ifnull) { mAppsView.setApps(apps); }
And then with the code to Allappscontainerview,
publicvoidsetApps(List<AppInfo> apps) { mApps.setApps(apps); }
Where does the apps work? The obvious is the onfinishinflate () function,
..... // Load the all apps recycler view mAppsRecyclerView = (AllAppsRecyclerView) findViewById(R.id.apps_list_view); mAppsRecyclerView.setApps(mApps); mAppsRecyclerView.setLayoutManager(mLayoutManager); mAppsRecyclerView.setAdapter(mAdapter); mAppsRecyclerView.setHasFixedSize(true);.....
Set to Recyclerview, it is clear that the Launcher application interface is a custom Recyclerview, adpter for this recyclerview binding is Allappsgridadapter, Looking at this adpter onCreateViewHolder
function, it is obvious that there are different layouts loaded depending on the type (app interface has apps and folders, there's a search box on the head, and this is the easiest to implement with Recyclerview). about how Recyclerview can load different layouts based on different types, you can refer to the different view implementations of the blog Recyclerview that I wrote a long time ago position load different.
Well, Launcher3 's workspace and application apps load the process, which will be followed by a detailed analysis of the contents of the launcher.
android7.x Launcher3 Source Parsing (3)---workspace and allapps loading process