注释1调用的是scheduleResumeTopActivities()方法,这个方法其实是关于Activity的启动流程的逻辑了,这里我们就不详细说明了,关于Activity的启动流程可以参考我后面文章。

这样Launcher就会被启动起来,并执行它的onCreate函数。

Android应用程序安装

Android系统在启动的过程中,Zygote进程启动SystemServer进程,SystemServer启动PackageManagerService服务,这个服务负责扫描系统中特定的目录,找到里面的应用程序文件,即以Apk为后缀的文件,然后对这些文件进解析(其实就是解析应用程序配置文件AndroidManifest.xml的过程),并从里面得到得到应用程序的相关信息,例如得到应用程序的组件Package、Activity、Service、Broadcast Receiver和Content Provider等信息,保存到PackageManagerService的mPackages、mActivities、mServices、mReceivers等成员变量(HashMap类型)中,得到应用程序

android launcher分析和修改1 androidlauncher启动流程_移动开发


的相关信息之后,完成应用程序的安装过程。

这些应用程序只是相当于在PackageManagerService服务注册好了,如果我们想要在Android桌面上看到这些应用程序,还需要有一个Home应用程序(Android系统默认的Home应用程序就是Launcher),负责从PackageManagerService服务中把这些安装好的应用程序取出来,并以友好的方式在桌面上展现出来,例如以快捷图标的形式,接着往下看。

Launcher中应用图标显示流程
从Launcher的onCreate函数开始分析。

packages/apps/Launcher3/src/com/android/launcher3/Launcher.java

Launcher#onCreate()

@Override
 protected void onCreate(Bundle savedInstanceState) {
 …
 LauncherAppState app = LauncherAppState.getInstance();//1
 mDeviceProfile = getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE ?
 app.getInvariantDeviceProfile().landscapeProfile
 : app.getInvariantDeviceProfile().portraitProfile;
 mSharedPrefs = Utilities.getPrefs(this);
 mIsSafeModeEnabled = getPackageManager().isSafeMode();
 mModel = app.setLauncher(this);//2
 …
 if (!mRestoring) {
 if (DISABLE_SYNCHRONOUS_BINDING_CURRENT_PAGE) {
 mModel.startLoader(PagedView.INVALID_RESTORE_PAGE);//3
 } else {
 mModel.startLoader(mWorkspace.getRestorePage());
 }
 }
 …
 }

注释1处获取LauncherAppState的实例。
注释2处调用它的setLauncher函数并将Launcher对象传入。

packages/apps/Launcher3/src/com/android/launcher3/LauncherAppState.java

LauncherAppState#setLauncher()

LauncherModel setLauncher(Launcher launcher) {
 getLauncherProvider().setLauncherProviderChangeListener(launcher);
 mModel.initialize(launcher);//1
 mAccessibilityDelegate = ((launcher != null) && Utilities.ATLEAST_LOLLIPOP) ? new LauncherAccessibilityDelegate(launcher) : null;
 return mModel;
 }

注释1处会调用LauncherModel的initialize函数。

packages/apps/Launcher3/src/com/android/launcher3/LauncherModel.java

LauncherModel#initialize()

public void initialize(Callbacks callbacks) {
 synchronized (mLock) {
 unbindItemInfosAndClearQueuedBindRunnables();
 mCallbacks = new WeakReference(callbacks);
 }
 }

在initialize函数中会将Callbacks,也就是传入的Launcher封装成一个弱引用对象。因此我们得知mCallbacks变量指的就是封装成弱引用对象的Launcher,这个mCallbacks后文会用到它。

再回到Launcher的onCreate函数,在注释3处调用了LauncherModel的startLoader函数:

LauncherModel#startLoader()

