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条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS关闭SELinux安全模块
- Eclipse初始化配置,告别卡顿、闪退、编译时间过长
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- CentOS8编译安装MySQL8.0.19
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- SpringBoot2整合Thymeleaf,官方推荐html解决方案
- MySQL数据库在高并发下的优化方案
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果