Android系统源码阅读(18):Android 应用的显示

1. 启动ActivityManagerService

在前面第14章讲到,在System进程启动时,会启动系统的一些基本服务。启动就有ActivityManagerService和PackageManagerService。在SystemServer中如下启动ActivityManagerService。

frameworks/base/services/java/com/android/server/SystemServer.java :

 // Activity manager runs the show. mActivityManagerService = mSystemServiceManager.startService(ActivityManagerService.Lifecycle.class).getService();

startService就是创建了ActivityManagerService的实例对象mActivityManagerService,然后启动了ActivityManagerService的looper线程。在SystemServer启动了基本服务后,就会调用mActivityManagerService的systemReady函数来启动HomeActivity。

2. 启动HomeActivity

目前仍在SystemServer主线程中调用的systemReady函数。该函数又会接着调用startHomeActivityLocked函数来启动HomeActivity,具体如下:

frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java :

  boolean startHomeActivityLocked(int userId, String reason) {        //...        //先创建一个启动Home的Intent,Intent的category为android.intent.category.home        Intent intent = getHomeIntent();        ActivityInfo aInfo =            resolveActivityInfo(intent, STOCK_PM_FLAGS, userId);        if (aInfo != null) {            intent.setComponent(new ComponentName(                    aInfo.applicationInfo.packageName, aInfo.name));            // Don't do this if the home app is currently being            // instrumented.            aInfo = new ActivityInfo(aInfo);            aInfo.applicationInfo = getAppInfoForUser(aInfo.applicationInfo, userId);            //因为是第一次启动home,所以还没有相应的进程,所以app为null            ProcessRecord app = getProcessRecordLocked(aInfo.processName,                    aInfo.applicationInfo.uid, true);            if (app == null || app.instrumentationClass == null) {                intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);                //这里开始启动HomeActivity                mStackSupervisor.startHomeActivity(intent, aInfo, reason);            }        }        return true;    }

这里交给了mStackSupervisor.startHomeActivity函数来启动HomeActivity,然后就会调用startActivityLocked函数。到这里,就开始重复第2章中,启动普通应用的activity的过程了,不再赘述。其中,在Launcher的Manifest中指明了它的类型为android.intent.category.home,所以启动的就是Laucher应用。

3. Launcher展示应用

下面从Launcher的onCreate函数开始讲起,部分代码如下:

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

LauncherAppState app = LauncherAppState.getInstance();//将该launcher设置为mModel的callback函数mModel = app.setLauncher(this);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 is in the foreground        //开始加载应用信息        mModel.startLoader(mWorkspace.getRestorePage());      }}

其中mModel是一个LauncherModel对象,它负责加载应用信息。在重载的startLoader函数中:

 public void startLoader(int synchronousBindPage, int loadFlags) {        //...        synchronized (mLock) {            //...            // Don't bother to start the thread if we know it's not going to do anything            if (mCallbacks != null && mCallbacks.get() != null) {                //需要重新加载了,所以先把原来的加载任务停了                // If there is already one running, tell it to stop.                stopLoaderLocked();                //创建了一个加载任务                mLoaderTask = new LoaderTask(mApp.getContext(), loadFlags);                if (synchronousBindPage != PagedView.INVALID_RESTORE_PAGE                    //...                } else {                    //交给workThread来处理这个任务                    sWorkerThread.setPriority(Thread.NORM_PRIORITY);                    //sWorker是sWorkerThread的Handler                    sWorker.post(mLoaderTask);                }            }        }    }

因为加载所有安装的应用信息是一个比较耗时的过程,所以应该交给一个异步线程来处理。这里先创建了一个加载任务mLoaderTask,然后将它交给sWorkerThread来处理。sWorkerThread是一个HandlerThread,我们知道HandlerThread是一个独立的线程,并且有着自己的looper。mLoaderTask加载任务执行一次就可以结束,但是为什么需要用一个HandlerThread在这里不断等待着其它任务呢?因为桌面上应用可以动态的添加和删除,所以应用的加载可能是频繁的。这里使用HandlerThread可以避免重复的创建加载线程。

下面我们就看LoaderTask.run函数中具体做了哪些任务。

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

      public void run() {            synchronized (mLock) {                if (mStopped) {                    return;                }                mIsLoaderTaskRunning = true;            }            // 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).            keep_running: {                if (DEBUG_LOADERS) Log.d(TAG, "step 1: loading workspace");                //启动workspace                loadAndBindWorkspace();                if (mStopped) {                    break keep_running;                }                waitForIdle();                // second step                if (DEBUG_LOADERS) Log.d(TAG, "step 2: loading all apps");                //加载应用                loadAndBindAllApps();            }            //...        }

WorkSpace就是Android桌面中的分屏,每个分屏有若干应用。先加载工作区,再加载应用更符合用户的心理预期?函数loadAndBindAllApps会判断是否已经加载过应用,如果已经加载过信息,则直接将app显示在桌面上即可;如果没有,则需要先调用函数loadAllApps,具体内容如下:

packages/apps/Launcher3/src/com/android/luancher3/LauncherModel.java :

 private void loadAllApps() {            final Callbacks oldCallbacks = mCallbacks.get();            // Clear the list of apps            mBgAllAppsList.clear();            for (UserHandleCompat user : profiles) {                // Query for the set of apps                //获取所有的app信息,这里最终还是从PackageManagerService获取的应用信息                final List apps = mLauncherApps.getActivityList(null, user);                // Create the ApplicationInfos                for (int i = 0; i < apps.size(); i++) {                    LauncherActivityInfoCompat app = apps.get(i);                    //把每个应用信息封装成AppInfo                    // This builds the icon bitmaps.                    mBgAllAppsList.add(new AppInfo(mContext, app, user, mIconCache));                }            }            //...            // Huh? Shouldn't this be inside the Runnable below?            final ArrayList added = mBgAllAppsList.added;            mBgAllAppsList.added = new ArrayList();            //这里一直运行在Launcher中创建的一个HandlerThread子线程中            //获取了应用信息后,需要通知主线程进行ui更新,mHandler是主线程的Handler            // Post callback on main thread            mHandler.post(new Runnable() {                public void run() {                    //这个callback就是launcher                    final Callbacks callbacks = tryGetCallbacks(oldCallbacks);                    if (callbacks != null) {                       //显示所有应用                        callbacks.bindAllApplications(added);                       //...                    } else {                        //...                    }                }            });            //...        }

mLauncherApps.getActivityList获取app信息的方法是通过向PackageManager发送请求的方式实现的。下面回到Launcher主线程,开始显示应用图标。首先看一眼这个回调函数:

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

   /**     * Add the icons for all apps.     *     * Implementation of the method from LauncherModel.Callbacks.     */    public void bindAllApplications(final ArrayList apps) {        //...        if (mAppsView != null) {            //mAppsView管理着所有应用的view            mAppsView.setApps(apps);        }        //...    }

mAppsView是一个view的容器,维持了一个AlphabeticalAppsList列表,保存应用的信息。当向其中添加新的应用信息后,会对home上的应用进行更新。当home上的图标被点击后,会触发启动该应用。

更多相关文章

  1. Android源码--开机启动流程学习
  2. 第100章、WebView应用之Javascript调用Android(从零开始学Android
  3. Android(安卓)Camera 使用小结
  4. Android应用程序组件Content Provider的共享数据更新通知机制分
  5. WiFi流程
  6. Android系统架构的简单描述
  7. 通过Android(安卓)Studio3.5.3编译安装App失败,提示安装包异常解
  8. Android应用程序获取ROOT权限的方法
  9. 箭头函数的基础使用

随机推荐

  1. Android(安卓)开发中使用 SQLite 数据库
  2. android menu菜单
  3. AVD(android virtual device)路径设置
  4. 在Android上本机运行的服务器
  5. Android(安卓)全自动js脚本测试 Appium教
  6. 【Android】数据存储之Shared Preference
  7. 用自定义 LayoutManager 实现 Android(安
  8. android与java web交互完成简单的登录和
  9. Android心得3.2--用SAX解析器解析xml文件
  10. Google官方提供的有用的Android范例程序,