…
 @Thunk static final HandlerThread sWorkerThread = new HandlerThread(“launcher-loader”);//1
 static {
 sWorkerThread.start();
 }
 @Thunk static final Handler sWorker = new Handler(sWorkerThread.getLooper());//2
 …
 public void startLoader(int synchronousBindPage, int loadFlags) {
 InstallShortcutReceiver.enableInstallQueue();
 synchronized (mLock) {
 synchronized (mDeferredBindRunnables) {
 mDeferredBindRunnables.clear();
 }
 if (mCallbacks != null && mCallbacks.get() != null) {
 stopLoaderLocked();
 mLoaderTask = new LoaderTask(mApp.getContext(), loadFlags); //3
 if (synchronousBindPage != PagedView.INVALID_RESTORE_PAGE && mAllAppsLoaded && mWorkspaceLoaded && !mIsLoaderTaskRunning) {
 mLoaderTask.runBindSynchronousPage(synchronousBindPage);
 } else {
 sWorkerThread.setPriority(Thread.NORM_PRIORITY);
 sWorker.post(mLoaderTask);//4
 }
 }
 }
 }

注释1处创建了具有消息循环的线程HandlerThread对象。
注释2处创建了Handler,并且传入HandlerThread的Looper。Hander的作用就是向HandlerThread发送消息。
注释3处创建LoaderTask。
注释4处将LoaderTask作为消息发送给HandlerThread 。LoaderTask类实现了Runnable接口。

LoaderTask

private class LoaderTask implements Runnable {
 …
 public void run() {
 synchronized (mLock) {
 if (mStopped) {
 return;
 }
 mIsLoaderTaskRunning = true;
 }
 keep_running: {
 if (DEBUG_LOADERS) Log.d(TAG, “step 1: loading workspace”);
 loadAndBindWorkspace();//1
 if (mStopped) {
 break keep_running;
 }
 waitForIdle();
 if (DEBUG_LOADERS) Log.d(TAG, “step 2: loading all apps”);
 loadAndBindAllApps();//2
 }
 mContext = null;
 synchronized (mLock) {
 if (mLoaderTask == this) {
 mLoaderTask = null;
 }
 mIsLoaderTaskRunning = false;
 mHasLoaderCompletedOnce = true;
 }
 }
 …
 }

Launcher是用工作区的形式来显示系统安装的应用程序的快捷图标,每一个工作区都是来描述一个抽象桌面的,它由n个屏幕组成,每个屏幕又分n个单元格,每个单元格用来显示一个应用程序的快捷图标。
注释1处调用loadAndBindWorkspace函数用来加载工作区信息。
注释2处的loadAndBindAllApps函数是用来加载系统已经安装的应用程序信息。

LauncherModel#loadAndBindAllApps()

private void loadAndBindAllApps() {
 if (DEBUG_LOADERS) {
 Log.d(TAG, “loadAndBindAllApps mAllAppsLoaded=” + mAllAppsLoaded);
 }
 if (!mAllAppsLoaded) {
 loadAllApps();//1
 synchronized (LoaderTask.this) {
 if (mStopped) {
 return;
 }
 }
 updateIconCache();
 synchronized (LoaderTask.this) {
 if (mStopped) {
 return;
 }
 mAllAppsLoaded = true;
 }
 } else {
 onlyBindAllApps();
 }
 }

如果系统没有加载已经安装的应用程序信息,则会调用注释1处的loadAllApps()函数。

LauncherModel#loadAllApps()

