android Launcher那点事儿

来源:互联网 发布:手机淘宝我要代理入口 编辑:程序博客网 时间:2024/05/16 19:48

    今天讲关于Launcher的事情,但讲之前我想先说说我自己。

    首先说一下学东西,以前我很害怕别人问我问题,因为我怕自己不会,回答不上来那多丢人啊,但现在我不这么想了,因为别人问你问题的时候也会想,我问这个问是不是很傻比啊,问一个傻逼的问题多丢人啊,其实大家心里都一样,都有一种恐惧心里,恐惧是什么,恐惧是来自对未知事物的不了解,当了解了一个事物,就不会感到害怕与恐慌。所以现在自己敢去面对以前总是逃避的问题,也敢对别人说“不知道”,知之为知之,不知为不知嘛,进而自己得出这么个结论,学习某个东西的时候是靠一个人的能力,学会了就是熟能生巧的问题了。不知道没什么可丢人,也没什么可恐慌的。

    接下来再给大家说说给别人讲东西,给人讲解东西有三种方法,一种是从为什么讲起,一种是从做什么讲起,一种是从怎么做讲起,我是第二种人,我这人喜欢从做什么讲起,不喜欢打哑谜,也就是直白,难听点就是二流子,就是一听他讲就觉着这人没水平,为什么我喜欢从做什么讲起呢?因为我觉着只有自己明白要做什么才能更有信心去做,明白了做什么,就会不自主的问自己我该怎么做?开始试探着做了才会问自己,我为什么要这么做?我觉着这才是顺利成章的事情。而喜欢从为什么讲起的人都是北斗型的人物,有能力,能控制场面,知识渊博,至于这种人有什么优点,有什么缺点,我就不讲解了。而喜欢从怎么做讲起的人那都是你的老师,三人行必有我“师”嘛,致敬吧。

    最后再说说我为什么要这么写android,当我遇到不会的问题,首先想到的就是去网上查阅一些资料,但是后来我发现网上对android的解析都是很深刻的纯技术剖析,读起来让人感觉相当的乏味,还不如自己琢磨,不知道大家是不是这个感觉,反正我刚学习android的时就是这感觉,对于某些文章都读不下去了,所以我写这些文章的时候不想这样,我觉着android所使用的java语言,当然也包括其他编程语言,他们都是一种语言,像汉语,英语等等一样,是一种可以交流的东西,应该是学起来很有趣的东西,我不喜欢写出的东西让别看后就一个感觉“虽然不知道在写什么,但是感觉很牛逼的样子”,这就失去了写作的很大的意义,更甚着,不是读很牛逼的文章就能衬托出自己很牛逼的样子。所以像我这种脑子不够灵活,嘴又笨的人都喜欢读《明朝那些事儿》不喜欢去读枯燥的历史教课书,因为我能力有限,只想做自己能做的事,写自己能写的东西,读自己能读懂的文章。

    言归正传,接下来我们学习Launcher,Launcher是什么?Launcher对于android来说就是一张脸,脸长的咋样,很可能决定一个人长的咋样,有人就会反驳了,说你这不是以貌取人吗?还有现在社会谁还看脸,都看身材的,对于第一个问题我的回答是,这不是以貌取人,这是以貌取机,对于第二个问题我的回答是别人身材再好也就她家老公知道,你能看见的也就是脸。靠,扯的有的远了。我们接着说Launcher,提起Launcher我们还是要从SystemServer说起,上一篇我们已经说过这个类是做什么的,这一篇就不再赘述,由于代码太多,我们就捡重点说,首先在systemReady中我们不难找到这么一句话

 context = ActivityManagerService.main(factoryTest);

通过上一篇中的名字分析法,我们很容易知道ActivityManagerService就是管理活动的服务,我们还可以猜测main是ActivityManagerService主函数,是用来做一些初始化工作的,那我们这样猜测对吗?我们还是进去看看

    public static final Context main(int factoryTest) {        AThread thr = new AThread();        thr.start();        synchronized (thr) {            while (thr.mService == null) {                try {                    thr.wait();                } catch (InterruptedException e) {                }            }        }        ActivityManagerService m = thr.mService;        mSelf = m;        ActivityThread at = ActivityThread.systemMain();        mSystemThread = at;        Context context = at.getSystemContext();        context.setTheme(android.R.style.Theme_Holo);        m.mContext = context;        m.mFactoryTest = factoryTest;        m.mMainStack = new ActivityStack(m, context, true);                m.mBatteryStatsService.publish(context);        m.mUsageStatsService.publish(context);                synchronized (thr) {            thr.mReady = true;            thr.notifyAll();        }        m.startRunning(null, null, null, null);                return context;    }


