启动Activity时的方法调用(应用层)(MVC模式)
一,从桌面启动应用
从桌面启动一个应用其实质也是从一个Activity中启动另一个Activity,比如官方的实例代码中:
android/platform_packages_apps_launcher
/** * 点击桌面图标启动Intent指向的Activity * * @param v The view representing the clicked shortcut. */ public void onClick(View v) { Object tag = v.getTag();//获取点击位置 if (tag instanceof ApplicationInfo) {//是ApplicationInfo的一个成员 // Open shortcut final Intent intent = ((ApplicationInfo) tag).intent; startActivitySafely(intent);//启动应用 } else if (tag instanceof FolderInfo) { handleFolderClick((FolderInfo) tag); } } void startActivitySafely(Intent intent) { intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); try { startActivity(intent); } catch (ActivityNotFoundException e) { Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show(); } catch (SecurityException e) { Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show(); e(LOG_TAG, "Launcher does not have the permission to launch " + intent + ". Make sure to create a MAIN intent-filter for the corresponding activity " + "or use the exported attribute for this activity.", e); } }
二,Activity内启动Activity
因为现在几乎都是从AppCompatActivity创建Activity,所以我们从AppCompatActivity开始分析。AppCompatActivity的类继承关系如下:
我们知道,如果从自己的Activity中调用startActivity()方法,系统会在类族中从下到上依次查找,直到遇到一个startActivity()为止,所以为了方便观察,先找出各类中启动startActivity方法和startActivityForResult方法(如果类中有的话):
AppCompatActivity中没有,它会向上查找父类FragmentActivity。
FragmentActivity中有一个startActivityForResult(Intent intent, int requestCode),并且在此方法中又super了此方法,所以它会在执行完后继续向上查找startActivityForResult(intent, requestCode)方法并执行:
/** * Modifies the standard behavior to allow results to be delivered to fragments. * This imposes a restriction that requestCode be <= 0xffff. */ @Override public void startActivityForResult(Intent intent, int requestCode) { // If this was started from a Fragment we've already checked the upper 16 bits were not in // use, and then repurposed them for the Fragment's index. if (!mStartedActivityFromFragment) { if (requestCode != -1) { checkForValidRequestCode(requestCode); } } super.startActivityForResult(intent, requestCode); }
FragmentActivity的直接父类是BaseFragmentActivityJB,在它的类中有一个startActivityForResult(Intent intent, int requestCode,
@Nullable Bundle options)方法,显然不是FragmentActivity中那个方法调用的,FragmentActivity会再继续向上查找startActivityForResult(intent, requestCode),BaseFragmentActivityJB中的这个方法同样也super了startActivityForResult(intent, requestCode, options):
@Override public void startActivityForResult(Intent intent, int requestCode, @Nullable Bundle options) { // If this was started from a Fragment we've already checked the upper 16 bits were not in // use, and then repurposed them for the Fragment's index. if (!mStartedActivityFromFragment) { if (requestCode != -1) { checkForValidRequestCode(requestCode); } } super.startActivityForResult(intent, requestCode, options); }
然后中间几个类就没有启动Activity的方法了,看Activity:
@Override public void startActivity(Intent intent) { this.startActivity(intent, null); }
@Override 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); } }
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode) { startActivityForResult(intent, requestCode, null); }
因为View一般是填充到Activity中去的,如果在View类中封装的事件中需要启动Activity,会需要传入Context,这个Context一般都是所在Activity赋予,所以这种情况下也是Activity中启动Activity,所以下面判断了是不是从UI中启动:
public void startActivityForResult(Intent intent, int requestCode, @Nullable Bundle options) { if (mParent == null) {//不是从UI中启动Activity //实现应用检测代码的基类,内部类.ActivityResult表示返回的Activity执行的结果 Instrumentation.ActivityResult ar = mInstrumentation.execStartActivity(//执行启动Activity this, mMainThread.getApplicationThread(), mToken, this, intent, requestCode, options); if (ar != null) { mMainThread.sendActivityResult(//主线程发送执行结果 mToken, mEmbeddedID, requestCode, ar.getResultCode(), ar.getResultData()); } if (requestCode >= 0) { // 如果这个开始请求一个结果, 我们可以禁止让这个activity 可见,直到收到返回结果。 // 设置这个代码使activity在 onCreate(Bundle savedInstanceState) 或者onResume() 期间处于隐藏状态,避免闪烁. // 只有在要求返回结果时才这么做,这样保证我们可以获得返回的信息,当activity结束,不管会发生什么。 mStartedActivity = true;//表示启动Activity } cancelInputsAndStartExitTransition(options); // TODO Consider clearing/flushing other event sources and events for child windows. } else { if (options != null) { mParent.startActivityFromChild(this, intent, requestCode, options); } else { // Note we want to go through this method for compatibility with // existing applications that may have overridden it. mParent.startActivityFromChild(this, intent, requestCode); } } }
在上面这个startActivityForResult中会判断是不是从界面中启动,不是则执行Instrumentation.execStartActivity,如果是则执行startActivityFromChild,Activity是UI:
public void startActivityFromChild(@NonNull Activity child, @RequiresPermission Intent intent, int requestCode) { startActivityFromChild(child, intent, requestCode, null); }
public void startActivityFromChild(@NonNull Activity child, @RequiresPermission Intent intent, int requestCode, @Nullable Bundle options) { Instrumentation.ActivityResult ar = mInstrumentation.execStartActivity( this, mMainThread.getApplicationThread(), mToken, child, intent, requestCode, options); if (ar != null) { mMainThread.sendActivityResult( mToken, child.mEmbeddedID, requestCode, ar.getResultCode(), ar.getResultData()); } cancelInputsAndStartExitTransition(options); }
startActivityFromChild中也是执行Instrumentation.execStartActivity,其有三个同名方法,一个执行的是来自Fragment,一个来自application的,还有一个是指定用户才可以调用的,这儿为第二个:
public ActivityResult execStartActivity( Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode, Bundle options) { IApplicationThread whoThread = (IApplicationThread) contextThread; Uri referrer = target != null ? target.onProvideReferrer() : null; if (referrer != null) { intent.putExtra(Intent.EXTRA_REFERRER, referrer); } if (mActivityMonitors != null) {//如果Activity监视器不为空 synchronized (mSync) { final int N = mActivityMonitors.size(); for (int i=0; ifinal ActivityMonitor am = mActivityMonitors.get(i); if (am.match(who, null, intent)) { am.mHits++; if (am.isBlocking()) {//如果是阻塞的,暂停状态的 return requestCode >= 0 ? am.getResult() : null;//如果有请求结果返回结果,如果没有返回null } break; } } } } try { intent.migrateExtraStreamToClipData(); intent.prepareToLeaveProcess(); int result = ActivityManagerNative.getDefault()//与ActivityManagerService通信启动Activity .startActivity(whoThread, who.getBasePackageName(), intent, intent.resolveTypeIfNeeded(who.getContentResolver()), token, target != null ? target.mEmbeddedID : null, requestCode, 0, null, options); checkStartActivityResult(result, intent); } catch (RemoteException e) { throw new RuntimeException("Failure from system", e); } return null; }
通过上面的方法可以得出,如果从我们继承自AppCompatActivit的Activity启动另一个Activity,程序执行的步骤:
结合代码可以看到从AppCompatActivity调用的startActivityForResult只是比从Activity中调用的多了以下这段代码:
//如果不是从Fragmengt启动的Activityif (!mStartedActivityFromFragment) { if (requestCode != -1) {//如果请求码不是-1 checkForValidRequestCode(requestCode);//检查给定的请求码是否有效 } }
来自BaseFragmentActivityEclair:
static void checkForValidRequestCode(int requestCode) { if ((requestCode & 0xffff0000) != 0) { throw new IllegalArgumentException("Can only use lower 16 bits for requestCode");//请求码不能超过16位 } }
三,Fragment中启动Activity
在Fragment中有启动Activity的方法,可以通过它启动Activity,但在android.app包和android.support.v4.app包两个包中都Fragment类,这时就得分情况了,使用哪个包中的就导入哪个包中的Fragment。
导入android.app.Fragment
调用android.app.Fragment中的startActivity或startActivityForResult:
/** * Call {@link Activity#startActivity(Intent)} from the fragment's * containing Activity. */ public void startActivity(Intent intent) { startActivity(intent, null); } /** * Call {@link Activity#startActivity(Intent, Bundle)} from the fragment's * containing Activity. */ public void startActivity(Intent intent, @Nullable Bundle options) { if (mHost == null) { throw new IllegalStateException("Fragment " + this + " not attached to Activity"); } mHost.onStartActivityFromFragment(this /*fragment*/, intent, -1, options); }
/** * Call {@link Activity#startActivityForResult(Intent, int)} from the fragment's * containing Activity. */ public void startActivityForResult(Intent intent, int requestCode) { startActivityForResult(intent, requestCode, null); } /** * Call {@link Activity#startActivityForResult(Intent, int, Bundle)} from the fragment's * containing Activity. */ public void startActivityForResult(Intent intent, int requestCode, @Nullable Bundle options) { if (mHost == null) { throw new IllegalStateException("Fragment " + this + " not attached to Activity"); } mHost.onStartActivityFromFragment(this /*fragment*/, intent, requestCode, options); }
可以看出startActivity和startActivityForResult调用的都是FragmentHostCallback.onStartActivityFromFragment,FragmentHostCallback是抽象类,Activity类中的内部类HostCallbacks是它的实现类:
class HostCallbacks extends FragmentHostCallback {... @Override public void onStartActivityFromFragment(Fragment fragment, Intent intent, int requestCode, Bundle options) { Activity.this.startActivityFromFragment(fragment, intent, requestCode, options); }...}
Activity.startActivityFromFragment:
public void startActivityFromFragment(@NonNull Fragment fragment, @RequiresPermission Intent intent, int requestCode) { startActivityFromFragment(fragment, intent, requestCode, null); } public void startActivityFromFragment(@NonNull Fragment fragment, @RequiresPermission Intent intent, int requestCode, @Nullable Bundle options) { startActivityForResult(fragment.mWho, intent, requestCode, options); }
它又调用Activity类的隐藏方法startActivityForResult:
/** * @hide */ @Override public void startActivityForResult( String who, Intent intent, int requestCode, @Nullable Bundle options) { Uri referrer = onProvideReferrer(); if (referrer != null) { intent.putExtra(Intent.EXTRA_REFERRER, referrer); } Instrumentation.ActivityResult ar = mInstrumentation.execStartActivity( this, mMainThread.getApplicationThread(), mToken, who, intent, requestCode, options); if (ar != null) { mMainThread.sendActivityResult( mToken, who, requestCode, ar.getResultCode(), ar.getResultData()); } cancelInputsAndStartExitTransition(options); }
然后最终调用Instrumentation.execStartActivity,Fragment使用的这个方法和Activity使用的同名方法的第4个参数不同,虽然含义相同:
public ActivityResult execStartActivity( Context who, IBinder contextThread, IBinder token, String target, Intent intent, int requestCode, Bundle options) { IApplicationThread whoThread = (IApplicationThread) contextThread; if (mActivityMonitors != null) { synchronized (mSync) { final int N = mActivityMonitors.size(); for (int i=0; ifinal ActivityMonitor am = mActivityMonitors.get(i); if (am.match(who, null, intent)) { am.mHits++; if (am.isBlocking()) { return requestCode >= 0 ? am.getResult() : null; } break; } } } } try { intent.migrateExtraStreamToClipData(); intent.prepareToLeaveProcess(); int result = ActivityManagerNative.getDefault() .startActivity(whoThread, who.getBasePackageName(), intent, intent.resolveTypeIfNeeded(who.getContentResolver()), token, target, requestCode, 0, null, options); checkStartActivityResult(result, intent); } catch (RemoteException e) { throw new RuntimeException("Failure from system", e); } return null; }
流程可以简洁表示如下:
相关类图:
这儿使用了MVC架构,
;FragmentHostCallback类组为模型模块;Activity作为视图模块。
MVC架构模式
方便理解,特意百度图片:
模型(Model) “数据模型”(Model)用于封装与应用程序的业务逻辑相关的数据以及对数据的处理方法。“模型”有对数据直接访问的权力,例如对数据库的访问。“模型”不依赖“视图”和“控制器”,也就是说,模型不关心它会被如何显示或是如何被操作。但是模型中数据的变化一般会通过一种刷新机制被公布。为了实现这种机制,那些用于监视此模型的视图必须事先在此模型上注册,从而,视图可以了解在数据模型上发生的改变。(比较:观察者模式(软件设计模式))
这儿是把Fragment当作数据,FragmentHostCallback类组对Fragment进行业务处理的封装,其子类HostCallbacks是Activity的内部类,并对Activity中的一些方法进行调用(放在Activity中方便外部调用):
class HostCallbacks extends FragmentHostCallback<Activity> { public HostCallbacks() { super(Activity.this /*activity*/); } @Override public void onDump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) { Activity.this.dump(prefix, fd, writer, args); } FragmentHostCallback(Activity activity) { this(activity, activity /*context*/, activity.mHandler, 0 /*windowAnimations*/); } @Override public void onStartActivityFromFragment(Fragment fragment, Intent intent, int requestCode, Bundle options) { Activity.this.startActivityFromFragment(fragment, intent, requestCode, options); }...}
视图(View) 视图层能够实现数据有目的的显示(理论上,这不是必需的)。在视图中一般没有程序上的逻辑。为了实现视图上的刷新功能,视图需要访问它监视的数据模型(Model),因此应该事先在它监视的数据模型那里注册。
Activity类此时在这儿充当视图层,如上在HostCallbacks的构造器中设置了模型关联的activity及上下文环境activity。Activity对控制器FragmentController进行引用,并进行一些方法调用:
final FragmentController mFragments = FragmentController.createController(new HostCallbacks());...mFragments.dispatchResume();mFragments.execPendingActions();
控制器(Controller) 控制器起到不同层面间的组织作用,用于控制应用程序的流程。它处理事件并作出响应。“事件”包括用户的行为和数据模型上的改变。
FragmentController和FragmentManager共同组成了控制器模块,FragmentController通过FragmentHostCallback.getFragmentManagerImpl()获得FragmentManager,然后共同对FragmentHostCallback进行控制,间接对Activity发挥作用:
/**意思是与FragmentManager一块为fragment宿主提供一个关键点,响应宿主管理fragment的生命周期。 * Provides integration points with a {@link FragmentManager} for a fragment host. * * It is the responsibility of the host to take care of the Fragment's lifecycle. * The methods provided by {@link FragmentController} are for that purpose. */
public class FragmentController { private final FragmentHostCallback<?> mHost; /** * Returns a {@link FragmentController}. */ public static final FragmentController createController(FragmentHostCallback<?> callbacks) { return new FragmentController(callbacks); } private FragmentController(FragmentHostCallback<?> callbacks) { mHost = callbacks; }
MVC模式根据情景不同,可能会有好几个嵌套,一个类会充当好几个角色。现在应用中比较流行切某些场合下更好的是MVP模式,所以了解即可。
导入android.support.v4.app.Fragment
使用android.support.v4.app.Fragment会和使用android.app.Fragment之间有稍微的差异。
android.support.v4.app.Fragment启动Activity的方法和android.app.Fragment中的代码相同,这里略。
调用的都是FragmentHostCallback.onStartActivityFromFragment,这儿的FragmentHostCallback也是抽象类,但和那个不是一个类,虽然类名相同,但所在不是同一个包(这部分的Fragment相关类在android.support.v4.app包中),它的实现类是FragmentActivity类中的内部类HostCallbacks:
@Override public void onStartActivityFromFragment(Fragment fragment, Intent intent, int requestCode) { FragmentActivity.this.startActivityFromFragment(fragment, intent, requestCode); } @Override public void onStartActivityFromFragment( Fragment fragment, Intent intent, int requestCode, @Nullable Bundle options) { FragmentActivity.this.startActivityFromFragment(fragment, intent, requestCode, options); }
都是调用FragmentActivity.startActivityFromFragment(参数不同):
/** * Called by Fragment.startActivityForResult() to implement its behavior. */ public void startActivityFromFragment(Fragment fragment, Intent intent, int requestCode) { startActivityFromFragment(fragment, intent, requestCode, null); } /** * Called by Fragment.startActivityForResult() to implement its behavior. */ public void startActivityFromFragment(Fragment fragment, Intent intent, int requestCode, @Nullable Bundle options) { mStartedActivityFromFragment = true; try { if (requestCode == -1) { ActivityCompat.startActivityForResult(this, intent, -1, options); return; } checkForValidRequestCode(requestCode); int requestIndex = allocateRequestIndex(fragment); ActivityCompat.startActivityForResult( this, intent, ((requestIndex + 1) << 16) + (requestCode & 0xffff), options); } finally { mStartedActivityFromFragment = false; } }
ActivityCompat.startActivityForResult:
public static void startActivityForResult(Activity activity, Intent intent, int requestCode, @Nullable Bundle options) { if (Build.VERSION.SDK_INT >= 16) { ActivityCompatJB.startActivityForResult(activity, intent, requestCode, options); } else { activity.startActivityForResult(intent, requestCode); } }
如果版本大于等于16,调用ActivityCompatJB.startActivityForResult,否则调用宿主activity的startActivityForResult(intent, requestCode),ActivityCompatJB.startActivityForResult:
public static void startActivityForResult(Activity activity, Intent intent, int requestCode, Bundle options) { activity.startActivityForResult(intent, requestCode, options); }
宿主activity即是FragmentActivity或其子类,调用的是FragmentActivity.startActivityForResult。
@Override public void startActivityForResult(Intent intent, int requestCode) { // If this was started from a Fragment we've already checked the upper 16 bits were not in // use, and then repurposed them for the Fragment's index. if (!mStartedActivityFromFragment) { if (requestCode != -1) { checkForValidRequestCode(requestCode); } } super.startActivityForResult(intent, requestCode); }
后面略,请参考前面Activity中启动Activity.相关类关系和前面Fragment类关系相似,也不重复了。
附:app包中的fragment和v4包中的fragment的相关使用
1,app包中的fragment,因为这个是在3.0之后才有的,支持3.0以后的版本,如果需要支持更低版本,需要使用v4包中的fragment。’这两个类功能几乎一样,都是可以使用标签,区别是导入包时的包名是不一样的。对应的方法名类似,不尽相同,实现过程也有点差异,所以如果用混了会报错。
2,因为现在大部分都是基于AppCompatActivity使用Fragment,所以在Fragment中启动Activity如果要求返回结果,如果导入的是app包中的fragment,则有两种实现方案:
第一种:调用Fragment的startActivityForResult方法,然后在Fragment的onActivityResult的方法中处理返回的请求。
第二种:在Fragment中通过getActivity()方法获取到Fragment所在的FragmentActivity对象,调用activity对象的startActivityForResult方法启动Activity,然后在FragmentActivity的onActivityResult的方法中处理返回的请求。
四,其它组件中启动Activity
其他组件还可以启动Activity的有Service和Broadcast Receiver,他们都是脱Activity运行的。
在Service中可以直接调用startActivity(因为Service是Context的一个子类),Broadcast Receiver调用Context.startActivity,此时它们调用的方法实现都是ContextImpl.startActivity:
@Override public void startActivity(Intent intent) { warnIfCallingFromSystemProcess(); startActivity(intent, null); } @Override public void startActivity(Intent intent, Bundle options) { warnIfCallingFromSystemProcess(); if ((intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) { throw new AndroidRuntimeException( "Calling startActivity() from outside of an Activity " + " context requires the FLAG_ACTIVITY_NEW_TASK flag." + " Is this really what you want?"); } mMainThread.getInstrumentation().execStartActivity( getOuterContext(), mMainThread.getApplicationThread(), null, (Activity) null, intent, -1, options); }
可以看到这儿有个判断intent中是否有个Intent.FLAG_ACTIVITY_NEW_TASK标志,如果没有就报错。在service中启动示例:
Intent intent=new Intent(getApplicationContext(),AnotherActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent);
Broadcast Receiver同理。
五,最后附上一张图
注:这里都是用Intent传递信息,还可以使用PendingIntent。
更多相关文章
- Android(安卓)7.0 Launcher3的启动和加载流程分析----转载
- android ViewGroup删除子视图时应该注意的一个问题
- Android之Service组件
- Android(安卓)Parcel和Parcelable类
- 判断应用或Activity是否存在
- 【Android界面实现】Starting an Activity(Activity生命周期金字
- 第三部分 MediaPlayer的主要实现分析
- Android设置Dialog透明度、黑暗度方法
- RecyclerView 中 item 点击事件的优化