初始化运行环境

LauncherAppState.setApplicationContext(getApplicationContext());
        LauncherAppState app = LauncherAppState.getInstance();
在oncreate中会调用这个方法,LauncherAppState 保存着初始化的信息,并且Launcher实现了LauncherProviderChangeListener这个接口,然后两者产生联系,当应用的快捷方式,文件夹发生了变换,数据库也就发生了变换,进而通知LauncherAppState 。
    ## Launcher与launchermode的连接 ##
mModel = app.setLauncher(this);

launcher实现了launchermodel的callbacks接口。通过这样的调用,launchermodel’生成的数据就可以传递给launcher了。

launcher oncreate方法

super.onCreate(savedInstanceState);

        LauncherAppState.setApplicationContext(getApplicationContext());
        LauncherAppState app = LauncherAppState.getInstance();

        // Load configuration-specific DeviceProfile
        mDeviceProfile = getResources().getConfiguration().orientation
                == Configuration.ORIENTATION_LANDSCAPE ?
                        app.getInvariantDeviceProfile().landscapeProfile
                            : app.getInvariantDeviceProfile().portraitProfile;
//设置有多少个格子
        mSharedPrefs = getSharedPreferences(LauncherAppState.getSharedPreferencesKey(),
                Context.MODE_PRIVATE);
        mIsSafeModeEnabled = getPackageManager().isSafeMode();
        mModel = app.setLauncher(this);
        mIconCache = app.getIconCache();
//图标缓冲区
        mDragController = new DragController(this);
//初始化拖拽器,这个可能是我们最经常的操作了

        mInflater = getLayoutInflater();
        mStateTransitionAnimation = new LauncherStateTransitionAnimation(this);

        mStats = new Stats(this);
//launcher中有一个stats.log文件,保存着应用的启动信息。在stats类实例化的时候,会读取文件的信息,并进行保存
        /*
        * 桌面小部件
        * 通过LauncherAppWidgetHost加载小部件,并启动监听
        * */
        mAppWidgetManager = AppWidgetManagerCompat.getInstance(this);

        mAppWidgetHost = new LauncherAppWidgetHost(this, APPWIDGET_HOST_ID);
        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;

        if (PROFILE_STARTUP) {
            android.os.Debug.startMethodTracing(
                    Environment.getExternalStorageDirectory() + "/launcher");
        }

        setContentView(R.layout.launcher);
//设置布局文件,由此可见,launcher其实也是一个activity

        setupViews();
//        对控件初始化
    mDeviceProfile.layout(this);
    /*
* 上一个我们讨论了activity的状态恢复
* 这里进行的是laucher的状态恢复
* */
        mSavedState = savedInstanceState;
        restoreState(mSavedState);
        /*
* launchermodel  负责launcher的数据处理
* mrestoring 是否是数据的恢复处理
* */
        if (!mRestoring) {
            if (DISABLE_SYNCHRONOUS_BINDING_CURRENT_PAGE) {
                // If the user leaves launcher, then we should just load items asynchronously when
                // they return.
                mModel.startLoader(PagedView.INVALID_RESTORE_PAGE);
            } else {
                // We only load the page synchronously if the user rotates (or triggers a
                // configuration change) while launcher is in the foreground
                mModel.startLoader(mWorkspace.getRestorePage());
            }
        }
/*
* launchermodel  负责launcher的数据处理
* mrestoring 是否是数据的恢复处理
* */
        if (!mRestoring) {
            if (DISABLE_SYNCHRONOUS_BINDING_CURRENT_PAGE) {
                // If the user leaves launcher, then we should just load items asynchronously when
                // they return.
                mModel.startLoader(PagedView.INVALID_RESTORE_PAGE);
            } else {
                // We only load the page synchronously if the user rotates (or triggers a
                // configuration change) while launcher is in the foreground
                mModel.startLoader(mWorkspace.getRestorePage());
            }
        }

        // For handling default keys
        mDefaultKeySsb = new SpannableStringBuilder();
        Selection.setSelection(mDefaultKeySsb, 0);

        IntentFilter filter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
        registerReceiver(mCloseSystemDialogsReceiver, filter);
//配置文件规定了launcher的的方向,点进去我们可以看到sForceEnableRotation,allow_rotation这两个参数有关
        mRotationEnabled = Utilities.isRotationAllowedForDevice(getApplicationContext());
        // In case we are on a device with locked rotation, we should look at preferences to check
        // if the user has specifically allowed rotation.
//        但是这里,如果说我们的参数设置了false,那么我们依然后判断共享参数,如果共享参数中存储可以
//        任意方向旋转,那么依然成立
        if (!mRotationEnabled) {
            mRotationEnabled = Utilities.isAllowRotationPrefEnabled(getApplicationContext(), false);
        }

        // 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