private void loadAllApps() {
 …
 final List apps = mLauncherApps.getActivityList(null, user); //1
 // Fail if we don’t have any apps
 // TODO: Fix this. Only fail for the current user.
 if (apps == null || apps.isEmpty()) {
 return;
 }
 // Create the ApplicationInfos
 for (int i = 0; i < apps.size(); i++) {
 LauncherActivityInfoCompat app = apps.get(i);
 // This builds the icon bitmaps.
 mBgAllAppsList.add(new AppInfo(mContext, app, user, mIconCache, quietMode)); //2
 }
 …
 // Huh? Shouldn’t this be inside the Runnable below?
 final ArrayList added = mBgAllAppsList.added;
 mBgAllAppsList.added = new ArrayList();mHandler.post(new Runnable() {
 public void run() {
 final long bindTime = SystemClock.uptimeMillis();
 final Callbacks callbacks = tryGetCallbacks(oldCallbacks);
 if (callbacks != null) {
 callbacks.bindAllApplications(added); //3
 if (DEBUG_LOADERS) {
 Log.d(TAG, "bound " + added.size() + " apps in " + (SystemClock.uptimeMillis() - bindTime) + “ms”);
 }
 } else {
 Log.i(TAG, “not binding apps: no Launcher activity”);
 }
 }
 });
 …
 }

注释1处获取所有已经安装的符合要求的Application信息。
注释2中将Application信息封装成AppInfo并添加到mBgAllAppsList列表中。
注释3处会调用callbacks的bindAllApplications函数并传入AppInfo列表,在前面我们得知这个callbacks实际是指向Launcher的,因此这里调用的是Launcher的bindAllApplications函数。

下面先看看注释1如何获取Application信息:

packages/apps/Launcher3/src/com/android/launcher3/compat/LauncherAppsCompatV16.java

LauncherAppsCompatV16#getActivityList()

public List getActivityList(String packageName, UserHandleCompat user) {
 //1
 final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
 mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
 mainIntent.setPackage(packageName);
 List infos = mPm.queryIntentActivities(mainIntent, 0); //2
 List list =
 new ArrayList(infos.size());
 for (ResolveInfo info : infos) {
 list.add(new LauncherActivityInfoCompatV16(mContext, info));
 }
 return list;
 }

注释1处构造带有ACTION_MAIN和CATEGORY_LAUNCHER的intent。
注释2处通过PackageManagerService.queryIntentActivities接口来取回系统中所有符合intent条件的Activity,即需要显示到桌面上的应用。(前面启动PackageManagerService时,会把系统中的应用程序都解析一遍,然后把解析得到的Activity都保存在mActivities成员变量中,这里通过这个mActivities变量的queryIntent函数返回符合intent条件的Activity,即Action类型为Intent.ACTION_MAIN,并且Category类型为Intent.CATEGORY_LAUNCHER的Activity)

回退一步,继续来看Launcher的bindAllApplications函数:

Launcher#bindAllApplications()

public void bindAllApplications(final ArrayList apps) {
 if (waitUntilResume(mBindAllApplicationsRunnable, true)) {
 mTmpAppsList = apps;
 return;
 }
 if (mAppsView != null) {
 mAppsView.setApps(apps); //1
 }
 if (mLauncherCallbacks != null) {
 mLauncherCallbacks.bindAllApplications(apps);
 }
 }

注释1处会调用AllAppsContainerView的setApps函数,并将包含应用信息的列表apps传进去。

packages/apps/Launcher3/src/com/android/launcher3/allapps/AllAppsContainerView.java

AllAppsContainerView#setApps()

public void setApps(List apps) {
 mApps.setApps(apps);
 }

包含应用信息的列表apps已经传给了AllAppsContainerView,查看AllAppsContainerView的onFinishInflate函数。

AllAppsContainerView#onFinishInflate()
@Override
 protected void onFinishInflate() {
 super.onFinishInflate();
 …
 // Load the all apps recycler view
 mAppsRecyclerView = (AllAppsRecyclerView) findViewById(R.id.apps_list_view);//1
 mAppsRecyclerView.setApps(mApps);//2
 mAppsRecyclerView.setLayoutManager(mLayoutManager);
 nishInflate()@Override
 protected void onFinishInflate() {
 super.onFinishInflate();
 …
 // Load the all apps recycler view
 mAppsRecyclerView = (AllAppsRecyclerView) findViewById(R.id.apps_list_view);//1
 mAppsRecyclerView.setApps(mApps);//2
 mAppsRecyclerView.setLayoutManager(mLayoutManager);