前言

转载请声明,转自【https://www.cnblogs.com/andy-songwei/p/11471355.html】,谢谢!

SystemUI是系统启动中第一个用户肉眼可见的应用,其功能包罗万象,比如开机后看到的锁屏界面,充电时充电界面,状态栏,导航栏,多任务栏等,都是与Android手机用户息息相关的功能。所以不止SystemUI开发者,普通的应用开发者也很有必要去了解一下SystemUI。本系列文章会基于Android P和Android Q来介绍SystemUI的各个方面,本篇作为本系列第一篇,主要介绍了SystemUI的启动流程,以及主要功能简介。

本文的主要内容如下:

一、SystemUI简介

SystemUI,顾名思义是系统为用户提供的系统级别的信息显示与交互的一套UI组件,所以其功能包罗万象。比如锁屏、状态栏、底部导航栏、最近使用App列表等,大部分功能相互独立,按需启动,后文会继续列出更多功能。在系统源码中,其位置为:frameworks/base/package/SystemUI。尽管从表现形式上看,SystemUI和普通的Android APP有较大的差别,但其本质和普通APP并没有什么差别,也是以apk的形式存在,如下图所示:

以当前测试机为例,其就预置在系统指定的目录下。也是通过Android的4大组件中的Activity、Service、BroadcastReceiver来接受外界的请求并执行相关的操作,只不过它们所接受的请求主要来自各个系统服务而已。

二、Lambda表达式简介

由于后面有个流程中用到了Lambda表达式,为了后面便于讲解,这里咱们先简单介绍一下它,并简单演示其使用方法,这里不做深入探讨,有兴趣的可以自行研究。

Lambda表达式是一个匿名函数,即没有函数名的函数,是基于数学中的λ演算得名。在java中,从java8开始引入,使用它来设计代码会更加简洁。下面在Android项目中举两个例子来直观感受一下Lambda语法的使用。

以下是一个很常见的设置点击事件的例子,先看看不用Lambda表达式时的情况:

  1. mTextView.setOnClickListener(new View.OnClickListener() {
  2. @Override
  3. public void onClick(View v) {
  4. Log.i("songzheweiwang", "test lambda");
  5. }
  6. });

在采用Lambda表达式后,就是下面这种情况:

  1. mTextView.setOnClickListener(onClickListener -> {
  2. Log.i("songzheweiwang", "test lambda");
  3. });

其中“onClickListener”是随意取的一个字符串,我们取名的时候便于识别就可以了。可见整个代码简洁了很多,阅读起来也非常简单。

另外再看一个更加明显的例子,不使用Lambda表达式时是这样:

  1. Runnable runnable = new Runnable() {
  2. @Override
  3. public void run() {
  4. Log.i("songzheweiwang", "test lambda");
  5. }
  6. };

使用Lambda表达式后,就成了这样:

  1. 1 Runnable runnable2 = () -> Log.i("songzheweiwang", "test lambda");

如上的“->”符号可以读作“go to”。使用Lambda表达式来代替匿名的内部类,确实是非常的方便,但是使用的时候需要注意java的版本号,前面说了,是在java8中才引入的,否则在编译时会报如下的错误:

如上内容参考【Lambda表达式_百度百科

三、SystemUI的启动时机

在【【乘风破浪】Android系统启动篇】中,我介绍过Android系统的大致流程,在第6步中讲到了SystemServer进程的启动。SystemServer进程启动时,会执行下面的代码:

  1. //=========SystemServer.java=========
  2. public static void main(String[] args) {
  3. new SystemServer().run();
  4. }
  5. private void run() {
  6. ......
  7. //创建消息Looper
  8. Looper.prepareMainLooper();
  9. // 加载动态库libandroid_servers.so,初始化native服务
  10. System.loadLibrary("android_servers");
  11. ......
  12. //初始化系统context
  13. createSystemContext();
  14. //创建SystemServiceManager
  15. mSystemServiceManager = new SystemServiceManager(mSystemContext);
  16. ......
  17. //启动引导服务,如AMS等
  18. startBootstrapServices();
  19. //启动核心服务
  20. startCoreServices();
  21. //启动其它服务,如WMS,SystemUI等
  22. startOtherServices();
  23. ....
  24. }

