Android 9.0 Launcher启动详解
Launcer作为一个独立的APP,从开始执行到加载完成的整个流程。
启动核心代码如下:
/packages/apps/Launcher3/src/com/android/launcher3/Launcher.java
@Override protected void onCreate(Bundle savedInstanceState) { Log.d(TAG,"onCreate ======="); .... mModel = app.setLauncher(this); initDeviceProfile(app.getInvariantDeviceProfile()); mSharedPrefs = Utilities.getPrefs(this); mIconCache = app.getIconCache(); mAccessibilityDelegate = new LauncherAccessibilityDelegate(this); mDragController = new DragController(this); mAllAppsController = new AllAppsTransitionController(this); mStateManager = new LauncherStateManager(this); UiFactory.onCreate(this); mAppWidgetManager = AppWidgetManagerCompat.getInstance(this); mAppWidgetHost = new LauncherAppWidgetHost(this); mAppWidgetHost.startListening(); mLauncherView = LayoutInflater.from(this).inflate(R.layout.launcher, null); ... setupViews(); ... int currentScreen = PagedView.INVALID_RESTORE_PAGE; if (savedInstanceState != null) { currentScreen = savedInstanceState.getInt(RUNTIME_STATE_CURRENT_SCREEN, currentScreen); } Log.e(TAG,"currentScreen :"+currentScreen+","+", loader bind: "+mModel.startLoader(currentScreen)+", internalStateHandled: "+internalStateHandled); if (!mModel.startLoader(currentScreen)) { if (!internalStateHandled) { // If we are not binding synchronously, show a fade in animation when // the first page bind completes. mDragLayer.getAlphaProperty(ALPHA_INDEX_LAUNCHER_LOAD).setValue(0); } } else { // Pages bound synchronously. mWorkspace.setCurrentPage(currentScreen); setWorkspaceLoading(true); } ... }
其中,setupViews,查找所有的view,并配置,
private void setupViews() { ... // default state, otherwise we will update to the wrong offsets in RTL mWorkspace.lockWallpaperToDefaultPage(); mWorkspace.bindAndInitFirstWorkspaceScreen(null /* recycled qsb */); mDragController.addDragListener(mWorkspace); // Get the search/delete/uninstall bar mDropTargetBar = mDragLayer.findViewById(R.id.drop_target_bar); // Setup Apps mAppsView = findViewById(R.id.apps_view); // Setup the drag controller (drop targets have to be added in reverse order in priority) mDragController.setMoveTarget(mWorkspace); mDropTargetBar.setup(mDragController); mAllAppsController.setupViews(mAppsView); }
1、packages/apps/Launcher3/src/com/android/launcher3/LauncherAppState.java
LauncherModel setLauncher(Launcher launcher) { getLocalProvider(mContext).setLauncherProviderChangeListener(launcher); mModel.initialize(launcher); return mModel; }
2、/packages/apps/Launcher3/src/com/android/launcher3/LauncherModel.java
其中 Launcer 实现了 Callbacks 接口,
public void initialize(Callbacks callbacks) { synchronized (mLock) { Preconditions.assertUIThread(); mCallbacks = new WeakReference<>(callbacks); } }
3、/packages/apps/Launcher3/src/com/android/launcher3/Launcher.java
initDeviceProfile(app.getInvariantDeviceProfile());
4、/packages/apps/Launcher3/src/com/android/launcher3/LauncherAppWidgetHost.java
@Override public void startListening() { ... try { super.startListening(); } catch (Exception e) { if (!Utilities.isBinderSizeError(e)) { throw new RuntimeException(e); } // We're willing to let this slide. The exception is being caused by the list of // RemoteViews which is being passed back. The startListening relationship will // have been established by this point, and we will end up populating the // widgets upon bind anyway. See issue 14255011 for more context. } // We go in reverse order and inflate any deferred widget for (int i = mViews.size() - 1; i >= 0; i--) { LauncherAppWidgetHostView view = mViews.valueAt(i); if (view instanceof DeferredAppWidgetHostView) { view.reInflate(); } } }
5-6、 /packages/apps/Launcher3/src/com/android/launcher3/Launcher.java
private void setupViews() { ... mWorkspace = mDragLayer.findViewById(R.id.workspace); mWorkspace.initParentViews(mDragLayer); mOverviewPanel = findViewById(R.id.overview_panel); mOverviewPanelContainer = findViewById(R.id.overview_panel_container); mHotseat = findViewById(R.id.hotseat); mHotseatSearchBox = findViewById(R.id.search_container_hotseat); ... mWorkspace.setup(mDragController); // Until the workspace is bound, ensure that we keep the wallpaper offset locked to the // default state, otherwise we will update to the wrong offsets in RTL mWorkspace.lockWallpaperToDefaultPage(); mWorkspace.bindAndInitFirstWorkspaceScreen(null /* recycled qsb */); ... }
7-8、/packages/apps/Launcher3/src/com/android/launcher3/LauncherModel.java
public boolean startLoader(int synchronousBindPage) { // Enable queue before starting loader. It will get disabled in Launcher#finishBindingItems InstallShortcutReceiver.enableInstallQueue(InstallShortcutReceiver.FLAG_LOADER_RUNNING); 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 (mModelLoaded && !mIsLoaderTaskRunning) { // Divide the set of loaded items into those that we are binding synchronously, // and everything else that is to be bound normally (asynchronously). loaderResults.bindWorkspace(); // For now, continue posting the binding of AllApps as there are other // issues that arise from that. loaderResults.bindAllApps(); loaderResults.bindDeepShortcuts(); loaderResults.bindWidgets(); return true; } else { startLoaderForResults(loaderResults); } } } return false; } public void startLoaderForResults(LoaderResults results) { synchronized (mLock) { stopLoader(); mLoaderTask = new LoaderTask(mApp, mBgAllAppsList, sBgDataModel, results); runOnWorkerThread(mLoaderTask); } }
9-14 /packages/apps/Launcher3/src/com/android/launcher3/model/LoaderTask.java
... TraceHelper.beginSection(TAG); try (LauncherModel.LoaderTransaction transaction = mApp.getModel().beginLoader(this)) { TraceHelper.partitionSection(TAG, "step 1.1: loading workspace"); loadWorkspace(); verifyNotStopped(); TraceHelper.partitionSection(TAG, "step 1.2: bind workspace workspace"); mResults.bindWorkspace(); // Notify the installer packages of packages with active installs on the first screen. TraceHelper.partitionSection(TAG, "step 1.3: send first screen broadcast"); sendFirstScreenActiveInstallsBroadcast(); // Take a break TraceHelper.partitionSection(TAG, "step 1 completed, wait for idle"); waitForIdle(); verifyNotStopped(); // second step TraceHelper.partitionSection(TAG, "step 2.1: loading all apps"); loadAllApps(); TraceHelper.partitionSection(TAG, "step 2.2: Binding all apps"); verifyNotStopped(); mResults.bindAllApps(); verifyNotStopped(); TraceHelper.partitionSection(TAG, "step 2.3: Update icon cache"); updateIconCache(); // Take a break TraceHelper.partitionSection(TAG, "step 2 completed, wait for idle"); waitForIdle(); verifyNotStopped(); // third step /home/meng/apinext_workspace TraceHelper.partitionSection(TAG, "step 3.1: loading deep shortcuts"); loadDeepShortcuts(); verifyNotStopped(); TraceHelper.partitionSection(TAG, "step 3.2: bind deep shortcuts"); mResults.bindDeepShortcuts(); // Take a break TraceHelper.partitionSection(TAG, "step 3 completed, wait for idle"); waitForIdle(); verifyNotStopped(); // fourth step TraceHelper.partitionSection(TAG, "step 4.1: loading widgets"); mBgDataModel.widgetsModel.update(mApp, null); verifyNotStopped(); TraceHelper.partitionSection(TAG, "step 4.2: Binding widgets"); mResults.bindWidgets(); transaction.commit(); } catch (CancellationException e) { // Loader stopped, ignore TraceHelper.partitionSection(TAG, "Cancelled"); } TraceHelper.endSection(TAG); ...
加载完成,会跳转到LoaderResults,进行绑定操作,
通过接口Callbacks 回调,返回Launcher。
public void bindWorkspace() { Runnable r; Callbacks callbacks = mCallbacks.get(); // Don't use these two variables in any of the callback runnables. // Otherwise we hold a reference to them. if (callbacks == null) { // This launcher has exited and nobody bothered to tell us. Just bail. Log.w(TAG, "LoaderTask running with no launcher"); return; } // Save a copy of all the bg-thread collections ArrayList<ItemInfo> workspaceItems = new ArrayList<>(); ArrayList<LauncherAppWidgetInfo> appWidgets = new ArrayList<>(); final ArrayList<Long> orderedScreenIds = new ArrayList<>(); synchronized (mBgDataModel) { workspaceItems.addAll(mBgDataModel.workspaceItems); appWidgets.addAll(mBgDataModel.appWidgets); orderedScreenIds.addAll(mBgDataModel.workspaceScreens); mBgDataModel.lastBindId++; } final int currentScreen; { int currScreen = mPageToBindFirst != PagedView.INVALID_RESTORE_PAGE ? mPageToBindFirst : callbacks.getCurrentWorkspaceScreen(); if (currScreen >= orderedScreenIds.size()) { // There may be no workspace screens (just hotseat items and an empty page). currScreen = PagedView.INVALID_RESTORE_PAGE; } currentScreen = currScreen; } final boolean validFirstPage = currentScreen >= 0; final long currentScreenId = validFirstPage ? orderedScreenIds.get(currentScreen) : INVALID_SCREEN_ID; // Separate the items that are on the current screen, and all the other remaining items ArrayList<ItemInfo> currentWorkspaceItems = new ArrayList<>(); ArrayList<ItemInfo> otherWorkspaceItems = new ArrayList<>(); ArrayList<LauncherAppWidgetInfo> currentAppWidgets = new ArrayList<>(); ArrayList<LauncherAppWidgetInfo> otherAppWidgets = new ArrayList<>(); filterCurrentWorkspaceItems(currentScreenId, workspaceItems, currentWorkspaceItems, otherWorkspaceItems); filterCurrentWorkspaceItems(currentScreenId, appWidgets, currentAppWidgets, otherAppWidgets); sortWorkspaceItemsSpatially(currentWorkspaceItems); sortWorkspaceItemsSpatially(otherWorkspaceItems); // Tell the workspace that we're about to start binding items r = new Runnable() { public void run() { Callbacks callbacks = mCallbacks.get(); if (callbacks != null) { callbacks.clearPendingBinds(); callbacks.startBinding(); } } }; mUiExecutor.execute(r); // Bind workspace screens mUiExecutor.execute(new Runnable() { @Override public void run() { Callbacks callbacks = mCallbacks.get(); if (callbacks != null) { callbacks.bindScreens(orderedScreenIds); } } }); Executor mainExecutor = mUiExecutor; // Load items on the current page. bindWorkspaceItems(currentWorkspaceItems, currentAppWidgets, mainExecutor); // In case of validFirstPage, only bind the first screen, and defer binding the // remaining screens after first onDraw (and an optional the fade animation whichever // happens later). // This ensures that the first screen is immediately visible (eg. during rotation) // In case of !validFirstPage, bind all pages one after other. final Executor deferredExecutor = validFirstPage ? new ViewOnDrawExecutor() : mainExecutor; mainExecutor.execute(new Runnable() { @Override public void run() { Callbacks callbacks = mCallbacks.get(); if (callbacks != null) { callbacks.finishFirstPageBind( validFirstPage ? (ViewOnDrawExecutor) deferredExecutor : null); } } }); bindWorkspaceItems(otherWorkspaceItems, otherAppWidgets, deferredExecutor); // Tell the workspace that we're done binding items r = new Runnable() { public void run() { Callbacks callbacks = mCallbacks.get(); if (callbacks != null) { callbacks.finishBindingItems(); } } }; deferredExecutor.execute(r); if (validFirstPage) { r = new Runnable() { public void run() { Callbacks callbacks = mCallbacks.get(); if (callbacks != null) { // We are loading synchronously, which means, some of the pages will be // bound after first draw. Inform the callbacks that page binding is // not complete, and schedule the remaining pages. if (currentScreen != PagedView.INVALID_RESTORE_PAGE) { callbacks.onPageBoundSynchronously(currentScreen); } callbacks.executeOnNextDraw((ViewOnDrawExecutor) deferredExecutor); } } }; mUiExecutor.execute(r); } }
11.2、bindAllApplications
13.2、bindDeepShortcuts
14.2、bindWidgets
处理逻辑类似,在此就不贴代码了。
有点不同是是loading widgets,图中的14.1、update(mApp, null)。
加载逻辑在这个文件,
/packages/apps/Launcher3/src/com/android/launcher3/model/WidgetsModel.java。
加载完成后,执行 transaction.commit()
在/packages/apps/Launcher3/src/com/android/launcher3/LauncherModel.jav
public void commit() { synchronized (mLock) { // Everything loaded bind the data. mModelLoaded = true; } }
然后,Launcher将数据赋值给各种View。
总结:
启动Launcher后,通过LauncherModel控制加载逻辑,LoaderTask开启线程加载数据,LoaderResults进行数据绑定的处理,最后将数据返回值Launcher。
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
SpringCloud微服务:Sentinel哨兵组件,管理服务限流和降级
一、基本简介 1、概念描述 Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。包括核心的独立类库,监控台,丰富的使用场景验证。(这似乎是阿里开源组件的一贯作风,极其有特点,且特点很规律) 基本特性图: 补刀一句:这种图很多人可能不在意,但是一般官方给这个图就是该中间件的基本使用思路,与核心功能点。 2、基础性概念 资源管理 资源是Sentinel组件中的核心概念之一。应用服务器上脚本,静态页面,API接口,文件图片等都可以理解为资源,对于Java开发者而言,API接口就是这里资源的概念。 规则配置 Sentinel组件通过流控规则的配置,来指定允许该资源(API接口)通过的请求次数,IP黑白名单,应用服务等。 测试效果 QPS:每秒查询率,是一台服务器每秒能够处理的查询次数。 TPS:每秒处理事务数,事务处理整体倾向于整个过程。 二、框架环境整合 这里的环境主要整合Nacos注册中心,Feign服务,Sentinel哨兵,和Sentinel控制台。 1、基本依赖 这里的依赖需要参考官方文档,不同的环境使用不同的依赖,这里主要适配Spring...
- 下一篇
Java多线程并发05——那么多的锁你都了解了吗
Java多线程并发05——那么多的锁你都了解了吗在多线程或高并发情境中,经常会为了保证数据一致性,而引入锁机制,本文将为各位带来有关锁的基本概念讲解。关注我的公众号「Java面典」了解更多 Java 相关知识点。 根据锁的各种特性,可将锁分为以下几类: 乐观锁/悲观锁独享锁(互斥锁)/共享锁(读写锁)可重入锁公平锁/非公平锁分段锁偏向锁/轻量级锁/重量级锁自旋锁1|0乐观锁/悲观锁 乐观锁与悲观锁并不是特指某两种类型的锁,是人们定义出来的概念或思想,主要是指看待并发同步的角度。 1|1乐观锁 前提:认为读多写少,遇到并发写的可能性低,每次去拿数据的时候都认为别人不会修改,所以不会上锁; 实现:在更新的时候会判断一下在此期间别人有没有去更新这个数据,采取在写时先读出当前版本号,然后加锁操作(比较跟上一次的版本号,如果一样则更新),如果失败则要重复读-比较-写的操作。 应用:在 Java 中 java.util.concurrent.atomic 包下面的原子变量类就是使用了乐观锁的一种实现方式CAS(Compare and Swap 【比较并交换】)实现的。CAS 是一种更新的原子操作,...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS8编译安装MySQL8.0.19
- Windows10,CentOS7,CentOS8安装Nodejs环境
- CentOS7编译安装Cmake3.16.3,解决mysql等软件编译问题
- Eclipse初始化配置,告别卡顿、闪退、编译时间过长
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- SpringBoot2整合Thymeleaf,官方推荐html解决方案
- SpringBoot2整合Redis,开启缓存,提高访问速度
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- CentOS7,8上快速安装Gitea,搭建Git服务器
- Docker安装Oracle12C,快速搭建Oracle学习环境