首先启动了一个线程AThread,线程里面做了什么事情

    static class AThread extends Thread {        ActivityManagerService mService;        boolean mReady = false;        public AThread() {            super("ActivityManager");        }        public void run() {            Looper.prepare();            android.os.Process.setThreadPriority(                    android.os.Process.THREAD_PRIORITY_FOREGROUND);            android.os.Process.setCanSelfBackground(false);            ActivityManagerService m = new ActivityManagerService();            synchronized (this) {                mService = m;                notifyAll();            }            synchronized (this) {                while (!mReady) {                    try {                        wait();                    } catch (InterruptedException e) {                    }                }            }            // For debug builds, log event loop stalls to dropbox for analysis.            if (StrictMode.conditionallyEnableDebugLogging()) {                Slog.i(TAG, "Enabled StrictMode logging for AThread's Looper");            }            Looper.loop();        }    }

不难看出new了一个ActivityManagerService对象给了mService,然后就一直wait()等待mReady为true

    我们继续main(),启动AThread线程之后也是一直wait()等待thr.mService不为空,直到thr.mService不为空也就是刚才我们在AThread中new完ActivityManagerService对象,又去做了几件大事,我们捡重点的说,一个把刚才new的ActivityManagerService对象给了mSelf,然后有分别new了ActivityThread、Context、ActivityStack等这些对象,这几个我们应该都不陌生具体是做什么的,以后有机会再给大家分析。做完这些之后把mReady赋值为true,正是我们刚才AThread中所要的。这些都是很精致的设计,这里不做分析。接着是m.startRunning(null, null, null, null);startRunning传进去四个空值,我们进去看看

        public final void startRunning(String pkg, String cls, String action,            String data) {        synchronized(this) {            if (mStartRunning) {                return;            }            mStartRunning = true;            mTopComponent = pkg != null && cls != null                    ? new ComponentName(pkg, cls) : null;            mTopAction = action != null ? action : Intent.ACTION_MAIN;            mTopData = data;            if (!mSystemReady) {                return;            }        }        systemReady(null);    }


其它的不做分析,我们只看mTopAction和mTopComponent,前面我们说了,这里传进来四个空值,所以这里的mTopAction=Intent.ACTION_MAIN,mTopComponent很明显为空了,为什么我们这里只说这两个,因为我们后面会用到。

    然后还会到main()最终返回了Context。这样我们就又回到了SystemServer。就对ActivityManagerService有做了一下这些事情

ActivityManagerService.setSystemProcess();
ActivityManagerService.installSystemProviders();
ActivityManagerService.self().setWindowManager(wm);
ActivityManagerService.self().enterSafeMode();
ActivityManagerService.self().showSafeModeOverlay();

这些都是做什么的我们简单说一下就是托付一些Service给ServiceManager,安装系统Providers,把上一章提到的WindowManagerService对象赋值给ActivityManagerService里面的对象,再接着做了一些安全设置,等等吧。

    最终到了ActivityManagerService.self().systemReady,就是告诉ActivityManagerService我们systemReady,你该做什么做什么的吧。systemReady的参数是一个Runnable,而在Runnable的run方法中是去启动一些第三方东西。这样可以保证我们是按一定顺序启动,不然一些东西没有附着体,或者温床,是不能存活的。这些我们都先不管,只管去看systemReady中的其它实质性内容,在这里面做了一大堆的初始化问题,最终到了

mMainStack.resumeTopActivityLocked(null);

这个mMainStack是什么呢?就是我们刚才在main()中提到的ActivityStack,我们接着进去看看

    final boolean resumeTopActivityLocked(ActivityRecord prev) {        // Find the first activity that is not finishing.        ActivityRecord next = topRunningActivityLocked(null);        // Remember how we'll process this pause/resume situation, and ensure        // that the state is reset however we wind up proceeding.        final boolean userLeaving = mUserLeaving;        mUserLeaving = false;        if (next == null) {            // There are no more activities!  Let's just start up the            // Launcher...            if (mMainStack) {                return mService.startHomeActivityLocked();            }        }

进去之后我们会发现里面又是一堆代码,我们只取我们关心的,其它的不做分析,我们可以看到首先去获取最顶层的一个ActivityRecord,而ActivityRecord是什么呢?简单说就是在创建每个Activity的同时都会创建一个ActivityRecord,我认为ActivityRecord相当于Activity的一个备份。当然了从手机启动到现在我们都没有创建过Activity,所以这里的next一定为空了,所以接下来走那里不用我说了mMainStack现在应该是true,为什么呢?因为我们刚才在main()中去new了一个ActivityStack,而new这个ActivityStack对象的时候我们已经把mMainStack赋值为true了,所以接下来就是mService.startHomeActivityLocked();里了,这时我们又回到了ActivityManagerService中,在startHomeActivityLocked做了什么,我们就只截取我们想要的代码

        if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL                && mTopAction == null) {            // We are running in factory test mode, but unable to find            // the factory test app, so just sit around displaying the            // error message and don't try to start anything.            return false;        }        Intent intent = new Intent(            mTopAction,            mTopData != null ? Uri.parse(mTopData) : null);        intent.setComponent(mTopComponent);        if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {            intent.addCategory(Intent.CATEGORY_HOME);        }        ActivityInfo aInfo =            intent.resolveActivityInfo(mContext.getPackageManager(),                    STOCK_PM_FLAGS);        if (aInfo != null) {            intent.setComponent(new ComponentName(                    aInfo.applicationInfo.packageName, aInfo.name));            // Don't do this if the home app is currently being            // instrumented.            ProcessRecord app = getProcessRecordLocked(aInfo.processName,                    aInfo.applicationInfo.uid);            if (app == null || app.instrumentationClass == null) {                intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);                mMainStack.startActivityLocked(null, intent, null, null, 0, aInfo,                        null, null, 0, 0, 0, false, false, null);            }        }


这里很明显了,去启动了一个activity,而这个activity的intent的action就是我们上面提到的mTopAction,也就是Intent.ACTION_MAIN,而intent的Category是Intent.CATEGORY_HOME,为什么一定会加Category呢?因为上面已经做了判断了,所以去启动这么个activity,而又这两个性质的activity,是什么呢?就是我们的Launcher。到此我们就进入了Launcher,至于是如何启动activity,activity的生命流程为什么是那样子,我们以后会有机会分析的,我们现在就进入Launcher中去看看吧,在Launcher的onCreate中先做了一些初始化工作,这些都不在提了,我们直奔主题

mModel.startLoader(this, true);

我们进去看看

mLoaderTask = new LoaderTask(context, isLaunching);

去启动了一个线程,我们直奔线程的run方法

                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();                }


很明显走了两个方法loadAndBindAllApps();和loadAndBindWorkspace();这两个做了一个顺序调用,loadAndBindWorkspace();这个我们不多做解释,我们只看loadAndBindAllApps();就是加载apps的过程

        private void loadAndBindAllApps() {            if (DEBUG_LOADERS) {                Log.d(TAG, "loadAndBindAllApps mAllAppsLoaded=" + mAllAppsLoaded);            }            if (!mAllAppsLoaded) {            loadAllAppsFromPersistence();                loadAllAppsByBatch();                synchronized (LoaderTask.this) {                    if (mStopped) {                        return;                    }                    mAllAppsLoaded = true;                }            } else {                onlyBindAllApps();            }        }

loadAllAppsFromPersistence();是从数据库加载apps,可能有的代码没有这个,这个的好处是什么呢?可以加速Launcher的启动,不做分析。我们只看loadAllAppsByBatch();这里代码又是一堆我们截取片段

            final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);            mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);            final PackageManager packageManager = mContext.getPackageManager();            List<ResolveInfo> apps = null;            int N = Integer.MAX_VALUE;            int startIndex;            int i=0;            int batchSize = -1;            while (i < N && !mStopped) {                if (i == 0) {                    mAllAppsList.clear();                    final long qiaTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;                    apps = packageManager.queryIntentActivities(mainIntent, 0);


这个代码不难解读,大致意思就是去获取手机中已安装应用中activity的action为Intent.ACTION_MAIN,Category为Intent.CATEGORY_LAUNCHER的那些信息给apps至于怎么添加的,自行研究,跟代码看,可以知道最终这些信息都给了mAllAppsList,给大家提到这里有什么好处呢?我们可以说说,在接下来的代码中,一、我们可以过滤我们不想让在launcher中显示的应用,二、这地方可以去更改应用在launcher中显示的图标,名字。这些都不再说,接下来我们看

                final Callbacks callbacks = tryGetCallbacks(oldCallbacks);                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) {                        isNeedSave = true;                            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");                        }                    }                });

接着就是又起了一个线程如加载这些应用了,怎么加载的呢?就是拷贝来拷贝去。不再赘述了。再说下去头又要大了,该收手时就收手吧,以后想听在往下分析吧。

    还是那些话,这些文章给android大师取乐,给后来者抛砖引玉,别再背后骂我就谢天谢地了。

0 0
原创粉丝点击