在执行完第18、20行的代码后,会启动引导服务和一些核心服务,如AMS等,然后第22行中就会启动其他服务,其中SystemUI就在其中。

  1. //======SystemServer.java======
  2. private void startOtherServices() {
  3. ......
  4. // We now tell the activity manager it is okay to run third party
  5. // code. It will call back into us once it has gotten to the state
  6. // where third party code can really run (but before it has actually
  7. // started launching the initial applications), for us to complete our
  8. // initialization.
  9. mActivityManagerService.systemReady(() -> {
  10. ......
  11. traceBeginAndSlog("StartSystemUI");
  12. try {
  13. startSystemUi(context, windowManagerF);
  14. } catch (Throwable e) {
  15. reportWtf("starting System UI", e);
  16. }
  17. traceEnd();
  18. ......
  19. }, BOOT_TIMINGS_TRACE_LOG);
  20. ......
  21. }

在第9行中,前面讲过AMS先启动了,mActivityManagerService调用systemReady方法,这里就用到了前面介绍过的Lambda表达式,systemReady方法的源码如下:

  1. public void systemReady(final Runnable goingCallback, BootTimingsTraceLog traceLog) {
  2. ......
  3. if (goingCallback != null) {
  4. goingCallback.run();
  5. }
  6. ......
  7. }

这里参照前面介绍的Lambda表达式的使用方法就容易理解了,实际上就是执行Runnable的回调而已,这里其实就等同于如下代码:

  1. mActivityManagerService.systemReady(new Runnable(){
  2. new Runnable() {
  3. @Override
  4. public void run() {
  5. //Lambda表达式中的回调代码
  6. }
  7. }
  8. },BOOT_TIMINGS_TRACE_LOG);

实际上在Lambda表达式还未引入前,即早期的代码中就是这样写法。

当一切就绪后,回调开始执行,就开始执行第13行的startSystemUI方法了。该方法的源码如下:

  1. static final void startSystemUi(Context context, WindowManagerService windowManager) {
  2. Intent intent = new Intent();
  3. intent.setComponent(new ComponentName("com.android.systemui",
  4. "com.android.systemui.SystemUIService"));
  5. intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
  6. //Slog.d(TAG, "Starting service: " + intent);
  7. context.startServiceAsUser(intent, UserHandle.SYSTEM);
  8. windowManager.onSystemUiStarted();
  9. }

第3、4行中给出了包名和类名,这样就开始启动SystemUI了。从这段代码可以看到,SystemUI是通过Service来启动的,而且是以系统的身份来启动它的。

四、Service启动流程浅析

上节中startSystemUI方法中开始启动SystemUIService,Service的启动流程比较复杂,这里不做详细分析,仅简单介绍一下其中和本节息息相关的关键流程。

上节代码第7行startSystemUI方法的调用者看起来是Context类型的context,Context是一个抽象类,实际执行者其实是ContextImpl。调用流程会通过Binder方式从ContextImpl跳转到AMS中,再通过Binder方式跳转到ActivityThread中的内部类ApplicationThread中的scheduleCreateService方法。在该方法中会发送给Handler H来处理,Handler H的实例化是使用的主线程的Looper,所以其回调方法handleMessage就是在主线程中执行的,此时会在该方法中调用handleCreateService方法,咱们从这个方法开始看。

  1. private void handleCreateService(CreateServiceData data) {
  2. ......
  3. Service service = null;
  4. try {
  5. ......
  6. service = packageInfo.getAppFactory()
  7. .instantiateService(cl, data.info.name, data.intent);
  8. } catch (Exception e) {
  9. ......
  10. }
  11. try {
  12. ......
  13. ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
  14. context.setOuterContext(service);
  15. Application app = packageInfo.makeApplication(false, mInstrumentation);
  16. service.attach(context, this, data.info.name, data.token, app,
  17. ActivityManager.getService());
  18. service.onCreate();
  19. ......
  20. } catch (Exception e) {
  21. ......
  22. }
  23. }

