初始化运行环境
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一样,他主要进行控件的初始化,以及获得设置的参数,做出相应的处理。