//       mRotationEnabled设置launcher的旋转方向
        setOrientation();

        if (mLauncherCallbacks != null) {
            mLauncherCallbacks.onCreate(savedInstanceState);
            if (mLauncherCallbacks.hasLauncherOverlay()) {
                ViewStub stub = (ViewStub) findViewById(R.id.launcher_overlay_stub);
                mLauncherOverlayContainer = (InsettableFrameLayout) stub.inflate();
                mLauncherOverlay = mLauncherCallbacks.setLauncherOverlayView(
                        mLauncherOverlayContainer, mLauncherOverlayCallbacks);
                mWorkspace.setLauncherOverlay(mLauncherOverlay);
            }
        }
/*
* 是否需要显示介绍界面
* shouldShowIntroScreen()判断是否显示,获取共享参数的值
* 
* */
        if (shouldShowIntroScreen()) {
            showIntroScreen();
        } else {
//            如果不需要显示介绍界面,那么launcher考虑是否在第一次启动的时候显示帮助界面,同样的这里也是参考了配置文件的数据
            showFirstRunActivity();
            showFirstRunClings();
        }
    }

控件初始化

private void setupViews() {
        final DragController dragController = mDragController;

        mLauncherView = findViewById(R.id.launcher);
        mFocusHandler = (FocusIndicatorView) findViewById(R.id.focus_indicator);
        mDragLayer = (DragLayer) findViewById(R.id.drag_layer);
        mWorkspace = (Workspace) mDragLayer.findViewById(R.id.workspace);
        mWorkspace.setPageSwitchListener(this);
//        设置workspace切换监听器
        mPageIndicators = mDragLayer.findViewById(R.id.page_indicator);
//这个是指示器
        mLauncherView.setSystemUiVisibility(
                View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
        mWorkspaceBackgroundDrawable = getResources().getDrawable(R.drawable.workspace_bg);
/*
* 设置launcher为全屏
*  获得背景图p
* */
        // Setup the drag layer
        mDragLayer.setup(this, dragController);
//设置拖拽曾
        // Setup the hotseat
        mHotseat = (Hotseat) findViewById(R.id.hotseat);
//        快捷启动栏

        if (mHotseat != null) {
            mHotseat.setOnLongClickListener(this);
        }

        mOverviewPanel = (ViewGroup) findViewById(R.id.overview_panel);
        mWidgetsButton = findViewById(R.id.widget_button);
        mWidgetsButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View arg0) {
                if (!mWorkspace.isSwitchingState()) {
                    onClickAddWidgetButton(arg0);
                }
            }
        });
        mWidgetsButton.setOnTouchListener(getHapticFeedbackTouchListener());

        View wallpaperButton = findViewById(R.id.wallpaper_button);
        wallpaperButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View arg0) {
                if (!mWorkspace.isSwitchingState()) {
                    onClickWallpaperPicker(arg0);
                }
            }
        });
        wallpaperButton.setOnTouchListener(getHapticFeedbackTouchListener());

        View settingsButton = findViewById(R.id.settings_button);
        if (hasSettings()) {
            settingsButton.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View arg0) {
                    if (!mWorkspace.isSwitchingState()) {
                        onClickSettingsButton(arg0);
                    }
                }
            });
            settingsButton.setOnTouchListener(getHapticFeedbackTouchListener());
        } else {
            settingsButton.setVisibility(View.GONE);
        }

        mOverviewPanel.setAlpha(0f);
        /*
        * 这一块是对预览模式下的设置,长按屏幕会进入预览模式
        * 下面会有三个按钮,壁纸,小部件,设置
        *
        * */

        // Setup the workspace应用菜单误操作反馈
        mWorkspace.setHapticFeedbackEnabled(false);
        mWorkspace.setOnLongClickListener(this);//设置长按
//        接收控制器的控制
        mWorkspace.setup(dragController);
        dragController.addDragListener(mWorkspace);

        // Get the search/delete bar。获取搜索框实例
        mSearchDropTargetBar = (SearchDropTargetBar)
                mDragLayer.findViewById(R.id.search_drop_target_bar);

        // Setup Apps and Widgets,初始化小部件,常用app
        mAppsView = (AllAppsContainerView) findViewById(R.id.apps_view);
        mWidgetsView = (WidgetsContainerView) findViewById(R.id.widgets_view);
        if (mLauncherCallbacks != null && mLauncherCallbacks.getAllAppsSearchBarController() != null) {
            mAppsView.setSearchBarController(mLauncherCallbacks.getAllAppsSearchBarController());
        } else {
            mAppsView.setSearchBarController(mAppsView.newDefaultAppSearchController());
        }

        // Setup the drag controller (drop targets have to be added in reverse order in priority)
        dragController.setDragScoller(mWorkspace);
        dragController.setScrollView(mDragLayer);
        dragController.setMoveTarget(mWorkspace);
        dragController.addDropTarget(mWorkspace);
        if (mSearchDropTargetBar != null) {
            mSearchDropTargetBar.setup(this, dragController);
            mSearchDropTargetBar.setQsbSearchBar(getOrCreateQsbBar());
        }
