Android(安卓)9.0 Launcher启动详解
16lz
2021-01-24
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 workspaceItems = new ArrayList<>(); ArrayList appWidgets = new ArrayList<>(); final ArrayList 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 currentWorkspaceItems = new ArrayList<>(); ArrayList otherWorkspaceItems = new ArrayList<>(); ArrayList currentAppWidgets = new ArrayList<>(); ArrayList 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处理。
更多相关文章
- 【Android学习系列】android Content Provider 应用步骤
- Android(安卓)intent数据传递
- android百度地图(二)之定位
- Android中的数据库——SQLite
- 解决 pinyin4j 在Android(安卓)某些编译环境下不能用
- Sqlite3 增删改查操作实例
- Android(安卓)ListView实现通讯录的例子
- Android学习笔记_31_通过后台代码生成View对象以及动态加载XML布
- Android(安卓)MediaPlayer播放prepareAsync called in state 8解