第6行创建了service的实例,第13行创建上下文,第15行创建Application,并在其中执行了Application的onCreate方法,第18行执行了service的onCreate方法。这里进入到第15行的makeApplication方法。下面截取了关键代码:

  1. public Application makeApplication(boolean forceDefaultAppClass,
  2. Instrumentation instrumentation) {
  3. ......
  4. Application app = null;
  5. String appClass = mApplicationInfo.className;
  6. if (forceDefaultAppClass || (appClass == null)) {
  7. appClass = "android.app.Application";
  8. }
  9. try {
  10. ......
  11. ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
  12. app = mActivityThread.mInstrumentation.newApplication(
  13. cl, appClass, appContext);
  14. appContext.setOuterContext(app);
  15. } catch (Exception e) {
  16. ......
  17. }
  18. mActivityThread.mAllApplications.add(app);
  19. ......
  20. if (instrumentation != null) {
  21. try {
  22. instrumentation.callApplicationOnCreate(app);
  23. } catch (Exception e) {
  24. ......
  25. }
  26. }
  27. ......
  28. return app;
  29. }

因为是初始启动,所以会走到第7行。第12行的newApplication源码如下:

  1. public Application newApplication(ClassLoader cl, String className, Context context)
  2. throws InstantiationException, IllegalAccessException,
  3. ClassNotFoundException {
  4. Application app = getFactory(context.getPackageName())
  5. .instantiateApplication(cl, className);
  6. app.attach(context);
  7. return app;
  8. }

继续追踪instantiateApplication方法:

  1. public @NonNull Application instantiateApplication(@NonNull ClassLoader cl,
  2. @NonNull String className)
  3. throws InstantiationException, IllegalAccessException, ClassNotFoundException {
  4. return (Application) cl.loadClass(className).newInstance();
  5. }

这里就通过类加载器的形式创建了Application的实例。可见前面的makeApplication方法第12行的作用就是创建Application实例了,然后走到该方法的第22行,进入该方法:

  1. public void callApplicationOnCreate(Application app) {
  2. app.onCreate();
  3. }

该方法中Application执行了onCreate方法。

到这里service的大致启动流程就明了了,这里咱们需要记住一个执行顺序(因为我看过不少资料容易在这里犯错,说是Application会比Service先实例化,通过这个流程我们可以看到这种说法是错误的,所以这里着重提出来):

(1)实例Service;

(2)实例Application;

(3)Application实例执行onCreate方法;

(4)Service实例执行onCrate方法。

五、SystemUIApplication中onCreate方法处理逻辑

上一节我们分析了,会先执行Application的onCreate方法,在执行Service的onCreate方法,这里先分析SystemUIApplication中onCreate方法的执行逻辑。

  1. //============SystemUIApplication.java========
  2. private SystemUI[] mServices;
  3. @Override
  4. public void onCreate() {
  5. super.onCreate();
  6. ......
  7. //设置主题
  8. setTheme(R.style.Theme_SystemUI);
  9. ......
  10. if (Process.myUserHandle().equals(UserHandle.SYSTEM)) {
  11. IntentFilter bootCompletedFilter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
  12. bootCompletedFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
  13. registerReceiver(new BroadcastReceiver() {
  14. @Override
  15. public void onReceive(Context context, Intent intent) {
  16. if (mBootCompleted) return;
  17.  
  18. if (DEBUG) Log.v(TAG, "BOOT_COMPLETED received");
  19. unregisterReceiver(this);
  20. mBootCompleted = true;
  21. if (mServicesStarted) {
  22. final int N = mServices.length;
  23. for (int i = 0; i < N; i++) {
  24. mServices[i].onBootCompleted();
  25. }
  26. }
  27. }
  28. }, bootCompletedFilter);
  29.  
  30. IntentFilter localeChangedFilter = new IntentFilter(Intent.ACTION_LOCALE_CHANGED);
  31. registerReceiver(new BroadcastReceiver() {
  32. @Override
  33. public void onReceive(Context context, Intent intent) {
  34. if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
  35. if (!mBootCompleted) return;
  36. // Update names of SystemUi notification channels
  37. NotificationChannels.createAll(context);
  38. }
  39. }
  40. }, localeChangedFilter);
  41. } else {
  42. ......
  43. startSecondaryUserServicesIfNeeded();
  44. }
  45. }

