@Override
protected void onCreate(Bundle savedInstanceState) {
if (DEBUG_STRICT_MODE) {
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectDiskReads()
.detectDiskWrites()
.detectNetwork() // or .detectAll() for all detectable problems
.penaltyLog()
.build());
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
.detectLeakedSqlLiteObjects()
.detectLeakedClosableObjects()
.penaltyLog()
.penaltyDeath()
.build());
}
if (LauncherAppState.PROFILE_STARTUP) {
Trace.beginSection("Launcher-onCreate");
}
if (mLauncherCallbacks != null) {
mLauncherCallbacks.preOnCreate();
}
WallpaperColorInfo wallpaperColorInfo = WallpaperColorInfo.getInstance(this);
wallpaperColorInfo.setOnThemeChangeListener(this);
overrideTheme(wallpaperColorInfo.isDark(), wallpaperColorInfo.supportsDarkText());
super.onCreate(savedInstanceState);
LauncherAppState app = LauncherAppState.getInstance(this);
// Load configuration-specific DeviceProfile
mDeviceProfile = app.getInvariantDeviceProfile().getDeviceProfile(this);
if (isInMultiWindowModeCompat()) {
Display display = getWindowManager().getDefaultDisplay();
Point mwSize = new Point();
display.getSize(mwSize);
mDeviceProfile = mDeviceProfile.getMultiWindowProfile(this, mwSize);
}
mOrientation = getResources().getConfiguration().orientation;
mSharedPrefs = Utilities.getPrefs(this);
mIsSafeModeEnabled = getPackageManager().isSafeMode();
mModel = app.setLauncher(this);
mModelWriter = mModel.getWriter(mDeviceProfile.isVerticalBarLayout());
mIconCache = app.getIconCache();
mAccessibilityDelegate = new LauncherAccessibilityDelegate(this);
mDragController = new DragController(this);
mAllAppsController = new AllAppsTransitionController(this);
mStateTransitionAnimation = new LauncherStateTransitionAnimation(this, mAllAppsController);
mAppWidgetManager = AppWidgetManagerCompat.getInstance(this);
mAppWidgetHost = new LauncherAppWidgetHost(this);
if (Utilities.ATLEAST_MARSHMALLOW) {
mAppWidgetHost.addProviderChangeListener(this);
}
mAppWidgetHost.startListening();
// If we are getting an onCreate, we can actually preempt onResume and unset mPaused here,
// this also ensures that any synchronous binding below doesn't re-trigger another
// LauncherModel load.
mPaused = false;
mLauncherView = LayoutInflater.from(this).inflate(R.layout.launcher, null);
setupViews();
mDeviceProfile.layout(this, false /* notifyListeners */);
loadExtractedColorsAndColorItems();
mPopupDataProvider = new PopupDataProvider(this);
((AccessibilityManager) getSystemService(ACCESSIBILITY_SERVICE))
.addAccessibilityStateChangeListener(this);
lockAllApps();
restoreState(savedInstanceState);
if (LauncherAppState.PROFILE_STARTUP) {
Trace.endSection();
}
// We only load the page synchronously if the user rotates (or triggers a
// configuration change) while launcher is in the foreground
int currentScreen = PagedView.INVALID_RESTORE_PAGE;
if (savedInstanceState != null) {
currentScreen = savedInstanceState.getInt(RUNTIME_STATE_CURRENT_SCREEN, currentScreen);
}
if (!mModel.startLoader(currentScreen)) {
// If we are not binding synchronously, show a fade in animation when
// the first page bind completes.
mDragLayer.setAlpha(0);
} else {
// Pages bound synchronously.
mWorkspace.setCurrentPage(currentScreen);
setWorkspaceLoading(true);
}
// For handling default keys
mDefaultKeySsb = new SpannableStringBuilder();
Selection.setSelection(mDefaultKeySsb, 0);
mRotationEnabled = getResources().getBoolean(R.bool.allow_rotation);
// In case we are on a device with locked rotation, we should look at preferences to check
// if the user has specifically allowed rotation.
if (!mRotationEnabled) {
mRotationEnabled = Utilities.isAllowRotationPrefEnabled(getApplicationContext());
mRotationPrefChangeHandler = new RotationPrefChangeHandler();
mSharedPrefs.registerOnSharedPreferenceChangeListener(mRotationPrefChangeHandler);
}
if (PinItemDragListener.handleDragRequest(this, getIntent())) {
// Temporarily enable the rotation
mRotationEnabled = true;
}
// On large interfaces, or on devices that a user has specifically enabled screen rotation,
// we want the screen to auto-rotate based on the current orientation
setOrientation();
setContentView(mLauncherView);
// Listen for broadcasts
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_OFF);
filter.addAction(Intent.ACTION_USER_PRESENT); // When the device wakes up + keyguard is gone
registerReceiver(mReceiver, filter);
mShouldFadeInScrim = true;
getSystemUiController().updateUiState(SystemUiController.UI_STATE_BASE_WINDOW,
Themes.getAttrBoolean(this, R.attr.isWorkspaceDarkText));
if (mLauncherCallbacks != null) {
mLauncherCallbacks.onCreate(savedInstanceState);
}
}
1.在onCreate中调用了mModel.startLoader(currentScreen)绑定UI和数据
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) {
final Callbacks oldCallbacks = mCallbacks.get();
// Clear any pending bind-runnables from the synchronized load process.
mUiExecutor.execute(new Runnable() {
public void run() {
oldCallbacks.clearPendingBinds();
}
});
// If there is already one running, tell it to stop.
stopLoader();
LoaderResults loaderResults = new LoaderResults(mApp, sBgDataModel,
mBgAllAppsList, synchronousBindPage, mCallbacks);
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;
}
2.loadWorkspace为加载配置数据,主要注意点
加载屏幕个数,
mBgDataModel.workspaceScreens.addAll(LauncherModel.loadWorkspaceScreensDb(context));
public static ArrayList loadWorkspaceScreensDb(Context context) {
final ContentResolver contentResolver = context.getContentResolver();
final Uri screensUri = LauncherSettings.WorkspaceScreens.CONTENT_URI;
// Get screens ordered by rank.
return LauncherDbUtils.getScreenIdsFromCursor(contentResolver.query(
screensUri, null, null, null, LauncherSettings.WorkspaceScreens.SCREEN_RANK));
}
加载数据库配置信息
final LoaderCursor c = new LoaderCursor(contentResolver.query(
LauncherSettings.Favorites.CONTENT_URI, null, null, null, null), mApp);
try {
final int appWidgetIdIndex = c.getColumnIndexOrThrow(
LauncherSettings.Favorites.APPWIDGET_ID);
final int appWidgetProviderIndex = c.getColumnIndexOrThrow(
LauncherSettings.Favorites.APPWIDGET_PROVIDER);
final int spanXIndex = c.getColumnIndexOrThrow
(LauncherSettings.Favorites.SPANX);
final int spanYIndex = c.getColumnIndexOrThrow(
LauncherSettings.Favorites.SPANY);
final int rankIndex = c.getColumnIndexOrThrow(
LauncherSettings.Favorites.RANK);
final int optionsIndex = c.getColumnIndexOrThrow(
LauncherSettings.Favorites.OPTIONS);
final LongSparseArray allUsers = c.allUsers;
根据itemType配置不同类型的数据,ITEM_TYPE_SHORTCUT,ITEM_TYPE_APPLICATION,ITEM_TYPE_DEEP_SHORTCUT,ITEM_TYPE_FOLDER,ITEM_TYPE_APPWIDGET,ITEM_TYPE_CUSTOM_APPWIDGET
3.loadAllApps(),加载All App页的所有包信息
final List apps = mLauncherApps.getActivityList(null, user);
4.loadDeepShortcuts();加载deep short
5.mResults.bindWorkspace(),数据和UI绑定,通过callback回调,callback即是Launcher,Launcher用 了MVC模式,Launcher是
View,LauncherModel是Model,方法里面需注意点是
callbacks.bindScreens(orderedScreenIds); // 展示屏幕数目
bindWorkspaceItems(otherWorkspaceItems, otherAppWidgets, deferredExecutor); // 绑定图标,快捷列表,Widget的UI
其里面最重要的方法是bindItems,绑定图标,快捷列表,Widget的逻辑放在这里,bindItems里workspace.addInScreenFromBind(view, item)是把各个View加载到每一屏中
public void bindItems(final List items, final boolean forceAnimateIcons) {
Runnable r = new Runnable() {
public void run() {
bindItems(items, forceAnimateIcons);
}
};
if (waitUntilResume(r)) {
return;
}
// Get the list of added items and intersect them with the set of items here
final AnimatorSet anim = LauncherAnimUtils.createAnimatorSet();
final Collection bounceAnims = new ArrayList<>();
final boolean animateIcons = forceAnimateIcons && canRunNewAppsAnimation();
Workspace workspace = mWorkspace;
long newItemsScreenId = -1;
int end = items.size();
for (int i = 0; i < end; i++) {
final ItemInfo item = items.get(i);
// Short circuit if we are loading dock items for a configuration which has no dock
if (item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT &&
mHotseat == null) {
continue;
}
final View view;
switch (item.itemType) {
case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT: {
ShortcutInfo info = (ShortcutInfo) item;
view = createShortcut(info);
break;
}
case LauncherSettings.Favorites.ITEM_TYPE_FOLDER: {
view = FolderIcon.fromXml(R.layout.folder_icon, this,
(ViewGroup) workspace.getChildAt(workspace.getCurrentPage()),
(FolderInfo) item);
break;
}
case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET: {
view = inflateAppWidget((LauncherAppWidgetInfo) item);
if (view == null) {
continue;
}
break;
}
default:
throw new RuntimeException("Invalid Item Type");
}
/*
* Remove colliding items.
*/
if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
CellLayout cl = mWorkspace.getScreenWithId(item.screenId);
if (cl != null && cl.isOccupied(item.cellX, item.cellY)) {
View v = cl.getChildAt(item.cellX, item.cellY);
Object tag = v.getTag();
String desc = "Collision while binding workspace item: " + item
+ ". Collides with " + tag;
if (FeatureFlags.IS_DOGFOOD_BUILD) {
throw (new RuntimeException(desc));
} else {
Log.d(TAG, desc);
getModelWriter().deleteItemFromDatabase(item);
continue;
}
}
}
workspace.addInScreenFromBind(view, item);
if (animateIcons) {
// Animate all the applications up now
view.setAlpha(0f);
view.setScaleX(0f);
view.setScaleY(0f);
bounceAnims.add(createNewAppBounceAnimation(view, i));
newItemsScreenId = item.screenId;
}
}
if (animateIcons) {
// Animate to the correct page
if (newItemsScreenId > -1) {
long currentScreenId = mWorkspace.getScreenIdForPageIndex(mWorkspace.getNextPage());
final int newScreenIndex = mWorkspace.getPageIndexForScreenId(newItemsScreenId);
final Runnable startBounceAnimRunnable = new Runnable() {
public void run() {
anim.playTogether(bounceAnims);
anim.start();
}
};
if (newItemsScreenId != currentScreenId) {
// We post the animation slightly delayed to prevent slowdowns
// when we are loading right after we return to launcher.
mWorkspace.postDelayed(new Runnable() {
public void run() {
if (mWorkspace != null) {
mWorkspace.snapToPage(newScreenIndex);
mWorkspace.postDelayed(startBounceAnimRunnable,
NEW_APPS_ANIMATION_DELAY);
}
}
}, NEW_APPS_PAGE_MOVE_DELAY);
} else {
mWorkspace.postDelayed(startBounceAnimRunnable, NEW_APPS_ANIMATION_DELAY);
}
}
}
workspace.requestLayout();
}
6.mResults.bindAllApps(); 绑定All App的UI
7.mResults.bindDeepShortcuts();绑定 Deep Shortcut UI
8.mResults.bindWidgets(); 绑定 Widget UI
至此,Launcher中的数据和UI绑定完成!!!