1.1.1进入到Launcher.java 找到
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);
}
}
...
...
}
1.1.2 进入OnClickAppShortcut(v)
/**
* Event handler for an app shortcut click.
*
* @param v The view that was clicked. Must be a tagged with a {@link ShortcutInfo}.
*/
protected void onClickAppShortcut(final View v) {
if (LOGD) Log.d(TAG, "onClickAppShortcut");
Object tag = v.getTag();
if (!(tag instanceof ShortcutInfo)) {
throw new IllegalArgumentException("Input must be a Shortcut");
}
// Open shortcut
final ShortcutInfo shortcut = (ShortcutInfo) tag;
if (shortcut.isDisabled != 0) {
if ((shortcut.isDisabled &
~ShortcutInfo.FLAG_DISABLED_SUSPENDED &
~ShortcutInfo.FLAG_DISABLED_QUIET_USER) == 0) {
// If the app is only disabled because of the above flags, launch activity anyway.
// Framework will tell the user why the app is suspended.
} else {
if (!TextUtils.isEmpty(shortcut.disabledMessage)) {
// Use a message specific to this shortcut, if it has one.
Toast.makeText(this, shortcut.disabledMessage, Toast.LENGTH_SHORT).show();
return;
}
// Otherwise just use a generic error message.
int error = R.string.activity_not_available;
if ((shortcut.isDisabled & ShortcutInfo.FLAG_DISABLED_SAFEMODE) != 0) {
error = R.string.safemode_shortcut_error;
} else if ((shortcut.isDisabled & ShortcutInfo.FLAG_DISABLED_BY_PUBLISHER) != 0 ||
(shortcut.isDisabled & ShortcutInfo.FLAG_DISABLED_LOCKED_USER) != 0) {
error = R.string.shortcut_not_available;
}
Toast.makeText(this, error, Toast.LENGTH_SHORT).show();
return;
}
}
// Check for abandoned promise
if ((v instanceof BubbleTextView) && shortcut.hasPromiseIconUi()) {
String packageName = shortcut.intent.getComponent() != null ?
shortcut.intent.getComponent().getPackageName() : shortcut.intent.getPackage();
if (!TextUtils.isEmpty(packageName)) {
onClickPendingAppItem(v, packageName,
shortcut.hasStatusFlag(ShortcutInfo.FLAG_INSTALL_SESSION_ACTIVE));
return;
}
}
// Start activities
startAppShortcutOrInfoActivity(v);
}
1.1.3进入 startAppShortcutOrInfoActivity()
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);
}
}
1.1.4 进入startActivitySafely
public boolean startActivitySafely(View v, Intent intent, ItemInfo item) {
if (mIsSafeModeEnabled && !Utilities.isSystemApp(this, intent)) {
Toast.makeText(this, R.string.safemode_shortcut_error, Toast.LENGTH_SHORT).show();
return false;
}
// 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()) { //注释1
// Shortcuts need some special checks due to legacy reasons.
startShortcutIntentSafely(intent, optsBundle, item);
} else if (user == null || user.equals(Process.myUserHandle())) {//注释2
// Could be launching some bookkeeping activity
startActivity(intent, optsBundle);
} else { //注释3
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;
}
分析
方法中有三个if else的判断
注释1
6.0以上的系统,快捷方式启动,需要做一些校验。所谓的快捷方式,是google提供的新特性,用于启动应用内的快捷操作,譬如是 发信息给某一个用户。
注释2
如果user为空 或就是launcher所在用户
startActivity() //启动Activity的地方
注释3 (哪种情况会走这里的逻辑,待确认)
1.2 APP内部启动
1.2.1 显式启动
直接指定我们要启动的class名字
private void ExplicitStartActivity(){
Intent intent = new Intent(this,ExplicitIntentActivity.class);
startActivity(intent);
}
1.2.2 隐式启动
设定intent的action,让系统去匹配查找
private void ImplicitStartActivity(){
Intent intent = new Intent("com.shine.activitystudy.ImplicitIntentActivity");
startActivity(intent);
}
1.3 从startActivity开始
可以看到 无论是从launcher启动还是app内部启动,最后都会调用到Activity.java的startActivity()方法。
1.3.1 startActivity分析
public void startActivity(Intent intent, @Nullable Bundle options) {
if (options != null) {
startActivityForResult(intent, -1, options);
} else {
// Note we want to go through this call for compatibility with
// applications that may have overridden the method.
startActivityForResult(intent, -1); //注释1
}
}
以options是否为null来调用startActivityForResult()
来看注释1的实现
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode) {
startActivityForResult(intent, requestCode, null);
}
也是调用到了这个方法。
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
@Nullable Bundle options)
下一节,我们就以
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
@Nullable Bundle options)
作为开始来进一步分析Activity是如何启动的。