这里说一下第9行的if-else逻辑,我们知道Linux是多用户操作系统,所以这个if-else语句就是判断是系统用户,还是切换到了其它用户。SystemUI大多数功能对所有用户都是一样的,只有少部分功能会因为不同的用户而表现不一样,比如通知、多任务功能等,这里后面会再讲到。如果是系统用户就会走if中的流程,这里注册了两个广播接收器,用于监听Intent.ACTION_BOOT_COMPLETED和Intent.ACTION_LOCALE_CHANGED。

Intent.ACTION_BOOT_COMPLETED是监听开机启动,这里分析的Android9.0的系统源码,当前系统中使用的是FBE加密方式(读者请自行查阅FBE加密方式,这里不做详细介绍),这种方式下,要等到系统启动并锁屏界面解锁后,在进入到桌面过程中,系统才会发送发送该广播,所以接收该广播的处理逻辑会比较延后。通过第15行和第18行可以看到,该广播只会处理一次,就会反注册该广播,以后就不会再接收了。在这个逻辑当中,第20行到第25行,判断mServicesStarted变量,该变量表示SystemUIService是否已经启动了,实际上由于该广播接收的时机比较延后,会在SystemUIService启动完后才接收到该广播,所以这里面的代码会在此时执行。第23行的mService[]数组存储的是SystemUI的子服务,当整个系统启动完成后,这里面的每个子服务都会执行onBootCompleted()方法,让各个子服务知道系统启动完成了,要做自己该做的事情了。mService[]的赋值以及它存储的SytemUI子服务,下一节会详细讲解,这里我们只需要知道,这个过程发生在SystemUIService的启动阶段即可。

Intent.ACTION_LOCALE_CHANGED广播是用于监听设备当前区域设置已更改时发出的广播,简单来说就是修改语言时发出的广播(暂时不知道其它动作是否也会发送该广播)。

第42行就是在当前用户不是系统用户时的情况,即切换用户后的场景,该动作发生时系统是已经启动了的,不会再触发Intent.ACTION_BOOT_COMPLETED广播。这里看一看它的执行过程:

  1. void startSecondaryUserServicesIfNeeded() {
  2. String[] names =
  3. getResources().getStringArray(R.array.config_systemUIServiceComponentsPerUser);
  4. startServicesIfNeeded(names);
  5. }

第2行和第4行其实就是启动资源文件指定的功能,如下所示:

  1. <string-array name="config_systemUIServiceComponentsPerUser" translatable="false">
  2. <item>com.android.systemui.Dependency</item>
  3. <item>com.android.systemui.util.NotificationChannels</item>
  4. <item>com.android.systemui.recents.Recents</item>
  5. </string-array>

可以看到包含了通知(第3行)和多任务(第4行),这几个功能会因用户不同而异,第2行是什么功能暂时不清楚,读者可以自己查阅。另外我们会发现,实际上这几个子服务,在下一节的 config_systemUIServiceComponents数组资源中也都是包含的,也就正好对应了前面说的,切换到个人用户后这几个功能会因用户不同而表现不同,需要重新加载一次。startSecondaryUserServicesIfNeeded方法的处理逻辑,在下一节会详细讲到,这里咱们只需要清楚这一块的功能即可。

六、SystemUIService中onCreate方法处理逻辑

如前文所述,SystemUI通过“com.android.systemui.SystemUIService”这个服务来启动,在Application的onCreate方法执行完后,就会执行自己的onCreate方法。下面看看SystemUIService启动过程中做了哪些工作:

  1. public class SystemUIService extends Service {
  2. @Override
  3. public void onCreate() {
  4. super.onCreate();
  5. ((SystemUIApplication) getApplication()).startServicesIfNeeded();
  6. ......
  7. }
  8. ......
  9. }

