首页 > IT职业 > IT职场 > Android App应用启动流程(一)
本篇源码分析基于Android8.0 API 26
关于Android源码查看:
你可以去看这里:https://android.googlesource.com/platform/frameworks/base/ 在线查看,也可以在Android Studio里面关联源码,也可以完全下载自己去编译
Launcher中的App列表使用的RecyclerView
//public class AllAppsRecyclerView extends BaseRecyclerView//public abstract class BaseRecyclerView extends RecyclerView//AllAppsRecyclerView最终继承自RecyclerView
这个Activity叫做Launcher.java,既然是RecyclerView,我们很自然的想到了item点击事件,item点击事件其实是对item设置的View.OnClickListener事件,恰巧Launcher实现了这个事件
/**
* Default launcher application.
*/public class Launcher extends BaseActivity
implements LauncherExterns, View.OnClickListener, OnLongClickListener, LauncherModel.Callbacks, View.OnTouchListener, LauncherProviderChangeListener, AccessibilityManager.AccessibilityStateChangeListener, WallpaperColorInfo.OnThemeChangeListener {
那么是不是这里就是用来处理RecyclerView应用图标的点击事件呢?答案是yes
给AllAppsRecyclerView设置adapter被封装到了AllAppsContainerView里面,然后AllAppsContainerView里面
mAdapter = new AllAppsGridAdapter(mLauncher, mApps, mLauncher, this);
AllAppsGridAdapter
/** * The grid view adapter of all the apps. */ public class AllAppsGridAdapter extends RecyclerView.Adapter{ ... //AllAppsGridAdapter构造函数传入iconClickListener public AllAppsGridAdapter(Launcher launcher, AlphabeticalAppsList apps, View.OnClickListener iconClickListener, View.OnLongClickListener iconLongClickListener) { Resources res = launcher.getResources(); mLauncher = launcher; mApps = apps; mEmptySearchMessage = res.getString(R.string.all_apps_loading_message); mGridSizer = new GridSpanSizer(); mGridLayoutMgr = new AppsGridLayoutManager(launcher); mGridLayoutMgr.setSpanSizeLookup(mGridSizer); mLayoutInflater = LayoutInflater.from(launcher); mIconClickListener = iconClickListener; mIconLongClickListener = iconLongClickListener; if (FeatureFlags.LAUNCHER3_PHYSICS) { mSpringAnimationHandler = new SpringAnimationHandler( SpringAnimationHandler.Y_DIRECTION, new AllAppsSpringAnimationFactory()); } } ... @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { switch (viewType) { case VIEW_TYPE_ICON: case VIEW_TYPE_PREDICTION_ICON: //icon点击事件 BubbleTextView icon = (BubbleTextView) mLayoutInflater.inflate( R.layout.all_apps_icon, parent, false); icon.setOnClickListener(mIconClickListener); icon.setOnLongClickListener(mIconLongClickListener); icon.setLongPressTimeout(ViewConfiguration.getLongPressTimeout()); icon.setOnFocusChangeListener(mIconFocusListener); // Ensure the all apps icon height matches the workspace icons in portrait mode. icon.getLayoutParams().height = mLauncher.getDeviceProfile().allAppsCellHeightPx; return new ViewHolder(icon); ... } } ...}
可见这个点击事件被设置上了,现在我们回去看看Launcher.java这个Activity里面的onClick事件
/**
* Launches the intent referred by the clicked shortcut.
*
* @param v The view representing the clicked shortcut.
*/public void onClick(View v) {
...
Object tag = v.getTag(); if (tag instanceof ShortcutInfo) {
onClickAppShortcut(v);
} else if (tag instanceof FolderInfo) { if (v instanceof FolderIcon) {
onClickFolderIcon(v);
}
} else if ((v instanceof PageIndicator) ||
(v == mAllAppsButton && mAllAppsButton != null)) {
onClickAllAppsButton(v);
} else if (tag instanceof AppInfo) { //执行这里
startAppShortcutOrInfoActivity(v);
} else if (tag instanceof LauncherAppWidgetInfo) { if (v instanceof PendingAppWidgetHostView) {
onClickPendingWidget((PendingAppWidgetHostView) v);
}
}
}//拿到应用信息,执行startActivitySafely(v, intent, item)private void startAppShortcutOrInfoActivity(View v) {
ItemInfo item = (ItemInfo) v.getTag();
Intent intent; if (item instanceof PromiseAppInfo) {
PromiseAppInfo promiseAppInfo = (PromiseAppInfo) item;
intent = promiseAppInfo.getMarketIntent();
} else {
intent = item.getIntent();
} if (intent == null) { throw new IllegalArgumentException("Input must have a valid intent");
} boolean success = startActivitySafely(v, intent, item);
getUserEventDispatcher().logAppLaunch(v, intent); // TODO for discovered apps b/35802115
if (success && v instanceof BubbleTextView) {
mWaitingForResume = (BubbleTextView) v;
mWaitingForResume.setStayPressed(true);
}
}public boolean startActivitySafely(View v, Intent intent, ItemInfo item) {
... // Only launch using the new animation if the shortcut has not opted out (this is a
// private contract between launcher and may be ignored in the future).
boolean useLaunchAnimation = (v != null) &&
!intent.hasExtra(INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION);
Bundle optsBundle = useLaunchAnimation ? getActivityLaunchOptions(v) : null;
UserHandle user = item == null ? null : item.user; // Prepare intent
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); if (v != null) {
intent.setSourceBounds(getViewBounds(v));
} try { if (Utilities.ATLEAST_MARSHMALLOW
&& (item instanceof ShortcutInfo)
&& (item.itemType == Favorites.ITEM_TYPE_SHORTCUT
|| item.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT)
&& !((ShortcutInfo) item).isPromise()) { // Shortcuts need some special checks due to legacy reasons.
startShortcutIntentSafely(intent, optsBundle, item);
} else if (user == null || user.equals(Process.myUserHandle())) { // Could be launching some bookkeeping activity
startActivity(intent, optsBundle);
} else {
LauncherAppsCompat.getInstance(this).startActivityForProfile(
intent.getComponent(), user, intent.getSourceBounds(), optsBundle);
} return true;
} catch (ActivityNotFoundException|SecurityException e) {
Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
Log.e(TAG, "Unable to launch. tag=" + item + " intent=" + intent, e);
} return false;
}
可以看到最后执行的是startActivity方法,startActivity是Activity的方法,关于app图标点击事件先讲到这。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/855/viewspace-2801645/ ,如需转载,请注明出处,否则将追究法律责任。