Android8.1 Launcher3启动源码解析之APP和界面加载

本文详细解析了Android 8.1 Launcher3启动过程,从onCreate方法开始,涵盖设备配置信息获取、APP数据加载等方面。在onCreate方法中,主要分为三个步骤:初始化LauncherAppState,加载设备配置,以及启动LoaderTask加载APP数据。LoaderTask内部通过loadWorkspace()加载工作区域,包括数据清理和分类,然后通过bindAllApps()绑定应用包信息,完成界面绘制。
摘要由CSDN通过智能技术生成

前面两篇文章介绍了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);

  • 0
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值