Work needs to be summarized, so as to ensure that the Foundation is solid and can climb higher;
----
Reprinted please indicate the source: Http://blog.csdn.net/wdaming1986/article/details/8478533
Some time ago I studied the loading process of launcher's allapps and made some modifications to it. Haha, it's not that difficult, as long as I can view all the launcher code as 80%, it's basically how to change it! What is allapps? Click mainmenu on the idel interface (Main Interface) of Android to go to the interface, that is, all application interfaces;
Let's take a look at how it was loaded by a mobile phone?
Step 1: When the mobile phone is started for the first time, first load the launcherapplication, register some listeners, and share data, such as the launchermodel object, which can be obtained through (launcherapplication) getapplication ();The launcherapplication object, and then load the launcher. Java class. First, the oncreate () method. The following method is called.:
if (!mRestoring) { mModel.startLoader(this, true); }
Step 2: in step 1, this method is called launchemodel. in the Java class, the main task in this method is to start a thread. Let's take a look at what operations the thread's run () method has done;
public void run() { // Optimize for end-user experience: if the Launcher is up and // running with the // All Apps interface in the foreground, load All Apps first. Otherwise, load the // workspace first (default). final Callbacks cbk = mCallbacks.get(); final boolean loadWorkspaceFirst = cbk != null ? (!cbk.isAllAppsVisible()) : true; keep_running: { // Elevate priority when Home launches for the first time to avoid // starving at boot time. Staring at a blank home is not 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(); } else { if (DEBUG_LOADERS) Log.d(TAG, "step 1: special: loading all apps"); loadAndBindAllApps(); } if (mStopped) { break keep_running; } // Whew! Hard work done. Slow us down, and wait until the UI thread has // settled down. synchronized (mLock) { if (mIsLaunching) { if (DEBUG_LOADERS) Log.d(TAG, "Setting 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 are done loading items synchronized (mLock) { android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT); } } // Update the saved icons if necessary if (DEBUG_LOADERS) Log.d(TAG, "Comparing loaded icons to database icons"); for (Object key : sDbIconCache.keySet()) { updateSavedIcon(mContext, (ShortcutInfo) key, sDbIconCache.get(key)); } sDbIconCache.clear(); // Clear out this reference, otherwise we end up holding it until all of the // callback runnables are done. mContext = null; synchronized (mLock) { // If we are still the last one to be scheduled, remove ourselves. if (mLoaderTask == this) { mLoaderTask = null; } } }
In fact, the main operation is to load workspace and allapps; loadandbindallapps () is to load allapps;
Step 3: In this loadandbindallapps (), the system calls loadall1_bybatch () to load allapps in batches;
According:
final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null); mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
Create a mainintent with the category_launcher type, and then use
List<ResolveInfo> apps=packageManager.queryIntentActivities(mainIntent, 0);
Filter out all apps and sort APPs by sort:
Collections.sort(apps,new LauncherModel.ShortcutNameComparator(packageManager, mLabelCache));
After sorting, add these apps to the arraylist one by one: the code is as follows:
for (int j=0; i<N && j<batchSize; j++) { // This builds the icon bitmaps. mAllAppsList.add(new ApplicationInfo(packageManager, apps.get(i), mIconCache, mLabelCache)); i++; }
To the add method in allmedialist. Java:
public void add(ApplicationInfo info) { if (findActivity(data, info.componentName)) { return; } data.add(info); added.add(info); }
The definition of this added is:
public ArrayList<ApplicationInfo> added = new ArrayList<ApplicationInfo>(DEFAULT_APPLICATIONS_NUMBER);
Then, call back to the bindallapplications () method of launcher. Java by enabling the thread callback:
final ArrayList<ApplicationInfo> added = mAllAppsList.added; mAllAppsList.added = new ArrayList<ApplicationInfo>(); mHandler.post(new Runnable() { public void run() { final long t = SystemClock.uptimeMillis(); if (callbacks != null) { if (first) { callbacks.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"); } } });
Step 4: Do In the bindallapplications () method in launcher. Java: If a dialog box exists, remove the dialog box,Mainly
mAppsCustomizeContent.setApps(apps);
Step 5: In appscustomizepagedview. Java, setapps () is mainly used to assign values to mapps, sort apps again, and calculate the number of pages occupied by apps and the number of pages occupied by Widgets. The Code is as follows::
public void setApps(ArrayList<ApplicationInfo> list) { mApps = list; Collections.sort(mApps, LauncherModel.APP_NAME_COMPARATOR); updatePageCounts(); // The next layout pass will trigger data-ready if both widgets and apps are set, so // request a layout to do this test and invalidate the page data when ready. if (testDataReady()) requestLayout(); }
Updatepagecounts () is used to calculate the number of pages of apps and the number of pages of widgets;
Step 6: when entering this allapps, it will be called when accessing the appscustomizepagedview. Java class.
Onmeasure () method; In this method, allapps and widgets are verified first,
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int width = MeasureSpec.getSize(widthMeasureSpec); int height = MeasureSpec.getSize(heightMeasureSpec); if (!isDataReady()) { if (testDataReady()) { setDataIsReady(); setMeasuredDimension(width, height); onDataReady(width, height); } } super.onMeasure(widthMeasureSpec, heightMeasureSpec); }
Use testdataready () to verify whether they are empty! If they are empty, they are not loaded. The Code is as follows:
/** * This differs from isDataReady as this is the test done if isDataReady is not set. */ private boolean testDataReady() { // We only do this test once, and we default to the Applications page, so we only really // have to wait for there to be apps. // TODO: What if one of them is validly empty return !mApps.isEmpty() && !mWidgets.isEmpty(); }
When the allapps and widgets data are ready, set the width and height of the view to setmeasureddimension (width, height );
Then, call ondataready (width, height). In this method, the number of occupied pages, the width of the content, the number of cells, and mandatory measures are calculated to update and recalculate the gap and store the page, refresh the data display through invalidatepagedata (math. max (0, page), hostistransitioning );
This is called the pageview. Java class (the main essence class of launcher, which has been written quite well. After reading it several times and reading it every time). What I mainly do in this method is
(1) load the view of apps and widgets first, and use the method:
// Update all the pages syncPages();
public void syncPages() { removeAllViews(); cancelAllTasks(); Context context = getContext(); for (int j = 0; j < mNumWidgetPages; ++j) { PagedViewGridLayout layout = new PagedViewGridLayout(context, mWidgetCountX, mWidgetCountY); setupPage(layout); addView(layout, new PagedViewGridLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); } for (int i = 0; i < mNumAppsPages; ++i) { PagedViewCellLayout layout = new PagedViewCellLayout(context); setupPage(layout); addView(layout); } }
(2) refresh the data to the View Interface on each page. The method is as follows:
// Load any pages that are necessary for the current window of views loadAssociatedPages(mCurrentPage, immediateAndOnly); requestLayout();
In pageview. the main method called in the loadassociatedpages () method in Java syncpageitems (I, (I = page) & immediateandonly); this interface is called to appscustomizepagedview. the syncpageitems () method in Java is included:
@Override public void syncPageItems(int page, boolean immediate) { if (page < mNumAppsPages) { syncAppsPageItems(page, immediate); } else { syncWidgetPageItems(page - mNumAppsPages, immediate); } }
Refresh Every page of apps or widgets;
Let's take a look at the syncappspageitems () method:
public void syncAppsPageItems(int page, boolean immediate) { // ensure that we have the right number of items on the pages int numCells = mCellCountX * mCellCountY; int startIndex = page * numCells; int endIndex = Math.min(startIndex + numCells, mApps.size()); PagedViewCellLayout layout = (PagedViewCellLayout) getPageAt(page); layout.removeAllViewsOnPage(); ArrayList<Object> items = new ArrayList<Object>(); ArrayList<Bitmap> images = new ArrayList<Bitmap>(); for (int i = startIndex; i < endIndex; ++i) { ApplicationInfo info = mApps.get(i); PagedViewIcon icon = (PagedViewIcon) mLayoutInflater.inflate( R.layout.apps_customize_application, layout, false); icon.applyFromApplicationInfo(info, true, mHolographicOutlineHelper); icon.setOnClickListener(this); icon.setOnLongClickListener(this); icon.setOnTouchListener(this); icon.setOnKeyListener(this); int index = i - startIndex; int x = index % mCellCountX; int y = index / mCellCountX; layout.addViewToCellLayout(icon, -1, i, new PagedViewCellLayout.LayoutParams(x,y, 1,1)); items.add(info); images.add(info.iconBitmap); } layout.createHardwareLayers(); /* TEMPORARILY DISABLE HOLOGRAPHIC ICONS if (mFadeInAdjacentScreens) { prepareGenerateHoloOutlinesTask(page, items, images); } */ }
When you see this addviewtocelllayout () method, I believe that you will feel like "the mountains are poor and there is no way to go, and there is no way to go! This is the position where each icon is loaded to the view;
The same is true for syncwidgetpageitems (). I believe everyone can understand the code!
Step 7: How is the widgets data loaded ??? This is loaded step by step in the oncreate () method in launcher. Java:
(1) In the oncreate () method in launcher. Java:
// Update customization drawer _after_ restoring the states if (mAppsCustomizeContent != null) { mAppsCustomizeContent.onPackagesUpdated(); }
(2) Call the onpackagesupdated () method in appscustomizepagedview. Java, which mainly starts a delayed thread to load widgets.
public void onPackagesUpdated() { // TODO: this isn't ideal, but we actually need to delay here. This call is triggered // by a broadcast receiver, and in order for it to work correctly, we need to know that // the AppWidgetService has already received and processed the same broadcast. Since there // is no guarantee about ordering of broadcast receipt, we just delay here. Ideally, // we should have a more precise way of ensuring the AppWidgetService is up to date. postDelayed(new Runnable() { public void run() { updatePackages(); } }, 500); }
(3) through the updatepackages () method to load widgets, let's take a look at the Code:
public void updatePackages() { // Get the list of widgets and shortcuts boolean wasEmpty = mWidgets.isEmpty(); mWidgets.clear(); List<AppWidgetProviderInfo> widgets = AppWidgetManager.getInstance(mLauncher).getInstalledProviders(); Intent shortcutsIntent = new Intent(Intent.ACTION_CREATE_SHORTCUT); List<ResolveInfo> shortcuts = mPackageManager.queryIntentActivities(shortcutsIntent, 0); for (AppWidgetProviderInfo widget : widgets) { if (widget.minWidth > 0 && widget.minHeight > 0) { mWidgets.add(widget); } else { Log.e(LOG_TAG, "Widget " + widget.provider + " has invalid dimensions (" + widget.minWidth + ", " + widget.minHeight + ")"); } } mWidgets.addAll(shortcuts); Collections.sort(mWidgets, new LauncherModel.WidgetAndShortcutNameComparator(mPackageManager)); updatePageCounts(); if (wasEmpty) { // The next layout pass will trigger data-ready if both widgets and apps are set, so request // a layout to do this test and invalidate the page data when ready. if (testDataReady()) requestLayout(); } else { cancelAllTasks(); invalidatePageData(); } }
I believe that, based on the above analysis, we should understand the data loading process of mwidgets!
Step 8: View The onclick () method for the Click Event in it;
A long press is an onlongclick () event that calls the parent class pagedviewwithdraggableitems. Java:
@Override public boolean onLongClick(View v) { // Return early if this is not initiated from a touch if (!v.isInTouchMode()) return false; // Return early if we are still animating the pages if (mNextPage != INVALID_PAGE) return false; // When we have exited all apps or are in transition, disregard long clicks if (!mLauncher.isAllAppsCustomizeOpen() || mLauncher.getWorkspace().isSwitchingState()) return false; return beginDragging(v); }
The following code calls back the appscustomizepagedview. Java begindragging () method of the subclass:
private void beginDraggingApplication(View v) { mLauncher.getWorkspace().onDragStartedWithItem(v); mLauncher.getWorkspace().beginDragShared(v, this); }
You can follow the process in the future to understand the transfer of drag-and-drop events. In fact, it is similar to the drag-and-drop principle of folder;
Let's summarize it today!
January 7, 2013 in Beijing