我是靠谱客的博主 可靠皮带,这篇文章主要介绍android8.0之SystemUI分析(一),现在分享给大家,希望可以做个参考。

SystemUI是指“系统UI”,SystemUI是以应用程序的形式提供系统UI界面的统一管理方案,它是一个标准的APK。

本文将比较全面的介绍SystemUI的组成,实现,布局以及客制化方案等等。本博文基于android8.0源码进行分析,由于android8.0相比以前的版本SystemUI部分改动是非常大的。

一、SystemUI组成

SystemUI包含的功能非常丰富,组成元素主要包含常见的System Bars,以及ScreenShot截屏、壁纸、最近运行的应用程序等。SystemUI也是各大安卓版本中变化比较大的一个部分。

  • Status Bar
  • Navigation Bar
  • Combined Bar (主要为Tablet设备使用)
  • Notifications
  • LockScreen
  • Recent (最近任务)
  • QuickSettings
  • 等等

二、SystemUI实现

了解了SystemUI后,本文先来大概讲解下StatusBar的实现流程。

1、应用启动相关代码

相关代码主要分为两个部分
1)、Service部分
代码路径:framework/base/services/java/com/android/server
2) 、应用部分
代码路径:framework/base/packages/SystemUI

SystemUI中SystemUIService是整个系统UI比较重要的载体,所以我们的分析将从SystemUIService开始,而SystemUIService是从SystemServer中启动的。关于这部分这里不做多的分析,详见SystemServer.java中的startSystemUi()方法。下面来看一下SystemUIServer中的onCreate()方法。

