Android|Android Launcher 详解


(1)Launcher的定义:Android系统启动后,加载的第一个程序,是其他应用程序的入口。
(2)Launcher的构成:HomeScreen(1.workspace(AppWidget,Wallpaper,Livefolder,ShortCut),2.HotSeats,3.AllApps/allApplist:GridView)
Android|Android Launcher 详解
文章图片



(3)针对Launcher的开发类型:
1.开发自定义的Launcher
2.与Workspace相关的开发(AppWidget,Wallpaper,Livefolder,ShortCut)
(4)解读Launcher源代码(以ShortCut为例),Launcher为系统级应用,位于Applications层。源代码位于MyAndroid\packages\apps\Launcher2中,可讲它导入eclipse中。
(5)看Manifest文件可知,Launcher的主Activity为:com.android.launcher2.Launcher。下面是它的部分配置信息:


(6)关于Activity的四种加载模式(android:launchMode):在多Activity开发中,有可能是自己应用之间的Activity跳转,或者夹带其他应用的可复用Activity。有可能会希望跳转到原来某个Activity实例,而不是产生大量重复的Activity。这就需要为Activity配置特定的加载模式,而不是默认的加载模式。


1.Standard:默认模式,每次激活Activity时都会创建Activity,并放入任务栈中。


2.singleTop:如果在任务栈栈顶正好存在该Activity的实例,就重用该实例(会调用实例的onNewIntent()),否则就会创建新的实例并放入栈顶,即使栈中已经存在该Activity的实例。


3.singleTask:如果在栈中已经有该Activity的实例,就会重用该实例,重用时,会让该实例回到栈顶,因此在它上面的实例将会被移出栈。


4.singleInstance:在一个新栈中创建该Activity的实例,并让多个应用共享该栈中的该Activity实例。一旦该模式的Activity实例已经存在于某个栈中,任何应用再激活该Activity时都会重用该栈中的实例( 会调用实例的onNewIntent() )。其效果相当于多个应用共享一个应用,不管谁激活该 Activity 都会进入同一个应用中。



(7)当用户按菜单键中的添加按钮或者长按workspace中的空白区域,会弹出一个对话框(如下图所示):

Android|Android Launcher 详解
文章图片