//初始化小部件  ,读取文件数据,如果为true,则进行加载
        if (getResources().getBoolean(R.bool.debug_memory_enabled)) {
            Log.v(TAG, "adding WeightWatcher");
//            钟表组件
            mWeightWatcher = new WeightWatcher(this);
            mWeightWatcher.setAlpha(0.5f);
            ((FrameLayout) mLauncherView).addView(mWeightWatcher,
                    new FrameLayout.LayoutParams(
                            FrameLayout.LayoutParams.MATCH_PARENT,
                            FrameLayout.LayoutParams.WRAP_CONTENT,
                            Gravity.BOTTOM)
            );

            boolean show = shouldShowWeightWatcher();
            mWeightWatcher.setVisibility(show ? View.VISIBLE : View.GONE);
        }
    }

mDeviceProfile.layout(this);

/*
* 控件已经进行了初始化,那么怎么摆放呢
* launcher中含有搜索框,hotseat快捷启动栏,页面指示器,那么我们就必须调用DeviceProfile的layout方法设置其位置,内容比较繁杂,但都是一个道理,根据横屏竖屏,以及参数改变其位置
* */
    public void layout(Launcher launcher) {
        FrameLayout.LayoutParams lp;
        /*
        * 布局参数ip
        * 判断是否是竖屏
        * */
        boolean hasVerticalBarLayout = isVerticalBarLayout();
        final boolean isLayoutRtl = Utilities.isRtl(launcher.getResources());

        // Layout the search bar space
        View searchBar = launcher.getSearchDropTargetBar();
        lp = (FrameLayout.LayoutParams) searchBar.getLayoutParams();
        if (hasVerticalBarLayout) {
            // Vertical search bar space -- The search bar is fixed in the layout to be on the left
            //                              of the screen regardless of RTL
            lp.gravity = Gravity.LEFT;
            lp.width = searchBarSpaceHeightPx;

            LinearLayout targets = (LinearLayout) searchBar.findViewById(R.id.drag_target_bar);
            targets.setOrientation(LinearLayout.VERTICAL);
            FrameLayout.LayoutParams targetsLp = (FrameLayout.LayoutParams) targets.getLayoutParams();
            targetsLp.gravity = Gravity.TOP;
            targetsLp.height = LayoutParams.WRAP_CONTENT;

        } else {
            // Horizontal search bar space
            lp.gravity = Gravity.TOP;
            lp.height = searchBarSpaceHeightPx;

            LinearLayout targets = (LinearLayout) searchBar.findViewById(R.id.drag_target_bar);
            targets.getLayoutParams().width = searchBarSpaceWidthPx;
        }
        searchBar.setLayoutParams(lp);

        // Layout the workspace
        PagedView workspace = (PagedView) launcher.findViewById(R.id.workspace);
        lp = (FrameLayout.LayoutParams) workspace.getLayoutParams();
        lp.gravity = Gravity.CENTER;
        Rect padding = getWorkspacePadding(isLayoutRtl);
        workspace.setLayoutParams(lp);
        workspace.setPadding(padding.left, padding.top, padding.right, padding.bottom);
        workspace.setPageSpacing(getWorkspacePageSpacing(isLayoutRtl));

        // Layout the hotseat
//        获取hotseat实例
        View hotseat = launcher.findViewById(R.id.hotseat);
//        获得LayoutParams
        lp = (FrameLayout.LayoutParams) hotseat.getLayoutParams();
        if (hasVerticalBarLayout) {
            // Vertical hotseat -- The hotseat is fixed in the layout to be on the right of the
            //                     screen regardless of RTL
            lp.gravity = Gravity.RIGHT;
            lp.width = hotseatBarHeightPx;
            lp.height = LayoutParams.MATCH_PARENT;
            hotseat.findViewById(R.id.layout).setPadding(0, 2 * edgeMarginPx, 0, 2 * edgeMarginPx);
        } else if (isTablet) {
            // Pad the hotseat with the workspace padding calculated above
            lp.gravity = Gravity.BOTTOM;
            lp.width = LayoutParams.MATCH_PARENT;
            lp.height = hotseatBarHeightPx;
            hotseat.setPadding(edgeMarginPx + padding.left, 0,
                    edgeMarginPx + padding.right,
                    2 * edgeMarginPx);
        } else {
            /*
            * 设置快键拦的位置为底部,设置padding距离
            * */
            // For phones, layout the hotseat without any bottom margin
            // to ensure that we have space for the folders
            lp.gravity = Gravity.BOTTOM;
            lp.width = LayoutParams.MATCH_PARENT;
            lp.height = hotseatBarHeightPx;
            hotseat.findViewById(R.id.layout).setPadding(2 * edgeMarginPx, 0,
                    2 * edgeMarginPx, 0);
        }
        hotseat.setLayoutParams(lp);

launcher状态恢复

private void restoreState(Bundle savedState) {
//        判断savestate数据是否为空
        if (savedState == null) {
            return;
        }

        State state = intToState(savedState.getInt(RUNTIME_STATE, State.WORKSPACE.ordinal()));
        if (state == State.APPS || state == State.WIDGETS) {
            mOnResumeState = state;
        }
//这个跟我们上次所讲的保存状态发生关联
        int currentScreen = savedState.getInt(RUNTIME_STATE_CURRENT_SCREEN,
                PagedView.INVALID_RESTORE_PAGE);
//        获得应用程序菜单在第几页,然后进行恢复
        if (currentScreen != PagedView.INVALID_RESTORE_PAGE) {
            mWorkspace.setRestorePage(currentScreen);
        }
//恢复要添加的组件
        final long pendingAddContainer = savedState.getLong(RUNTIME_STATE_PENDING_ADD_CONTAINER, -1);
        final long pendingAddScreen = savedState.getLong(RUNTIME_STATE_PENDING_ADD_SCREEN, -1);

        if (pendingAddContainer != ItemInfo.NO_ID && pendingAddScreen > -1) {
            mPendingAddInfo.container = pendingAddContainer;
            mPendingAddInfo.screenId = pendingAddScreen;
            mPendingAddInfo.cellX = savedState.getInt(RUNTIME_STATE_PENDING_ADD_CELL_X);
            mPendingAddInfo.cellY = savedState.getInt(RUNTIME_STATE_PENDING_ADD_CELL_Y);
            mPendingAddInfo.spanX = savedState.getInt(RUNTIME_STATE_PENDING_ADD_SPAN_X);
            mPendingAddInfo.spanY = savedState.getInt(RUNTIME_STATE_PENDING_ADD_SPAN_Y);
            AppWidgetProviderInfo info = savedState.getParcelable(
                    RUNTIME_STATE_PENDING_ADD_WIDGET_INFO);
            mPendingAddWidgetInfo = info == null ?
                    null : LauncherAppWidgetProviderInfo.fromProviderInfo(this, info);

            mPendingAddWidgetId = savedState.getInt(RUNTIME_STATE_PENDING_ADD_WIDGET_ID);
//            根据 保存的信息进行恢复,使launcher处于等待状态,下面贴出列这个方法的实现,似乎只是把value的值付给了mwaitingforresult,然后进行了判断,两者不可能不一样,那么调用 onWorkspaceLockedChanged();
            setWaitingForResult(true);
//            这个应该表示恢复成功,进行标识,以便后续使用
            mRestoring = true;
        }

        mItemIdToViewId = (HashMap<Integer, Integer>)
                savedState.getSerializable(RUNTIME_STATE_VIEW_IDS);
    }
    private void setWaitingForResult(boolean value) {
        boolean isLocked = isWorkspaceLocked();
        mWaitingForResult = value;
        if (isLocked != isWorkspaceLocked()) {
            onWorkspaceLockedChanged();
        }
    }

showIntroScreen介绍界面的显示

rotected void showIntroScreen() {
//        获取介绍界面的view
        View introScreen = getIntroScreen();
//        设置介绍界面的壁纸不可见
        changeWallpaperVisiblity(false);
        if (introScreen != null) {
//            这个在我们初始化控件的时候有显示  draglayer是一个根视图,在内部进行了一个addview的操作,这个
//            我们会很熟悉
            mDragLayer.showOverlayView(introScreen);
        }
        if (mLauncherOverlayContainer != null) {
            mLauncherOverlayContainer.setVisibility(View.INVISIBLE);
        }
    }

到这里launcher3的oncreate方法介绍完毕。 跟我们寻常的activity一样,他主要进行控件的初始化,以及获得设置的参数,做出相应的处理。