该类中关键代码是第5行代码,其它的没有什么重要逻辑,继续追踪startServicesIfNeeded()方法:

  1. //===========SystemUIApplication==========
  2. public void startServicesIfNeeded() {
  3. String[] names = getResources().getStringArray(R.array.config_systemUIServiceComponents);
  4. startServicesIfNeeded(names);
  5. }

第3行在资源文件中对应的数组如下所示,每一项都对应了一个子服务(这里并不是表示它们是Service,而是指某项功能模块),实际上在Android O及以前的版本中,这些类都是以数组的形式保存在代码中的。

  1. <string-array name="config_systemUIServiceComponents" translatable="false">
  2. <item>com.android.systemui.Dependency</item>
  3. <item>com.android.systemui.util.NotificationChannels</item>
  4. <item>com.android.systemui.statusbar.CommandQueue$CommandQueueStart</item>
  5. <item>com.android.systemui.keyguard.KeyguardViewMediator</item>
  6. <item>com.android.systemui.recents.Recents</item>
  7. <item>com.android.systemui.volume.VolumeUI</item>
  8. <item>com.android.systemui.stackdivider.Divider</item>
  9. <item>com.android.systemui.SystemBars</item>
  10. <item>com.android.systemui.usb.StorageNotification</item>
  11. <item>com.android.systemui.power.PowerUI</item>
  12. <item>com.android.systemui.media.RingtonePlayer</item>
  13. <item>com.android.systemui.keyboard.KeyboardUI</item>
  14. <item>com.android.systemui.pip.PipUI</item>
  15. <item>com.android.systemui.shortcut.ShortcutKeyDispatcher</item>
  16. <item>@string/config_systemUIVendorServiceComponent</item>
  17. <item>com.android.systemui.util.leak.GarbageMonitor$Service</item>
  18. <item>com.android.systemui.LatencyTester</item>
  19. <item>com.android.systemui.globalactions.GlobalActionsComponent</item>
  20. <item>com.android.systemui.ScreenDecorations</item>
  21. <item>com.android.systemui.fingerprint.FingerprintDialogImpl</item>
  22. <item>com.android.systemui.SliceBroadcastRelayHandler</item>
  23. </string-array>

在Android Q上将第21行修改为了

  1. <item>com.android.systemui.biometrics.BiometricDialogImpl</item>

就是将指纹识别功能改成了生物识别功能,在Android Q上开始,除了指纹识别外,还增加了人脸识别。在原来的基础上另外再添加了3条:

  1. <item>com.android.systemui.SizeCompatModeActivityController</item>
  2. <item>com.android.systemui.statusbar.notification.InstantAppNotifier</item>
  3. <item>com.android.systemui.theme.ThemeOverlayController</item>

打开这每一个类后,会发现它们都继承自SystemUI类,SystemUI类是一个抽象类,提供了如下接口:

  1. public abstract class SystemUI implements SysUiServiceProvider {
  2. ......
  3. public abstract void start();
  4.  
  5. protected void onConfigurationChanged(Configuration newConfig) {
  6. }
  7.  
  8. public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
  9. }
  10.  
  11. protected void onBootCompleted() {
  12. }
  13. ......
  14. }
  15. }

startServicesIfNeeded(names)方法源码如下:

  1. private SystemUI[] mServices;
  2. private void startServicesIfNeeded(String[] services) {
  3. ......
  4. mServices = new SystemUI[services.length];
  5. ......
  6. final int N = services.length;
  7. for (int i = 0; i < N; i++) {
  8. String clsName = services[i];
  9. Class cls;
  10. try {
  11. cls = Class.forName(clsName);
  12. mServices[i] = (SystemUI) cls.newInstance();
  13. } catch (ClassNotFoundException ex) {
  14. throw new RuntimeException(ex);
  15. } catch (IllegalAccessException ex) {
  16. throw new RuntimeException(ex);
  17. } catch (InstantiationException ex) {
  18. throw new RuntimeException(ex);
  19. }
  20. ......
  21. mServices[i].mContext = this;
  22. mServices[i].mComponents = mComponents;
  23. ......
  24. mServices[i].start();
  25. ......
  26. if (mBootCompleted) {
  27. mServices[i].onBootCompleted();
  28. }
  29. }
  30. }