@Override publicbooleanonOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { caseMENU_ADD: addItems(); /* 按菜单键,添加按钮*/ returntrue; caseMENU_MANAGE_APPS: manageApps(); returntrue; caseMENU_WALLPAPER_SETTINGS: startWallpaper(); returntrue; caseMENU_SEARCH:@Override publicbooleanonOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { caseMENU_ADD: addItems(); /* 按菜单键,添加按钮*/ returntrue; caseMENU_MANAGE_APPS: manageApps(); returntrue; caseMENU_WALLPAPER_SETTINGS: startWallpaper(); returntrue; caseMENU_SEARCH: onSearchRequested(); returntrue; caseMENU_NOTIFICATIONS: showNotifications(); returntrue; }returnsuper.onOptionsItemSelected(item); }privatevoidaddItems() { closeAllApps(true); showAddDialog(mMenuAddInfo); /* 显示对话框 */ }// 长按workspace空白区域 if (mWorkspace.allowLongPress()) { if (cellInfo.cell == null) { if (cellInfo.valid) { // User long pressed on empty space mWorkspace.setAllowLongPress(false); mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING); showAddDialog(cellInfo); /* 显示对话框 */ } } else { if (!(cellInfo.cellinstanceof Folder)) { // User long pressed on an item mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING); mWorkspace.startDrag(cellInfo); } } } // showAddDialog方法 privatevoidshowAddDialog(CellLayout.CellInfocellInfo) { mAddItemCellInfo = cellInfo; mWaitingForResult = true; showDialog(DIALOG_CREATE_SHORTCUT); }// showDialog方法会调用下面这个方法创建对话框 protected Dialog onCreateDialog(int id) { switch (id) { caseDIALOG_CREATE_SHORTCUT: // 注意这里的常量 returnnewCreateShortcut().createDialog(); caseDIALOG_RENAME_FOLDER: returnnewRenameFolder().createDialog(); }returnsuper.onCreateDialog(id); }// CreateShortcut为Launcher的内部类,看其中的pickShortcut() // 方法,它实现很多接口/** * Displays the shortcut creation dialog and launches, if necessary, theappropriate activity. */ privateclassCreateShortcutimplementsDialogInterface.OnClickListener, DialogInterface.OnCancelListener, DialogInterface.OnDismissListener, DialogInterface.OnShowListener {privateAddAdaptermAdapter; Dialog createDialog() { mAdapter = newAddAdapter(Launcher.this); finalAlertDialog.Builder builder = newAlertDialog.Builder(Launcher.this); builder.setTitle(getString(R.string.menu_item_add_item)); builder.setAdapter(mAdapter, this); builder.setInverseBackgroundForced(true); AlertDialog dialog = builder.create(); dialog.setOnCancelListener(this); dialog.setOnDismissListener(this); dialog.setOnShowListener(this); return dialog; }publicvoidonCancel(DialogInterface dialog) { mWaitingForResult = false; cleanup(); }publicvoidonDismiss(DialogInterface dialog) { }privatevoid cleanup() { try { dismissDialog(DIALOG_CREATE_SHORTCUT); } catch (Exception e) { // An exception is thrown if the dialog is not visible, which is fine } }/** * Handle the action clicked in the “Add to home” dialog. */ publicvoidonClick(DialogInterface dialog, int which) { Resources res = getResources(); cleanup(); switch (which) { caseAddAdapter.ITEM_SHORTCUT: { // Insert extra item to handle picking application pickShortcut(); //当点击对话框中的快捷方式项,会//调用此方法 break; }caseAddAdapter.ITEM_APPWIDGET: { intappWidgetId = Launcher.this.mAppWidgetHost.allocateAppWidgetId(); Intent pickIntent = new Intent(AppWidgetManager.ACTION_APPWIDGET_PICK); pickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId); // start the pick activity startActivityForResult(pickIntent, REQUEST_PICK_APPWIDGET); break; }caseAddAdapter.ITEM_LIVE_FOLDER: { // Insert extra item to handle inserting folder Bundle bundle = new Bundle(); ArrayListshortcutNames = newArrayList(); shortcutNames.add(res.getString(R.string.group_folder)); bundle.putStringArrayList(Intent.EXTRA_SHORTCUT_NAME, shortcutNames); ArrayListshortcutIcons = newArrayList(); shortcutIcons.add(ShortcutIconResource.fromContext(Launcher.this, R.drawable.ic_launcher_folder)); bundle.putParcelableArrayList(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, shortcutIcons); Intent pickIntent = new Intent(Intent.ACTION_PICK_ACTIVITY); pickIntent.putExtra(Intent.EXTRA_INTENT, new Intent(LiveFolders.ACTION_CREATE_LIVE_FOLDER)); pickIntent.putExtra(Intent.EXTRA_TITLE, getText(R.string.title_select_live_folder)); pickIntent.putExtras(bundle); startActivityForResult(pickIntent, REQUEST_PICK_LIVE_FOLDER); break; }caseAddAdapter.ITEM_WALLPAPER: { startWallpaper(); break; } } }publicvoidonShow(DialogInterface dialog) { mWaitingForResult = true; } }// pickShortcut()方法 privatevoidpickShortcut() { Bundle bundle = new Bundle(); ArrayListshortcutNames = newArrayList(); shortcutNames.add(getString(R.string.group_applications)); bundle.putStringArrayList(Intent.EXTRA_SHORTCUT_NAME, shortcutNames); ArrayListshortcutIcons = newArrayList(); shortcutIcons.add(ShortcutIconResource.fromContext(Launcher.this, R.drawable.ic_launcher_application)); bundle.putParcelableArrayList(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, shortcutIcons); Intent pickIntent = new Intent(Intent.ACTION_PICK_ACTIVITY); pickIntent.putExtra(Intent.EXTRA_INTENT, new Intent(Intent.ACTION_CREATE_SHORTCUT)); pickIntent.putExtra(Intent.EXTRA_TITLE, getText(R.string.title_select_shortcut)); pickIntent.putExtras(bundle); startActivityForResult(pickIntent,REQUEST_PICK_SHORTCUT); // 启动了一个Activity,其实是一个快捷方式//列表,一个回调方法 }// 在onActivityResult()中caseREQUEST_PICK_SHORTCUT: processShortcut(data); // 回调此方法,data为Intent break; voidprocessShortcut(Intent intent) { // Handle case where user selected "Applications" String applicationName = getResources().getString(R.string.group_applications); String shortcutName = intent.getStringExtra(Intent.EXTRA_SHORTCUT_NAME); if (applicationName != null&&applicationName.equals(shortcutName)) { Intent mainIntent = new Intent(Intent.ACTION_MAIN, null); mainIntent.addCategory(Intent.CATEGORY_LAUNCHER); Intent pickIntent = new Intent(Intent.ACTION_PICK_ACTIVITY); pickIntent.putExtra(Intent.EXTRA_INTENT, mainIntent); pickIntent.putExtra(Intent.EXTRA_TITLE, getText(R.string.title_select_application)); startActivityForResultSafely(pickIntent, REQUEST_PICK_APPLICATION); } else { startActivityForResultSafely(intent, REQUEST_CREATE_SHORTCUT); //这里还要启动一个Activity } }caseREQUEST_CREATE_SHORTCUT: completeAddShortcut(data, mAddItemCellInfo); break; /** * Add a shortcut to the workspace. * * @param data The intent describing the shortcut. * @paramcellInfo The position on screen where to create the shortcut. */ privatevoidcompleteAddShortcut(Intent data, CellLayout.CellInfocellInfo) { cellInfo.screen = mWorkspace.getCurrentScreen(); if (!findSingleSlot(cellInfo)) return; finalShortcutInfo info = mModel.addShortcut(this, data, cellInfo, false); if (!mRestoring) { final View view = createShortcut(info); mWorkspace.addInCurrentScreen(view, cellInfo.cellX, cellInfo.cellY, 1, 1, isWorkspaceLocked()); } }



