packages\apps\Launcher3\src\com\android\launcher3\Launcher.java
onCreate方法中
LauncherAppState app = LauncherAppState.getInstance(this);获取LauncherAppState的实例
mModel = app.getModel();获取LauncherModel的实例
mSharedPrefs = Utilities.getPrefs(this);
if (!mModel.addCallbacksAndLoad(this)) { 加载
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);
}
}
packages\apps\Launcher3\src\com\android\launcher3\LauncherAppState.java
public LauncherModel getModel() {
return mModel;
}
public LauncherAppState(Context context, @Nullable String iconCacheFileName) {
Log.v(Launcher.TAG, "LauncherAppState initiated");
Preconditions.assertUIThread();
mContext = context;
mInvariantDeviceProfile = InvariantDeviceProfile.INSTANCE.get(context);
mIconCache = new IconCache(mContext, mInvariantDeviceProfile, iconCacheFileName);
mWidgetCache = new WidgetPreviewLoader(mContext, mIconCache);
mModel = new LauncherModel(this, mIconCache, AppFilter.newInstance(mContext));
mPredictionModel = PredictionModel.newInstance(mContext);
}
packages\apps\Launcher3\src\com\android\launcher3\LauncherModel.java
mModel.addCallbacksAndLoad(this)
public boolean addCallbacksAndLoad(Callbacks callbacks) {
synchronized (mLock) {
addCallbacks(callbacks);
return startLoader();
}
}
/**
* Adds a callbacks to receive model updates
*/
public void addCallbacks(Callbacks callbacks) {
Preconditions.assertUIThread();
synchronized (mCallbacksList) {
mCallbacksList.add(callbacks);
}
}
public boolean startLoader() {
// 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
final Callbacks[] callbacksList = getCallbacks();
if (callbacksList.length > 0) {
// Clear any pending bind-runnables from the synchronized load process.
for (Callbacks cb : callbacksList) {
mMainExecutor.execute(cb::clearPendingBinds);
}
// If there is already one running, tell it to stop.
stopLoader();
LoaderResults loaderResults = new LoaderResults(
mApp, mBgDataModel, mBgAllAppsList, callbacksList, mMainExecutor);
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;
}
Launcher是用工作区的形式来显示系统已安装的应用程序的快捷图标,每个工作区都是来描述一个抽象桌面,它由n个屏幕组成(n页),每个屏幕又分n个单元格(n个快捷图标),每个单元格用来显示一个应用程序的快捷图标。
bindWorkspace函数用来加载工作区信息,bindAllApps函数是用来加载系统已经安装的应用程序信息
LoaderResults 的方法实现为BaseLoaderResults
packages\apps\Launcher3\src\com\android\launcher3\model\BaseLoaderResults.java
public void bindAllApps() {
// shallow copy
AppInfo[] apps = mBgAllAppsList.copyData();
int flags = mBgAllAppsList.getFlags();
executeCallbacksTask(c -> c.bindAllApplications(apps, flags), mUiExecutor);
}
protected void executeCallbacksTask(CallbackTask task, Executor executor) {
executor.execute(() -> {
if (mMyBindingId != mBgDataModel.lastBindId) {
Log.d(TAG, "Too many consecutive reloads, skipping obsolete data-bind");
return;
}
for (Callbacks cb : mCallbacksList) {
task.execute(cb);
}
});
}
CallbackTask定义在 packages\apps\Launcher3\src\com\android\launcher3\LauncherModel.java
public interface CallbackTask {
void execute(Callbacks callbacks);
}
mUiExecutor为packages\apps\Launcher3\src\com\android\launcher3\util\LooperExecutor.java
@Override
public void execute(Runnable runnable) {
if (getHandler().getLooper() == Looper.myLooper()) {
runnable.run();
} else {
getHandler().post(runnable);
}
}
packages\apps\Launcher3\src\com\android\launcher3\Launcher.java
@Override
public void bindAllApplications(AppInfo[] apps, int flags) {
mAppsView.getAppsStore().setApps(apps, flags);
}
AllAppsContainerView
packages\apps\Launcher3\src\com\android\launcher3\allapps\AllAppsContainerView.java
public AllAppsStore getAppsStore() {
return mAllAppsStore;
}
mAllAppsStore.addUpdateListener(this::onAppsUpdated);
private void onAppsUpdated() {
boolean hasWorkApps = false;
for (AppInfo app : mAllAppsStore.getApps()) {
if (mWorkMatcher.matches(app, null)) {
hasWorkApps = true;
break;
}
}
rebindAdapters(hasWorkApps);
if (hasWorkApps) {
resetWorkProfile();
}
}
private void rebindAdapters(boolean showTabs) {
rebindAdapters(showTabs, false /* force */);
}
protected void rebindAdapters(boolean showTabs, boolean force) {
if (showTabs == mUsingTabs && !force) {
return;
}
replaceRVContainer(showTabs);
mUsingTabs = showTabs;
mAllAppsStore.unregisterIconContainer(mAH[AdapterHolder.MAIN].recyclerView);
mAllAppsStore.unregisterIconContainer(mAH[AdapterHolder.WORK].recyclerView);
分页策略
if (mUsingTabs) {
setupWorkToggle();
mAH[AdapterHolder.MAIN].setup(mViewPager.getChildAt(0), mPersonalMatcher);
mAH[AdapterHolder.WORK].setup(mViewPager.getChildAt(1), mWorkMatcher);
mViewPager.getPageIndicator().setActiveMarker(AdapterHolder.MAIN);
findViewById(R.id.tab_personal)
.setOnClickListener((View view) -> mViewPager.snapToPage(AdapterHolder.MAIN));
findViewById(R.id.tab_work)
.setOnClickListener((View view) -> mViewPager.snapToPage(AdapterHolder.WORK));
onTabChanged(mViewPager.getNextPage());
} else {
mAH[AdapterHolder.MAIN].setup(findViewById(R.id.apps_list_view), null);
mAH[AdapterHolder.WORK].recyclerView = null;
if (mWorkModeSwitch != null) {
((ViewGroup) mWorkModeSwitch.getParent()).removeView(mWorkModeSwitch);
mWorkModeSwitch = null;
}
}
setupHeader();
mAllAppsStore.registerIconContainer(mAH[AdapterHolder.MAIN].recyclerView);
mAllAppsStore.registerIconContainer(mAH[AdapterHolder.WORK].recyclerView);
}
AllAppsStore
packages\apps\Launcher3\src\com\android\launcher3\allapps\AllAppsStore.java
/**
* Sets the current set of apps.
*/
public void setApps(AppInfo[] apps, int flags) {
mApps = apps;
mModelFlags = flags;
notifyUpdate();
}
private void notifyUpdate() {
if (mDeferUpdatesFlags != 0) {
mUpdatePending = true;
return;
}
for (OnUpdateListener listener : mUpdateListeners) {
listener.onAppsUpdated();
}
}
packages\apps\Launcher3\src\com\android\launcher3\allapps\AlphabeticalAppsList.java
AlphabeticalAppsList实现了OnUpdateListener 接口
/**
* Updates internals when the set of apps are updated.
*/
@Override
public void onAppsUpdated() {
// Sort the list of apps
mApps.clear();
for (AppInfo app : mAllAppsStore.getApps()) {
if (mItemFilter == null || mItemFilter.matches(app, null) || hasFilter()) {
mApps.add(app);
}
}
Collections.sort(mApps, mAppNameComparator);
// As a special case for some languages (currently only Simplified Chinese), we may need to
// coalesce sections
Locale curLocale = mLauncher.getResources().getConfiguration().locale;
boolean localeRequiresSectionSorting = curLocale.equals(Locale.SIMPLIFIED_CHINESE);
if (localeRequiresSectionSorting) {
// Compute the section headers. We use a TreeMap with the section name comparator to
// ensure that the sections are ordered when we iterate over it later
TreeMap<String, ArrayList<AppInfo>> sectionMap = new TreeMap<>(new LabelComparator());
for (AppInfo info : mApps) {
// Add the section to the cache
String sectionName = info.sectionName;
// Add it to the mapping
ArrayList<AppInfo> sectionApps = sectionMap.get(sectionName);
if (sectionApps == null) {
sectionApps = new ArrayList<>();
sectionMap.put(sectionName, sectionApps);
}
sectionApps.add(info);
}
// Add each of the section apps to the list in order
mApps.clear();
for (Map.Entry<String, ArrayList<AppInfo>> entry : sectionMap.entrySet()) {
mApps.addAll(entry.getValue());
}
}
// Recompose the set of adapter items from the current set of apps
updateAdapterItems();
}
|