复制代码
1
2
3
4
5
6
7
8
9
10
/*framework/base/packages/systemui/src/com/android/systemui/SystemUIService.java*/ @Override public void onCreate() { super.onCreate(); ((SystemUIApplication) getApplication()).startServicesIfNeeded(); // For debugging RescueParty if (Build.IS_DEBUGGABLE && SystemProperties.getBoolean("debug.crash_sysui", false)) { throw new RuntimeException(); } }

上面的代码可以看出SystemUIService中实际有效代码只是实例化了一个SystemUIApplication对象,并且调用了startServiceIfNeeded()方法。下面来看SystemUIApplication中的具体实现逻辑。

复制代码
1
2
3
4
public void startServicesIfNeeded() { startServicesIfNeeded(SERVICES); }

其中SERVICES是一组所有用户共用的SystemUI服务,如下:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/** * The classes of the stuff to start. */ private final Class<?>[] SERVICES = new Class[] { Dependency.class, NotificationChannels.class, //通知管理 CommandQueue.CommandQueueStart.class, KeyguardViewMediator.class, //锁屏管理 Recents.class, //近期应用管理,以堆叠栈的形式展现 VolumeUI.class, //用来展示和控制音量的变化:媒体音量、铃声音量和闹钟音量 Divider.class, //分屏管理 SystemBars.class, StorageNotification.class, PowerUI.class, //主要处理和Power相关的事件,比如省电模式切换,电池电量变化和开关屏幕等事件 RingtonePlayer.class, //铃声播放 KeyboardUI.class, PipUI.class, //提供对画中画模式的管理 ShortcutKeyDispatcher.class, // VendorServices.class, GarbageMonitor.Service.class, LatencyTester.class, GlobalActionsComponent.class, RoundedCorners.class, }; /** * The classes of the stuff to start for each user. This is a subset of the services listed * above. */ private final Class<?>[] SERVICES_PER_USER = new Class[] { Dependency.class, NotificationChannels.class, Recents.class };

上面对SystemUI要启动的一系列服务有了个基本的介绍,下面来看SystemUIApplication中是怎么启动这一些列服务的

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
private void startServicesIfNeeded(Class<?>[] services) { ... log.traceBegin("StartServices"); final int N = services.length; //获取要启动的服务列表的长度 for (int i = 0; i < N; i++) { Class<?> cl = services[i]; if (DEBUG) Log.d(TAG, "loading: " + cl); log.traceBegin("StartServices" + cl.getSimpleName()); long ti = System.currentTimeMillis(); try { /* 通过SystemUIFactory来创建相应的单例 */ Object newService = SystemUIFactory.getInstance().createInstance(cl); mServices[i] = (SystemUI) ((newService == null) ? cl.newInstance() : newService); }... mServices[i].mContext = this; mServices[i].mComponents = mComponents; if (DEBUG) Log.d(TAG, "running: " + mServices[i]); mServices[i].start(); //服务启动的地方 log.traceEnd(); // Warn if initialization of component takes too long ti = System.currentTimeMillis() - ti; if (ti > 1000) { Log.w(TAG, "Initialization of " + cl.getName() + " took " + ti + " ms"); } if (mBootCompleted) { mServices[i].onBootCompleted(); } } log .traceEnd(); ... }

上面这段代码首先去除SERVICES数组中的class名,然后分别实例化他们,最后调用start接口统一启动。因此,每一个系统ui元素都必须继承自SystemUI这个抽象类,并且重载其中的start方法。这是一种比较灵活的编程方式,它允许我们在后期对系统UI元素进行轻松的扩展或者删除。

2、SystemBar启动加载

android7.0后的SystemBar的启动加载控制和以前的版本有较大区别,6.0的版本中在SystemUIService中会有hasSystemBar()的一个判断,会对StatusBar或者SystemBar有个取舍,而在7.0和后面的8.0版本中这部分逻辑有了大的调整,下面来看启动的SystemBar服务,SystemBar继承自SystemUI抽象类。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class SystemBars extends SystemUI { ... // in-process fallback implementation, per the product config private SystemUI mStatusBar; ... private void createStatusBarFromConfig() { if (DEBUG) Log.d(TAG, "createStatusBarFromConfig"); final String clsName = mContext.getString(R.string.config_statusBarComponent); if (clsName == null || clsName.length() == 0) { throw andLog("No status bar component configured", null); } Class<?> cls = null; try { cls = mContext.getClassLoader().loadClass(clsName); }... try { mStatusBar = (SystemUI) cls.newInstance(); }... mStatusBar.mContext = mContext; mStatusBar.mComponents = mComponents; mStatusBar.start(); if (DEBUG) Log.d(TAG, "started " + mStatusBar.getClass().getSimpleName()); } ... }

可以看到SystemBar这个服务只是作为了一个中间过程,启动了StatusBar,现在我们开看一下StatusBar的start()方法:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Override public void start() { ... //这里面进行了StatusBar中各个组件的初始化 mBarService = IStatusBarService.Stub.asInterface( ServiceManager.getService(Context.STATUS_BAR_SERVICE)); ... try { /* 经过一系列对象的创建与初始化后,开始向StatusBarService进行注册。这里涉及跨进程操作, 因而传递的参数都是继承自Parcelable的 */ mBarService.registerStatusBar(mCommandQueue, iconSlots, icons, switches, binders, fullscreenStackBounds, dockedStackBounds); } ... createAndAddWindows(); //这里才是真正将Status Bar显示出来的地方 }

这里大家就会有疑问了,既然已经有了StatusBar了,那么这里突然杀出来个StatusBarService,到底是为什么呢?
先来看看StatusBarService,通过Context.STATUS_BAR_SERVICE,直觉告诉我们这个应用程序应该是在SystemServer中。我们可以看看是谁向SystemServer中注册的这个服务,下面来看一下SystemUI中的代码。

复制代码
1
2
3
4
5
6
7
8
9
10
11
if (!disableSystemUI) { traceBeginAndSlog("StartStatusBarManagerService"); try { statusBar = new StatusBarManagerService(context, wm); ServiceManager.addService(Context.STATUS_BAR_SERVICE, statusBar); } catch (Throwable e) { reportWtf("starting StatusBarManagerService", e); //原来StatusBarManagerService这个家伙注册的 } traceEnd(); }

接下来进一步分析StatusBarManagerService的实现,首先来看下其中的registerStatusBar中的代码:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
@Override public void registerStatusBar(IStatusBar bar, List<String> iconSlots, List<StatusBarIcon> iconList, int switches[], List<IBinder> binders, Rect fullscreenStackBounds, Rect dockedStackBounds) { enforceStatusBarService(); Slog.i(TAG, "registerStatusBar bar=" + bar); mBar = bar; try { mBar.asBinder().linkToDeath(new DeathRecipient() { @Override public void binderDied() { mBar = null; notifyBarAttachChanged(); } }, 0); } catch (RemoteException e) { } notifyBarAttachChanged(); synchronized (mIcons) { //复制icon列表 for (String slot : mIcons.keySet()) { iconSlots.add(slot); iconList.add(mIcons.get(slot)); } } synchronized (mLock) { switches[0] = gatherDisableActionsLocked(mCurrentUserId, 1); switches[1] = mSystemUiVisibility; switches[2] = mMenuVisible ? 1 : 0; switches[3] = mImeWindowVis; switches[4] = mImeBackDisposition; switches[5] = mShowImeSwitcher ? 1 : 0; switches[6] = gatherDisableActionsLocked(mCurrentUserId, 2); switches[7] = mFullscreenStackSysUiVisibility; switches[8] = mDockedStackSysUiVisibility; binders.add(mImeToken); fullscreenStackBounds.set(mFullscreenStackBounds); dockedStackBounds.set(mDockedStackBounds); } }

从上面的代码看,registerStatusBar的作用主要是:一、为新启动的SystemUI应用赋予当前系统的真实值(比如有多少需要显示的图标);二、通过成员变量mBar记录IstatusBar对象,它在SystemUI中对应的是CommandQueue。
下面通过自己整理的调用流程图,大家可以参考一下:
这里写图片描述

最后

以上就是可靠皮带最近收集整理的关于android8.0之SystemUI分析(一)的全部内容,更多相关android8内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(59)

评论列表共有 0 条评论

立即
投稿
返回
顶部