您现在的位置是:首页 > 文章详情

Android 9.0 Launcher启动详解

日期:2020-03-20点击:573

Launcer作为一个独立的APP,从开始执行到加载完成的整个流程。

Launcher.png

启动核心代码如下:

/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。

原文链接:https://yq.aliyun.com/articles/750912
关注公众号

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。

持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。

转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。

文章评论

共有0条评论来说两句吧...

文章二维码

扫描即可查看该文章

点击排行

推荐阅读

最新文章