首页 > 代码库 > 启动Activity时的方法调用(应用层)(MVC模式)
启动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; i<N; i++) {
final 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启动的Activity
if (!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<Activity> {
...
@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; i<N; i++) {
final 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.
* <p>
* 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。
启动Activity时的方法调用(应用层)(MVC模式)