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大师取乐,给后来者抛砖引玉,别再背后骂我就谢天谢地了。
- android Launcher那点事儿
- android Launcher那点事儿(二)
- Android那点事儿
- android activity那点事儿
- android 摇一摇那点事儿
- android Binder那点事儿
- android Surface 那点事儿
- android PackageInstaller那点事儿
- android PackageInstaller那点事儿
- Android内存那点事儿
- android权限那点事儿
- android那点事儿 开篇寄语
- android 锁屏那点事儿
- android 悬浮窗那点事儿
- 关于Android WebView的那点事儿..
- Android 封装Json数据那点事儿
- 关于android传感器的那点事儿
- 聊聊 Android ANR 那点事儿
- 字符串转换整数
- Oracle 11gOCP 053 v12.02 1--300题疑问答案更正
- Servlet的生命周期
- 守护进程
- C# 实现将一个文本文档按行数分成多个文档
- android Launcher那点事儿
- 深入linux内核架构-学习笔记一
- android 混淆文件project.properties和proguard-project.txt
- VivaldiSimulator仿真参数说明
- 关于win7下的ARM的程序烧录
- csdn英雄会(pongo)题解之回文数
- Spring mvc+hibernate+freemarker(开源项目)
- Java2D (WeatherWizard)
- ffmpeg简介