前言
在前面3篇文章
- Android15 Framework(1):用户空间第一个进程 Init 解析
- Android15 Framework(2):应用进程的孵化器 Zygote 进程解析
- Android15 Framework(3):系统服务进程 SystemServer 解析
我们看了Init、Zygote、SystemServer进程,本文是Android 15 Framework解析系列的第四篇,一起来看看 Launcher吧。
注意:本文出现的源码基于Android - 15.0.0_r1。另外本文关注主要逻辑,省略部分代码。
一、 Android系统启动流程
本文是介绍Launcher,照例先看下Android系统启动流程:
启动电源及系统启动 -> Bootloader -> Linux内核启动 -> Init -> Zygote -> SystemServer -> Launcher
二、Launcher
本文将从Launcher启动流程、页面加载、点击事件介绍Launcher。
先说说Launcher是什么?Launcher是由Android系统的一个桌面应用,它用来显示安装好的应用,比如电话,短信...。它的源码位置是在packages/apps/Launcher3。
那么首先看看Launcher启动流程吧
2.1 Launcher启动流程
Launcher是SystemServer启动的,就从SystemServer#run方法开始看
// SystemServer#run
private void run() {
...
// 启动服务
try {
t.traceBegin("StartServices");
// 引导服务,如AMS,DMS
startBootstrapServices(t);
// 核心服务,如BatteryService
startCoreServices(t);
// 其他服务,如WMS, IMS,这里还会启动 Launcher
startOtherServices(t);
...
} catch (Throwable ex) {
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting system services", ex);
throw ex;
} finally {
t.traceEnd(); // StartServices
}
...
}
private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
...
// 调用 AMS#systemReady
mActivityManagerService.systemReady(() -> {
...
})
...
}
// AMS#systemReady
public void systemReady(final Runnable goingCallback, @NonNull TimingsTraceAndSlog t) {
...
synchronized (this) {
...
// 当前启动的用户是否是 系统用户 (user 0)
boolean isBootingSystemUser = currentUserId == UserHandle.USER_SYSTEM;
// 是系统用户 且 不是 Headless System User 模式 (普通 Android 手机正常启动)
if (isBootingSystemUser && !UserManager.isHeadlessSystemUserMode()) {
t.traceBegin("startHomeOnAllDisplays");
// 启动Launcher,调用 LocalServices#startHomeOnAllDisplays
// ATMS 构造方法构造 LocalServices 对象,start 将此对象存入 LocalServices
// AMS 构造方法会获取此对象,即LocalServices对象
mAtmInternal.startHomeOnAllDisplays(currentUserId, "systemReady");
t.traceEnd();
}
...
}
}
// ATMS的构造方法
public ActivityTaskManagerService(Context context) {
...
mInternal = new LocalService();
...
}
// ATMS#start
private void start() {
LocalServices.addService(ActivityTaskManagerInternal.class, mInternal);
}
// AMS的构造方法
public ActivityManagerService(Context systemContext, ActivityTaskManagerService atm) {
...
mAtmInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
...
}
// LocalService定义在ATMS类中
final class LocalService extends ActivityTaskManagerInternal {
...
@Override
public boolean startHomeOnAllDisplays(int userId, String reason) {
synchronized (mGlobalLock) {
// 调用 RootWindowContainer#startHomeOnAllDisplays
return mRootWindowContainer.startHomeOnAllDisplays(userId, reason);
}
}
...
}
// RootWindowContainer#startHomeOnAllDisplays
boolean startHomeOnAllDisplays(int userId, String reason) {
boolean homeStarted = false;
for (int i = getChildCount() - 1; i >= 0; i--) {
final int displayId = getChildAt(i).mDisplayId;
homeStarted |= startHomeOnDisplay(userId, reason, displayId);
}
return homeStarted;
}
boolean startHomeOnDisplay(int userId, String reason, int displayId) {
return startHomeOnDisplay(userId, reason, displayId, false /* allowInstrumenting */,
false /* fromHomeKey */);
}
boolean startHomeOnDisplay(int userId, String reason, int displayId, boolean allowInstrumenting,
boolean fromHomeKey) {
// Fallback to top focused display or default display if the displayId is invalid.
if (displayId == INVALID_DISPLAY) {
final Task rootTask = getTopDisplayFocusedRootTask();
displayId = rootTask != null ? rootTask.getDisplayId() : DEFAULT_DISPLAY;
}
final DisplayContent display = getDisplayContent(displayId);
// reduceOnAllTaskDisplayAreas兼容单/多屏, startHomeOnTaskDisplayArea启动Launcher
return display.reduceOnAllTaskDisplayAreas((taskDisplayArea, result) ->
result | startHomeOnTaskDisplayArea(userId, reason, taskDisplayArea,
allowInstrumenting, fromHomeKey),
false /* initValue */);
}
boolean startHomeOnTaskDisplayArea(int userId, String reason, TaskDisplayArea taskDisplayArea,
boolean allowInstrumenting, boolean fromHomeKey) {
...
Intent homeIntent = null;
ActivityInfo aInfo = null;
// 主屏 (默认显示屏 / 单屏设备) 执行 if 分支
if (taskDisplayArea == getDefaultTaskDisplayArea()
|| mWmService.shouldPlacePrimaryHomeOnDisplay(
taskDisplayArea.getDisplayId(), userId)) {
// 获取启动 Launcher 的Intent:action是Intent.ACTION_MAIN,category是Intent.CATEGORY_HOME
homeIntent = mService.getHomeIntent();
// 获取Launcher 的ActivityInfo
// 通过调用 PMS#resolveIntent 去获取 ResolveInfo,它的activityInfo属性就是ActivityInfo
aInfo = resolveHomeActivity(userId, homeIntent);
} else if (shouldPlaceSecondaryHomeOnDisplayArea(taskDisplayArea)) {
...
}
...
// 设置 Component, 即packageName 和 acitivityInfo.name
homeIntent.setComponent(new ComponentName(aInfo.applicationInfo.packageName, aInfo.name));
// 设置 flags 为 _NEW_TASK
homeIntent.setFlags(homeIntent.getFlags() | FLAG_ACTIVITY_NEW_TASK);
...
// 添加额外信息
homeIntent.putExtra(WindowManagerPolicy.EXTRA_START_REASON, reason);
// Update the reason for ANR debugging to verify if the user activity is the one that
// actually launched.
final String myReason = reason + ":" + userId + ":" + UserHandle.getUserId(
aInfo.applicationInfo.uid) + ":" + taskDisplayArea.getDisplayId();
// 调用 ActivityStartController#startHomeActivity
mService.getActivityStartController().startHomeActivity(homeIntent, aInfo, myReason,
taskDisplayArea);
return true;
}
// ActivityStartController#startHomeActivity
void startHomeActivity(Intent intent, ActivityInfo aInfo, String reason,
TaskDisplayArea taskDisplayArea) {
...
// 先调用了各种setter, 最后调用 ActivityStarter#execute 去开启Launcher
mLastHomeActivityStartResult = obtainStarter(intent, "startHomeActivity: " + reason)
.setOutActivity(tmpOutRecord)
.setCallingUid(0)
.setActivityInfo(aInfo)
.setActivityOptions(options.toBundle())
.execute();
mLastHomeActivityStartRecord = tmpOutRecord[0];
// Launcher是否已经开启了
if (rootHomeTask.mInResumeTopActivity) {
// 已经开启,将 Launcher 拉到栈顶
mSupervisor.scheduleResumeTopActivities();
}
}
至此,我们已经分析了Launcher启动的触发时机和前期流程。从 ActivityStarter#execute 开始,Launcher的启动便进入了标准的应用冷启动流程,这包括进程创建、应用初始化、Activity生命周期等阶段。冷启动流程,我将在后续的启动速度优化文章中详细解析。
2.2 Launcher界面加载
看完了Launcher启动流程,我们继续看Launcher界面加载。既然Launcher是一个应用,那么它也会执行生命周期函数,我们就从它的 onCreate 开始看
// Launcher#onCreate
protected void onCreate(Bundle savedInstanceState) {
...
if (!mModel.addCallbacksAndLoad(this)) {
if (!internalStateHandled) {
// If we are not binding synchronously, pause drawing until initial bind complete,
// so that the system could continue to show the device loading prompt
mOnInitialBindListener = Boolean.FALSE::booleanValue;
}
}
...
}
// LauncherModel#addCallbacksAndLoad
public boolean addCallbacksAndLoad(@NonNull final Callbacks callbacks) {
synchronized (mLock) {
// 这里往 addCallbacksAndLoad 添加了 callbacks
addCallbacks(callbacks);
// 调用 startLoader 加载页面
return startLoader(new Callbacks[] { callbacks });
}
}
// 参数中的 callbacks 是 Launcher 自己
public void addCallbacks(@NonNull final Callbacks callbacks) {
Preconditions.assertUIThread();
synchronized (mCallbacksList) {
mCallbacksList.add(callbacks);
}
}
public boolean startLoader() {
return startLoader(new Callbacks[0]);
}
private boolean startLoader(@NonNull final Callbacks[] newCallbacks) {
// Enable queue before starting loader. It will get disabled in Launcher#finishBindingItems
ItemInstallQueue.INSTANCE.get(mApp.getContext())
.pauseModelPush(ItemInstallQueue.FLAG_LOADER_RUNNING);
synchronized (mLock) {
// 是否有LoaderTask正在运行:首次执行时, 没有Task运行, 返回false
boolean wasRunning = stopLoader();
// 是否已经加载过并且Task正在执行:首次执行,mModelLoaded 和 mIsLoaderTaskRunning 均为false
boolean bindDirectly = mModelLoaded && !mIsLoaderTaskRunning;
// bindDirectly 为 false,所以bindAllCallbacks 为 true
boolean bindAllCallbacks = wasRunning || !bindDirectly || newCallbacks.length == 0;
// 在 addCallbacksAndLoad 中调用了 addCallbacks,getCallbacks不会返回空
final Callbacks[] callbacksList = bindAllCallbacks ? getCallbacks() : newCallbacks;
// 这里的 callbacksList 里面只有 Launcher 自己
BaseLauncherBinder launcherBinder = new BaseLauncherBinder(
mApp, mBgDataModel, mBgAllAppsList, callbacksList);
// 不返回空,执行此处
if (callbacksList.length > 0) {
...
// bindDirectly 为 false, 不执行if分支
if (bindDirectly) {
...
return true;
} else {
stopLoader();
// 构造 LoaderTask 对象, 且 LoaderTask 实现了 Runnable 接口
mLoaderTask = new LoaderTask(
mApp, mBgAllAppsList, mBgDataModel, mModelDelegate, launcherBinder);
// MODEL_EXECUTOR 其实是一个Handler
MODEL_EXECUTOR.post(mLoaderTask);
}
}
}
return false;
}
public Callbacks[] getCallbacks() {
synchronized (mCallbacksList) {
return mCallbacksList.toArray(new Callbacks[mCallbacksList.size()]);
}
}
// Executors.MODEL_EXECUTOR
public static final LooperExecutor MODEL_EXECUTOR =
new LooperExecutor(createAndStartNewLooper("launcher-loader"));
// LooperExecutor的构造方法
public LooperExecutor(Looper looper) {
mHandler = new Handler(looper);
}
public Handler getHandler() {
return mHandler;
}
public void post(Runnable runnable) {
getHandler().post(runnable);
}
// LoaderTask的构造方法
LoaderTask(@NonNull LauncherAppState app, AllAppsList bgAllAppsList, BgDataModel bgModel,
ModelDelegate modelDelegate, @NonNull BaseLauncherBinder launcherBinder,
UserManagerState userManagerState) {
...
// mApp.getContext()是返回了 Context 对象,而 Context 的实现类是 ContextImp
mLauncherApps = mApp.getContext().getSystemService(LauncherApps.class);
...
}
// ContextImp#getSystemService
public Object getSystemService(String name) {
...
return SystemServiceRegistry.getSystemService(this, name);
}
// SystemServiceRegistry
public final class SystemServiceRegistry {
public static boolean sEnableServiceNotFoundWtf = false;
...
// SystemServer#run 调用了 SystemServiceRegistry.sEnableServiceNotFoundWtf = true, 会执行此静态块
static {
...
registerService(Context.LAUNCHER_APPS_SERVICE, LauncherApps.class,
new CachedServiceFetcher<LauncherApps>() {
@Override
public LauncherApps createService(ContextImpl ctx) {
return new LauncherApps(ctx);
}});
...
}
private static <T> void registerService(@NonNull String serviceName,
@NonNull Class<T> serviceClass, @NonNull ServiceFetcher<T> serviceFetcher) {
SYSTEM_SERVICE_NAMES.put(serviceClass, serviceName);
SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher);
SYSTEM_SERVICE_CLASS_NAMES.put(serviceName, serviceClass.getSimpleName());
}
public static Object getSystemService(@NonNull ContextImpl ctx, String name) {
// 先获取到 ServiceFetcher
final ServiceFetcher<?> fetcher = getSystemServiceFetcher(name);
if (fetcher == null) {
return null;
}
// 再调用 ServiceFetcher.getService
final Object ret = fetcher.getService(ctx);
...
return ret;
}
private static ServiceFetcher<?> getSystemServiceFetcher(String name) {
if (name == null) {
return null;
}
final ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
if (fetcher == null) {
if (sEnableServiceNotFoundWtf) {
Slog.wtf(TAG, "Unknown manager requested: " + name);
}
return null;
}
return fetcher;
}
...
}
// CachedServiceFetcher
public final T getService(ContextImpl ctx) {
...
// 这个 createService 就是 registerService 传的最后一个参数里重写方法
// LauncherApps 这里就是调用了构造方法 return new LauncherApps(ctx);
service = createService(ctx);
ret = service;
...
return ret;
}
// LauncherApps
public LauncherApps(Context context, ILauncherApps service) {
mContext = context;
mService = service;
mPm = context.getPackageManager();
mUserManager = context.getSystemService(UserManager.class);
}
public LauncherApps(Context context) {
// LauncherApps 中的 mService 其实是 LauncherAppsService BinderProxy
this(context, ILauncherApps.Stub.asInterface(
ServiceManager.getService(Context.LAUNCHER_APPS_SERVICE)));
}
首先SystemServer#run 调用了 SystemServiceRegistry.sEnableServiceNotFoundWtf = true, 从而调用了 SystemServiceRegistry的 静态块, 静态块去调用了 registerService(Context.LAUNCHER_APPS_SERVICE, LauncherApps.class...), 将 CachedServiceFetcher<LauncherApps> 对象,放到了SYSTEM_SERVICE_FETCHERS中。
后续执行 LauncherModel#startLoader方法,调用了 LoaderTask的构造方法,它里面调用了 mLauncherApps = mApp.getContext().getSystemService(LauncherApps.class), 跑到了ContentImp#getSystemService, 继续调用 SystemServiceRegistry#getSystemService,而在此方法中,先通过 getSystemServiceFetcher方法从 SYSTEM_SERVICE_FETCHERS 中将 CachedServiceFetcher<LauncherApps> 对象 取了出来, 然后再调用了 CachedServiceFetcher#getService, 在这个 getService 里面调用了 LauncherApps, 进一步就调用到了 LauncherApps的构造方法, 构造方法中去赋值了 LauncherApps 的成员变量 mService 为 LauncherAppsService BinderProxy。
这里稍稍有一点绕,其实就是先往 SYSTEM_SERVICE_FETCHERS 中塞东西,后面去拿出来,最终就调用到了 LauncherApps的构造方法里面。之所以要解释这么多,是因为后续调用涉及到 LauncherApps 里的 mService。
看完了LoadTask 的构造方法,我们看看MODEL_EXECUTOR.post。
在 Launcher#onCreate 中,通过调用 addCallbacksAndLoad 方法,执行了 MODEL_EXECUTOR.post(mLoaderTask), 而 MODEL_EXECUTOR 是 LooperExecutor对象,在它里面有一个 Handler对象成员变成,而MODEL_EXECUTOR#post其实就是调用了 LooperExecutor 里的 Handler 对象的 post。因此我们后续就去看 LoaderTask#run方法
// LoaderTask#run
public void run() {
...
try (LauncherModel.LoaderTransaction transaction = mApp.getModel().beginLoader(this)) {
List<ShortcutInfo> allShortcuts = new ArrayList<>();
// 加载工作区
loadWorkspace(allShortcuts, "", memoryLogger, restoreEventLogger);
...
verifyNotStopped();
// 绑定工作区
mLauncherBinder.bindWorkspace(true /* incrementBindId */, /* isBindSync= */ false);
...
try {
// 加载所有的apps,重点看apps相关,其余感兴趣的可以自己看下
allActivityList = loadAllApps();
} finally {
Trace.endSection();
}
...
// 绑定所有的apps
mLauncherBinder.bindAllApps();
// 还会加载快捷方式、小部件等增强功能
...
} catch (CancellationException e) {
// Loader stopped, ignore
logASplit("Cancelled");
} catch (Exception e) {
memoryLogger.printLogs();
throw e;
}
TraceHelper.INSTANCE.endSection();
}
private List<LauncherActivityInfo> loadAllApps() {
final List<UserHandle> profiles = mUserCache.getUserProfiles();
...
for (UserHandle user : profiles) {
// 获取所有的app信息,
// mLauncherApps初始化是在
final List<LauncherActivityInfo> apps = mLauncherApps.getActivityList(null, user);
...
allActivityList.addAll(apps);
}
...
return allActivityList;
}
// LauncherApp#getActivityList
public List<LauncherActivityInfo> getActivityList(String packageName, UserHandle user) {
logErrorForInvalidProfileAccess(user);
try {
// mService 就是上面说的 LauncherAppsService BinderProxy。
// 这里 Binder 通信,我们直接去 Server 端看看做了什么
return convertToActivityList(mService.getLauncherActivities(mContext.getPackageName(),
packageName, user), user);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
}
// 涉及 Binder 通信,因为数据可能较大,所以使用了 ParceledListSlice
// client 使用此方法 将其转换为普通的 List
private List<LauncherActivityInfo> convertToActivityList(
@Nullable ParceledListSlice<LauncherActivityInfoInternal> internals, UserHandle user) {
if (internals == null || internals.getList().isEmpty()) {
return Collections.EMPTY_LIST;
}
ArrayList<LauncherActivityInfo> lais = new ArrayList<>();
for (LauncherActivityInfoInternal internal : internals.getList()) {
LauncherActivityInfo lai = new LauncherActivityInfo(mContext, internal);
if (DEBUG) {
Log.v(TAG, "Returning activity for profile " + user + " : "
+ lai.getComponentName());
}
lais.add(lai);
}
return lais;
}
// LauncherAppsService
public ParceledListSlice<LauncherActivityInfoInternal> getLauncherActivities(
String callingPackage, @Nullable String packageName, UserHandle user)
throws RemoteException {
...
try {
...
// 调用 PMS BinderProxy 去获取所有安装的应用和信息
final List<ApplicationInfo> installedPackages =
mPackageManagerInternal.getInstalledApplications(
/* flags= */ 0, user.getIdentifier(), callingUid);
for (ApplicationInfo applicationInfo : installedPackages) {
if (!visiblePackages.contains(applicationInfo.packageName)) {
if (!shouldShowSyntheticActivity(user, applicationInfo)) {
continue;
}
LauncherActivityInfoInternal info =
getHiddenAppActivityInfo(
applicationInfo.packageName, callingUid, user);
if (info != null) {
result.add(info);
}
}
}
return new ParceledListSlice<>(result);
} finally {
injectRestoreCallingIdentity(ident);
}
}
后续就是调用 PMS 去获取所有安装的应用信息,这里就先不跟了,本文毕竟是讲 Launcher, 等后续写 PMS 文章时,再来填这个坑吧。
现在我们拿到安装的应用信息,后面就去绑定所有的apps
// BaseLauncherBinder#bindAllApps
public void bindAllApps() {
// shallow copy
AppInfo[] apps = mBgAllAppsList.copyData();
int flags = mBgAllAppsList.getFlags();
Map<PackageUserKey, Integer> packageUserKeytoUidMap = Arrays.stream(apps).collect(
Collectors.toMap(
appInfo -> new PackageUserKey(appInfo.componentName.getPackageName(),
appInfo.user), appInfo -> appInfo.uid, (a, b) -> a));
// mUiExecutor = MAIN_EXECUTOR, 就是 new LooperExecutor(Looper.getMainLooper())
executeCallbacksTask(c -> c.bindAllApplications(apps, flags, packageUserKeytoUidMap),
mUiExecutor);
}
protected void executeCallbacksTask(CallbackTask task, Executor executor) {
// 把绑定apps的操作放到主线程中
executor.execute(() -> {
if (mMyBindingId != mBgDataModel.lastBindId) {
Log.d(TAG, "Too many consecutive reloads, skipping obsolete data-bind");
return;
}
// mCallbacksList 当前只有 Launcher 本身,也就跑到了 Launcher#bindAllApplications
// mCallbacksList 赋值在构造方法,构造方法则是在 LauncherModel#startLoader中调用的
for (Callbacks cb : mCallbacksList) {
task.execute(cb);
}
});
}
// Launcher#bindAllApplications
public void bindAllApplications(AppInfo[] apps, int flags,
Map<PackageUserKey, Integer> packageUserKeytoUidMap) {
mModelCallbacks.bindAllApplications(apps, flags, packageUserKeytoUidMap);
...
}
// ModelCallbacks#bindAllApplications
override fun bindAllApplications(
apps: Array<AppInfo>,
flags: Int,
packageUserKeytoUidMap: Map<PackageUserKey, Int>,
) {
Preconditions.assertUIThread()
val hadWorkApps = launcher.appsView.shouldShowTabs()
// setApps方法会更新应用列表数据,调用notifyUpdate通知观察者更新UI
launcher.activityComponent.appsStore.setApps(apps, flags, packageUserKeytoUidMap)
...
}
后续具体是怎么更新应用列表的,此处就不再跟进了,感兴趣可以自己跟进看看
2.3 Launcher点击事件
看完了Launcher的启动流程和页面加载流程,我们最后看看Launcher的点击事件是怎么设置的吧。
这还得从 Launcher#onCreate 说起
// Launcher#onCreate
protected void onCreate(Bundle savedInstanceState) {
...
setupViews();
...
}
protected void setupViews() {
mStartupLatencyLogger.logStart(LAUNCHER_LATENCY_STARTUP_VIEW_INFLATION);
inflateRootView(R.layout.launcher);
...
}
在setupViews 加载了 launcher 布局文件,继续往后跟
// launcher.xml
<com.android.launcher3.LauncherRootView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:launcher="http://schemas.android.com/apk/res-auto"
android:id="@+id/launcher"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
...
<include
android:id="@+id/apps_view"
layout="@layout/all_apps"
android:layout_width="match_parent"
android:layout_height="match_parent" />
...
</com.android.launcher3.LauncherRootView>
// all_apps.xml
<com.android.launcher3.allapps.LauncherAllAppsContainerView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/apps_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="true"
android:clipToPadding="false"
android:focusable="false"
android:saveEnabled="false" />
Launcher#onCreate 中调用了 setupViews,而它去加载了 launcher.xml。在 launcher.xml 中使用了 all_apps.xml, all_apps.xml 使用了LauncherAllAppsContainerView,我们继续往下看看 LauncherAllAppsContainerView 的构造方法。
public class LauncherAllAppsContainerView extends ActivityAllAppsContainerView<Launcher> {
public LauncherAllAppsContainerView(Context context) {
this(context, null);
}
public LauncherAllAppsContainerView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public LauncherAllAppsContainerView(Context context, AttributeSet attrs, int defStyleAttr) {
// LauncherAllAppsContainerView的构造方法都会去调用父类的构造方法
super(context, attrs, defStyleAttr);
}
...
}
// ActivityAllAppsContainerView 构造方法
public ActivityAllAppsContainerView(Context context, AttributeSet attrs, int defStyleAttr) {
mActivityContext = ActivityContext.lookupContext(context);
...
initContent();
...
}
protected void initContent() {
mMainAdapterProvider = mSearchUiDelegate.createMainAdapterProvider();
// app list
mAH.set(AdapterHolder.MAIN, new AdapterHolder(AdapterHolder.MAIN,
new AlphabeticalAppsList<>(mActivityContext,
mAllAppsStore,
null,
mPrivateProfileManager)));
mAH.set(AdapterHolder.WORK, new AdapterHolder(AdapterHolder.WORK,
new AlphabeticalAppsList<>(mActivityContext, mAllAppsStore, mWorkManager, null)));
mAH.set(SEARCH, new AdapterHolder(SEARCH,
new AlphabeticalAppsList<>(mActivityContext, null, null, null)));
...
}
public class AdapterHolder {
...
AdapterHolder(int type, AlphabeticalAppsList<T> appsList) {
mType = type;
mAppsList = appsList;
// 这里去创建了 Adapter
mAdapter = createAdapter(mAppsList);
mAppsList.setAdapter(mAdapter);
mLayoutManager = mAdapter.getLayoutManager();
}
...
}
// ActivityAllAppsContainerView#createAdapter
protected BaseAllAppsAdapter<T> createAdapter(AlphabeticalAppsList<T> appsList) {
return new AllAppsGridAdapter<>(mActivityContext, getLayoutInflater(), appsList,
mMainAdapterProvider);
}
// AllAppsGridAdapter 没有重写 onCreateViewHolder,去它的父类 BaseAllAppsAdapter里找
public class AllAppsGridAdapter<T extends Context & ActivityContext> extends
BaseAllAppsAdapter<T> {
...
}
// BaseAllAppsAdapter
public abstract class BaseAllAppsAdapter<T extends Context & ActivityContext> extends
RecyclerView.Adapter<BaseAllAppsAdapter.ViewHolder> {
...
public BaseAllAppsAdapter(T activityContext, LayoutInflater inflater,
AlphabeticalAppsList<T> apps, SearchAdapterProvider<?> adapterProvider) {
mActivityContext = activityContext;
mApps = apps;
mLayoutInflater = inflater;
// mOnIconClickListener 赋值在这里
mOnIconClickListener = mActivityContext.getItemOnClickListener();
mOnIconLongClickListener = mActivityContext.getAllAppsItemLongClickListener();
mAdapterProvider = adapterProvider;
}
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
switch (viewType) {
case VIEW_TYPE_ICON:
int layout = (Flags.enableTwolineToggle()
&& LauncherPrefs.ENABLE_TWOLINE_ALLAPPS_TOGGLE.get(
mActivityContext.getApplicationContext()))
? R.layout.all_apps_icon_twoline : R.layout.all_apps_icon;
BubbleTextView icon = (BubbleTextView) mLayoutInflater.inflate(
layout, parent, false);
icon.setLongPressTimeoutFactor(1f);
icon.setOnFocusChangeListener(mIconFocusListener);
// 设置应用图标点击事件
icon.setOnClickListener(mOnIconClickListener);
icon.setOnLongClickListener(mOnIconLongClickListener);
// Ensure the all apps icon height matches the workspace icons in portrait mode.
icon.getLayoutParams().height =
mActivityContext.getDeviceProfile().allAppsCellHeightPx;
return new ViewHolder(icon);
...
}
}
}
我们目前跟踪到了 BaseAllAppsAdapter#onCreateViewHolder中,看到是通过 icon.setOnClickListener(mOnIconClickListener) 设置了应用图标点击事件,而 mOnIconClickListener 又是通过 mActivityContext.getItemOnClickListener 赋值给它的,所以现在就要看看这里的 mActivityContext 是什么
还记得 ActivityAllAppsContainerView 构造方法吗,我们前面只讲了 initContent,但没有说 ActivityContext.lookupContext(context)
// ActivityAllAppsContainerView 构造方法
public ActivityAllAppsContainerView(Context context, AttributeSet attrs, int defStyleAttr) {
// 这里的 context 就是 Launcher
// ActivityAllAppsContainerView 中的 mActivityContext 后续会传给 BaseAllAppsAdapter
mActivityContext = ActivityContext.lookupContext(context);
...
initContent();
...
}
// ActivityContext#lookupContext
static <T extends Context & ActivityContext> T lookupContext(Context context) {
// 调用 lookupContextNoThrow
T activityContext = lookupContextNoThrow(context);
if (activityContext == null) {
throw new IllegalArgumentException("Cannot find ActivityContext in parent tree");
}
return activityContext;
}
// ActivityContext#lookupContextNoThrow
static <T extends Context & ActivityContext> T lookupContextNoThrow(Context context) {
if (context instanceof ActivityContext) {
return (T) context;
} else if (context instanceof ActivityContextDelegate acd) {
return (T) acd.mDelegate;
} else if (context instanceof ContextWrapper) {
return lookupContextNoThrow(((ContextWrapper) context).getBaseContext());
} else {
return null;
}
}
到这,我们就找到了,在 ActivityContext#lookupContextNoThrow 中,如果是 ActivityContext,就转类型,那么我们看看 Launcher 的父类
public class Launcher extends StatefulActivity<LauncherState> ... {}
public abstract class StatefulActivity<STATE_TYPE extends BaseState<STATE_TYPE>>
extends BaseDraggingActivity ...{}
public abstract class BaseDraggingActivity extends BaseActivity ...{}
public abstract class BaseActivity extends Activity implements ActivityContext {}
// 从上面可以得出
Launcher
extends StatefulActivity<…>
extends BaseDraggingActivity
extends BaseActivity
implements ActivityContext
原来,Launcher 也是 ActivityContext的子类,那么 ActivityContext#lookupContextNoThrow 中,context instanceof ActivityContext 就为true, 所以 ActivityAllAppsContainerView 构造方法中的 ActivityContext.lookupContext(context) 就是 Launcher 自己,那么调用它的 getItemOnClickListener,但Launcher 并没有重写 getItemOnClickListener,因此会查找父类,在BaseDraggingActivity 中找到了此方法的实现,我们继续往后跟
// BaseDraggingActivity#getItemOnClickListener
public View.OnClickListener getItemOnClickListener() {
return ItemClickHandler.INSTANCE;
}
public class ItemClickHandler {
public static final OnClickListener INSTANCE = ItemClickHandler::onClick;
private static void onClick(View v) {
...
Object tag = v.getTag();
// 根据Tag, 调用不同的方法
if (tag instanceof WorkspaceItemInfo) {
onClickAppShortcut(v, (WorkspaceItemInfo) tag, launcher);
} else if (tag instanceof FolderInfo) {
onClickFolderIcon(v);
} else if (tag instanceof AppPairInfo) {
onClickAppPairIcon(v);
} else if (tag instanceof AppInfo) { // 点击 App 图标
startAppShortcutOrInfoActivity(v, (AppInfo) tag, launcher);
} else if (tag instanceof LauncherAppWidgetInfo) {
...
} else if (tag instanceof ItemClickProxy) {
((ItemClickProxy) tag).onItemClicked(v);
} else if (tag instanceof PendingAddShortcutInfo) {
CharSequence msg = Utilities.wrapForTts(
launcher.getText(R.string.long_press_shortcut_to_add),
launcher.getString(R.string.long_accessible_way_to_add_shortcut));
Snackbar.show(launcher, msg, null);
} else if (tag instanceof PendingAddWidgetInfo) {
...
CharSequence msg = Utilities.wrapForTts(
launcher.getText(R.string.long_press_widget_to_add),
launcher.getString(R.string.long_accessible_way_to_add));
Snackbar.show(launcher, msg, null);
}
}
...
}
Launcher 点击事件流程最后是到了 ItemClickHandler#onClick 中,根据不同Tag, 调用不同方法,比如说点击 shortcut, 会调用 onClickAppShortcut,这里就不每一个往后跟了,冷启动后续流程会在 启动速度优化 文章中详细写调用链。
三、小结与思考
本文主要介绍了 Launcher 启动流程,Launcher 页面加载流程,以及 Launcher 点击事件流程。
最后想说点个人思考,在AI时代,还有必要看源码吗?毕竟大部分问AI都可以知道,但我觉得仍然是有必要的。首先我们自己不去阅读源码,怎么判断AI的回答是对还是错呢;其次阅读源码是提升自己能力的重要方式,可以从中学习到一些优秀的设计模式和思想;最后通过阅读源码,我们可以加深对知识的理解,那么改bug, 做优化,我们就知道从哪里下手。比如优化Android冷启动速度,如果我们都不知道冷启动流程是什么,又何谈去优化它呢。
感谢阅读,希望本文对你有所帮助,如有任何不对的地方,欢迎大家指正。