前面两篇文章介绍了AMS的启动,已经AMS启动之后启动Launcher的第一个Activity的过程。讲完上面那些东西,现在就说一下Launcher界面的加载过程。
一、Launcher启动之onCreate方法
@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); //步骤1-获取配置Launcher启动信息对象实例 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; //获取主界面View mLauncherView = LayoutInflater.from(this).inflate(R.layout.launcher, null); //获取各个控件的View 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); } //步骤三-加载各个界面,加载所有的APP 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); } }
这部分代码差不多要完成Launcher显示所需要的数据的加载工作,我这里主要分三个步骤。
- LauncherAppState app = LauncherAppState.getInstance(this)完成步骤一加载设备配置信息,根据屏幕数据来设定APP图标大小,已经选定所需显示界面的大小
- 步骤二获取界面中View,在下一个步骤中将数据绑定到View
- mModel.startLoader(currentScreen)完成步骤三获取所有屏幕中显示的数据,APP的数据。然后将数据绑定到View中显示
下面就来讲解步骤一和步骤三
二、获取设备配置信息
1、LauncherAppState的实例化
public static LauncherAppState getInstance(final Context context) { if (INSTANCE == null) { if (Looper.myLooper() == Looper.getMainLooper()) { //是在主线程,进行实例化 INSTANCE = new LauncherAppState(context.getApplicationContext()); } else { try { return new MainThreadExecutor().submit(new Callable<LauncherAppState>() { @Override public LauncherAppState call() throws Exception { return LauncherAppState.getInstance(context); } }).get(); } catch (InterruptedException|ExecutionException e) { throw new RuntimeException(e); } } } return INSTANCE; } private LauncherAppState(Context context) { if (getLocalProvider(context) == null) { throw new RuntimeException( "Initializing LauncherAppState in the absence of LauncherProvider"); } Log.v(Launcher.TAG, "LauncherAppState initiated"); Preconditions.assertUIThread(); mContext = context; if (TestingUtils.MEMORY_DUMP_ENABLED) { TestingUtils.startTrackingMemory(mContext); } //设备基本配置信息 mInvariantDeviceProfile = new InvariantDeviceProfile(mContext); //图标大小 mIconCache = new IconCache(mContext, mInvariantDeviceProfile); mWidgetCache = new WidgetPreviewLoader(mContext, mIconCache); //加载APP等操作对象实例化 mModel = new LauncherModel(this, mIconCache, AppFilter.newInstance(mContext)); //添加监听APK变化的监听器 LauncherAppsCompat.getInstance(mContext).addOnAppsChangedCallback(mModel); // Register intent receivers IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_LOCALE_CHANGED); // For handling managed profiles filter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED); filter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED); filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE); filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE); filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNLOCKED); // For extracting colors from the wallpaper if (Utilities.ATLEAST_NOUGAT) { // TODO: add a broadcast entry to the manifest for pre-N. filter.addAction(Intent.ACTION_WALLPAPER_CHANGED); } mContext.registerReceiver(mModel, filter); UserManagerCompat.getInstance(mContext).enableAndResetCache(); new ConfigMonitor(mContext).register(); ExtractionUtils.startColorExtractionServiceIfNecessary(mContext); if (!mContext.getResources().getBoolean(R.bool.notification_badging_enabled)) { mNotificationBadgingObserver = null; } else { // Register an observer to rebind the notification listener when badging is re-enabled. mNotificationBadgingObserver = new SettingsObserver.Secure( mContext.getContentResolver()) { @Override public void onSettingChanged(boolean isNotificationBadgingEnabled) { if (isNotificationBadgingEnabled) { NotificationListener.requestRebind(new ComponentName( mContext, NotificationListener.class)); } } }; mNotificationBadgingObserver.register(NOTIFICATION_BADGING); } }这这部分过程中获取设备配置信息,计算图标,控件等大小,最后还要添加APP变化监听器。下面看一下获取设备配置信息
2、InvariantDeviceProfile对象实例化
InvariantDeviceProfile(Context context) { WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); Display display = wm.getDefaultDisplay(); DisplayMetrics dm = new DisplayMetrics(); display.getMetrics(dm);