实际上就是通过反射的方式将前面的各个子服务类实例化,并执行这些对象中的start()方法,来启动这些服务。这样整个SystemUI就算启动了,上述逻辑还是比较简单的。

我们需要注意的是,这里使用了模板模式。SystemUI是一个基类,其中定义了4个抽象或空方法,作为模板指定了子类的行为模式。资源文件中定义的众多子服务类都是SystemUI的子类,既然都继承自SystemUI类,那么这些子类就有一些共同的行为模式,在某些阶段应该有什么表现,只是具体如何表现因不同子类而异。比如说,在上述代码中第24行和27行分别规定了SystemUI子类们在启动时要执行start()方法,系统启动后要执行onBootCompleted()方法,所以在这些子类中都重写了这两个方法,到一定的阶段都会以回调的方式执行,但是具体要在这些方法中干什么,子类们自己说了算。这就是典型的模板模式使用,至于具体介绍和使用模板模式,这里不展开讲,读者可以自行查资料,该模式在Android系统中使用还是很常见的,读者最好能好好掌握。

到这里为止,SystemUI的启动流程就介绍完了,这里归纳起来就是执行了如下几个阶段:

(1)系统启动就绪后,SystemServer进程下达启动SystemUIService的命令;

(2)SystemUI的SystemUiApplication中执行onCreate方法,注册系统启动广播和区域设置更改广播。

(3)SystemUI的SystemUIService中执行onCreate方法,启动公共用户的各项服务,各子服务执行onStart()回调方法。

(4)系统启动后,第二步注册的广播会接收到系统启动广播,然后各个子服务执行onBootCompleted()回调方法。

(5)在切换都个人用户时,再次加载因人而异的子服务功能。

七、SystemUI包含的功能模块

上一节中通过数组的形式列出了SystemUI的子服务类,这些类都分别表示什么功能呢?下面我简单介绍其中几项,读者可以根据名称来对号入座。至于更详细的介绍,有需要的话会专门写一篇文章来做介绍。

(1)Status bars(状态栏)

(2)Navigation bars(导航栏)

(3)Notification(通知)

(4)Keyguard(锁屏)

(5)Quick settings(快速设置)

(6)Recent task panel(最近任务面板)

(7)VolumeUI(音量UI)

(8)Screenshot(截屏)

(9)PowerUI(电量UI)

(10)RingtonePlayer(铃声播放器)

(11)StackDivider(分屏)

(12)PipUI(画中画UI)

(13)Biometrics(生物识别解锁功能,如指纹解锁、人脸解锁、虹膜解锁等)

结语

SystemUI的启动流程就介绍到这里,由于讲得还算比较详细,所以涉及的内容及细节不少,一定会有些描述不准确或者不妥的地方,如果发现,请读者不吝赐教。另外由于篇幅有限,有些地方还是仅提到或者简单介绍而已,比如FBE加密,模板模式,Lambda表达式等,在平时系统开发中都会经常碰到,读者都可以继续拓展深入学习。

