Today the main analysis of the Android Launcher source code in the relationship between some important classes, the basic loading process. Take a look at a class diagram first
Launcher.java is the primary activity that initializes the Launchermode instance within the OnCreate method.
Launcherapplication app = ((launcherapplication) getapplication ());
Mmodel = App.setlauncher (this);
The method of directly entering Launcherapplication.java
Launchermodel Setlauncher (Launcher Launcher) { mmodel.initialize (Launcher); return mmodel; }
Here Mmodel is the Launchermodel class, Launchermodel play an important role, is actually a broadcast, monitoring the app installation, change, and uninstall is also loading all the app information
Here launcher implemented the callbacks interface, directly added to the callbacks list, the back of a lot of functions to rely on it callback processing
public void Initialize (callbacks callbacks) { synchronized (mLock) { mcallbacks = new weakreference< Callbacks> (callbacks); } }
See the following code in the Launcher.java oncreate code.
if (!mrestoring) { if (spausedfromuseraction) { //If the user leaves launcher, then we should just load items asy nchronously when //they return. Mmodel.startloader (True,-1); } else { //We only load the page synchronously if the user rotates (or triggers a //configuration change) while LA Uncher is in the foreground Mmodel.startloader (True, Mworkspace.getcurrentpage ()); } }
Note In the source code also shows the situation in 2, one is that the current user interface is not the desktop may be an application interface so that we load asynchronously through the background.
Another scenario is to refresh the app information data for the current page.
Now locate the Launchermode.java source in the Startloader Method section code below.
if (Synchronousbindpage >-1 && mallappsloaded && mworkspaceloaded) { Mloadertask.runbindsynchronouspage (synchronousbindpage);//synchronously loads the current page } else { sworkerthread.setpriority ( thread.norm_priority); Sworker.post (mloadertask);//Asynchronous Load }
As mentioned above, load the current page information or update all the information. Synchronousbindpage is the current user swipe to the first few screens, altogether 5 screens.
We used the Loadertask. This class is a runnable implementation. This place uses Handlerthread (this class I have not used before, has been to get looper to deal with myself)
This class is a concrete load of Appinfo,appwidget, folder information.
Let's look at the Loadertask run method implementation. Note that Loadertask is the inner class of Launchermode.
Keep_running: {//Elevate first time Home launches for the first time to avoid Starving at boot time. Staring at a blank home isn't cool. Synchronized (MLock) {if (debug_loaders) log.d (TAG, "Setting thread priority to" + (mislaunching?) "DEFAULT": "BACKGROUND")); Android.os.Process.setThreadPriority (mislaunching? Process.THREAD_PRIORITY_DEFAULT:Process.THREAD_PRIORITY_BACKGROUND); } if (Loadworkspacefirst) {if (debug_loaders) log.d (TAG, "Step 1:loading Workspace"); Loadandbindworkspace ();//First Load} else {if (debug_loaders) log.d (TAG, "Step 1:special:loading All Apps"); Loadandbindallapps (); Update Data} if (mstopped) {break keep_running; } whew! Hard work done. Slow us down, and wait until the UI thread have//settled down. Synchronized (MLock) {if (mislaunching) {if (debug_loaders) log.d (TAG, "settin G Thread priority to BACKGROUND "); Android.os.Process.setThreadPriority (Process.thread_priority_background); }} waitforidle (); Second step 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 were done loading items synchronized (mLock ) {android.os.Process.setThreadPriority (ProcEss. Thread_priority_default); } }
According to the source note is the first time to load workspace, the second time to load all the app information, you will find the Loadandbindallapps method and Loadandbindworkspace 2 times the call is inverted.
My understanding is to perform load workspace and then load all apps.
We are positioned in the Loadandbindworkspace method,
if (!mworkspaceloaded) { loadworkspace (); Synchronized (loadertask.this) { if (mstopped) { return; } mworkspaceloaded = true; } }
Call the Loadworkspace method if workspace has not yet been loaded. Locating in this method, it is clear that the application information is directly obtained including widgets.
The packagemanager,appwidgetmanager,contentresolver is called directly for information.
After the reading information is saved we need to rendezvous with workspace, this place is called Bindworkspace
In this aspect we will find that using the callbacks mentioned above, the callback complete data is displayed with the view binding.
/** * Binds all loaded data to actual views on the main thread. */private void bindworkspace (int synchronizebindpage) {final Long T = Systemclock.uptimemillis (); Runnable R; Don ' t use these-variables in any of the callback runnables. Otherwise we hold a reference to them. Final callbacks oldcallbacks = Mcallbacks.get (); if (oldcallbacks = = null) {//This launcher have exited and nobody bothered to tell us. Just bail. LOG.W (TAG, "Loadertask Running with no launcher"); Return } Final Boolean isloadingsynchronously = (Synchronizebindpage >-1); Final int currentscreen = isloadingsynchronously? SynchronizeBindPage:oldCallbacks.getCurrentWorkspaceScreen (); Load all the items is on the current page first (and in the process, unbind//all the existing worksPace items before we call StartBinding () below. Unbindworkspaceitemsonmainthread (); arraylist<iteminfo> workspaceitems = new arraylist<iteminfo> (); arraylist<launcherappwidgetinfo> appwidgets = new arraylist<launcherappwidgetinfo> (); Hashmap<long, folderinfo> folders = new Hashmap<long, folderinfo> (); Hashmap<long, iteminfo> itemsidmap = new Hashmap<long, iteminfo> (); Synchronized (Sbglock) {workspaceitems.addall (sbgworkspaceitems); Appwidgets.addall (sbgappwidgets); Folders.putall (sbgfolders); Itemsidmap.putall (SBGITEMSIDMAP); } arraylist<iteminfo> Currentworkspaceitems = new arraylist<iteminfo> (); arraylist<iteminfo> otherworkspaceitems = new arraylist<iteminfo> (); Arraylist<launcherappwidgetinfo> currentappwidgets = New Arraylist<launcherappwidgetinfo> (); arraylist<launcherappwidgetinfo> otherappwidgets = new arraylist<launcherappwidgetinfo> (); Hashmap<long, folderinfo> currentfolders = new Hashmap<long, folderinfo> (); Hashmap<long, folderinfo> otherfolders = new Hashmap<long, folderinfo> (); Separate the items is on the "current" screen, and the "other remaining items filtercurrentworkspacei TEMs (Currentscreen, Workspaceitems, Currentworkspaceitems, Otherworkspaceitems); Filtercurrentappwidgets (Currentscreen, Appwidgets, Currentappwidgets, otherappwidgets); Filtercurrentfolders (Currentscreen, Itemsidmap, folders, Currentfolders, otherfolders); Sortworkspaceitemsspatially (Currentworkspaceitems); Sortworkspaceitemsspatially (Otherworkspaceitems); TelL The workspace that we ' re on to start binding items R = new Runnable () {public void run () { Callbacks callbacks = Trygetcallbacks (oldcallbacks); if (callbacks! = null) {callbacks.startbinding (); } } }; Runonmainthread (R); Load items on the current page Bindworkspaceitems (oldcallbacks, Currentworkspaceitems, Currentappwidgets, Currentfolders, NULL); if (isloadingsynchronously) {r = new Runnable () {public void run () { Callbacks callbacks = Trygetcallbacks (oldcallbacks); if (callbacks! = null) {callbacks.onpageboundsynchronously (currentscreen); } } }; Runonmainthread (R); }//Load all the Remaining pages (if we are loading synchronously, we want to defer this//work until after the first render) Mdeferredbindrunnables.clear (); Bindworkspaceitems (Oldcallbacks, Otherworkspaceitems, Otherappwidgets, Otherfolders, IsLoadingSynchron Ously? Mdeferredbindrunnables:null)); Tell the workspace, that we ' re do binding items R = new Runnable () {public void run () { Callbacks callbacks = Trygetcallbacks (oldcallbacks); if (callbacks! = null) {Callbacks.finishbindingitems (); }//If we ' re profiling, ensure the last thing in the queue. if (debug_loaders) {log.d (TAG, "Bound workspace in" + (Systemclock.upt Imemillis ()-T) + "MS"); } Misloadingandbindingworkspace = false; } }; if (isloadingsynchronously) {Mdeferredbindrunnables.add (R); } else {Runonmainthread (R); } }
This code has a lot to explain, the essence is app,widgets, folders get and pass to the main interface. Analysis here today. There's a lot going on back there, this time.
If you have any questions, please say thank you. O (∩_∩) o~
Android Launcher Source Research (ii) Load app flow 1