(8)如何让你的应用支持创建Shortcut,即你的应用能够出现在快捷方式列表中。
//单独创建一个Activity,例如ShortCut.java //配置此Activity// 以下是它的代码,这个startActivityForResultSafely(intent, //REQUEST_CREATE_SHORTCUT)方法会跳到这个Activity publicclassShortCutextends Activity { @Override protectedvoidonCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if(getIntent().getAction().equals(Intent.ACTION_CREATE_SHORTCUT)) { Intent returnIntent = new Intent(); returnIntent.putExtra(Intent.EXTRA_SHORTCUT_NAME, "应用管理器"); returnIntent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, new Intent(this, ShowAppActivity.class)); /* returnIntent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, Intent.ShortcutIconResource.fromContext(this, R.drawable.icon)); */ returnIntent.putExtra(Intent.EXTRA_SHORTCUT_ICON, R.drawable.icon); setResult(RESULT_OK, returnIntent); finish(); } }}


(9)如何在用户第一次启动应用后,提示用户是否要创建Shortcut:现在Manifest文件中添加一个权限()只要向Launcher发送一个广播,数据为一个Intent。此Intent与上面代码中的returnIntent类似,只要这个Intent添加一个Action(
intent.setAction("com.android.launcher.action.INSTALL_SHORTCUT"))。然后sendBroadcast(intent)。在Launcher中有个InstallShortcutReceiver.java,接受这个广播。





【Android|Android Launcher 详解】

    推荐阅读