【系统解读】SystemUI篇(一)SystemUI启动流程的更多相关文章

  1. linux开机启动流程及需要开机启动服务讲解和修改及防火墙

    linux系统从开机到登陆的启动流程. 1.开机BIOS自检 2.MBR引导 3.grub引导菜单 4.加载内核kernel 5.启动init进程 6.读取inittab文件,执行rc.sysinit ...

  2. 渣渣菜鸡的 ElasticSearch 源码解析 —— 启动流程(上)

    关注我 转载请务必注明原创地址为:http://www.54tianzhisheng.cn/2018/08/11/es-code02/ 前提 上篇文章写了 ElasticSearch 源码解析 -- ...

  3. 菜鸟nginx源代码剖析 框架篇(一) 从main函数看nginx启动流程

    菜鸟nginx源代码剖析 框架篇(一) 从main函数看nginx启动流程 Author:Echo Chen(陈斌) Email:chenb19870707@gmail.com Blog:Blog.c ...

  4. “无处不在” 的系统核心服务 —— ActivityManagerService 启动流程解析

    本文基于 Android 9.0 , 代码仓库地址 : android_9.0.0_r45 系列文章目录: Java 世界的盘古和女娲 -- Zygote Zygote 家的大儿子 -- System ...

  5. Android系统之LK启动流程分析(一)

    1.前言 LK是Little Kernel的缩写,在Qualcomm平台的Android系统中普遍采用LK作为bootloader,它是一个开源项目,LK是整个系统的引导部分,所以不是独立存在的,但是 ...

  6. Spring源码解析 | 第二篇:Spring IOC容器之XmlBeanFactory启动流程分析和源码解析

    一. 前言 Spring容器主要分为两类BeanFactory和ApplicationContext,后者是基于前者的功能扩展,也就是一个基础容器和一个高级容器的区别.本篇就以BeanFactory基 ...

  7. Linux系统的启动流程以及做个小小的Linux

    内核的作用     进程管理:进程间切换     内存管理:内存空间分割为内核空间和用户空间     IO管理:对底层硬件的使用必须由内来实现,不能由用户空间进程来实现     文件系统管理     ...

  8. 插件占坑,四大组件动态注册前奏(二) 系统Service的启动流程

    转载请注明出处:http://blog.csdn.net/hejjunlin/article/details/52203903 前言:为什么要了解系统Activity,Service,BroadCas ...

  9. Android系统开机启动流程及init进程浅析

    Android系统启动概述 Android系统开机流程基于Linux系统,总体可分为三个阶段: Boot Loader引导程序启动Linux内核启动Android系统启动,Launcher/app启动 ...

随机推荐

  1. tp3 的前端内置标签

    Volist 标签 volist标签通常用于查询数据集(select 方法),对于查询出来的结果数组进行遍历输出. 首先赋值: $User = M("User"); $list = ...

  2. Jmeter CSV config使用

    1.添加线程组,自己给线程组命名 2.添加CSV data set config 如上,filename是文件的名字 新增.txt文件,将变量写在文件中,完成后,更名为.csv:变量之间用逗号隔开(第 ...

  3. Nginx搭建详细

    Linux 安装Nginx搭建详细内容 进入:/usr/java/nginx位置下载nginx: wget et http://nginx.org/download/nginx-1.8.0.tar.g ...

  4. isMemberOfClass、isKindOfClass原理分析

    isMemberOfClass - 调用者必须是传入的类的实例对象才返回YES- 判断调用者是否是传入对象的实例,别弄反了,如 [s1 isMemberOfClass:p1] ,意思是s1是否是p1的 ...

  5. PHP编码风格规范

    由于PHP的灵活性,很多人写起代码来也不讲求一个好的代码规范,使得本就灵活的PHP代码看起来很乱,其实PSR规范中的PSR-1和PSR-2已经定义了在PHP编码中的一些规范,只要我们好好遵守这些规范, ...

  6. EditText 使用详解

    极力推荐文章:欢迎收藏 Android 干货分享 本篇文章主要介绍 Android 开发中的部分知识点,通过阅读本篇文章,您将收获以下内容: 一.EditText 继承关系 二.EditText 常用 ...

  7. 字符串(String、StringBuffer、StringBuilder)进阶分析

    转载自https://segmentfault.com/a/1190000002683782 我们先要记住三者的特征: String 字符串常量 StringBuffer 字符串变量(线程安全) St ...

  8. hashCode和equals的区别

    关注公众号,大家可以在公众号后台回复“博客园”,免费获得作者 Java 知识体系/面试必看资料. 有面试官会问:你重写过 hashcode 和 equals 么,为什么重写equals时必须重写has ...

  9. 【TCP/IP】ICMP协议

    ICMP协议有两种报文: 1,查询报文 2,差错报文

  10. Netty学习(九)-Netty编解码技术之Marshalling

    前面我们讲过protobuf的使用,主流的编解码框架其实还有很多种: ①JBoss的Marshalling包 ②google的Protobuf ③基于Protobuf的Kyro ④Apache的Thr ...