学习资料:
- Android开发艺术探索
- 罗升阳大神的Android应用程序的Activity启动过程简要介绍和学习计划
本篇是个挖坑之作,步子跨得太大扯着了。不知天高地厚地开始学习后,发现涉及到很多暂时无法理解的东西。遂,中道崩殂,哈哈:),估计明年这个时候才能补充了
Android——Activity学习(上)学习了Activity
的生命周期,启动模式,任务栈,本篇进行学习工作过程
对于用户来说,一个APP
能够感知的就是一个Activity
,四大组件的其他三位,都是在后台运行的,用户是看不到的,不可感知的。根据上篇的学习,Activity
有不同的启动模式,启动方式也可以分为显示Intent
和隐式Intent
,finish()
方法可以结束一个组件的运行。
1. 工作过程 <p>
在一个现有Activity_A
中,经常会使用一个Intent
来开启一个Activity_B
Intent intent = new Intent(Activity_A.this,Activity_B.class);
startActivity(intent);
startActivity()
方法可以作为学习的入口点
扫了一眼Activity源码的行数,加上注释7177行,相对于View的23000行来说,小巫见大巫。最近一段时间的学习,感觉最明显的变化便是看源码时的心态。然而也仅仅是心态有了点朝好的趋势发展,阅读代码的能力还是渣
1.1 startActivity() 开启Activity<p>
有两种重载重载方式,startActivity(Intent intent)
内部调用了startActivity(Intent intent, @Nullable Bundle options)
@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);
}
}
最终两种形式的startActivity()
方法都会调用startActivityForResult()
方法
Activity_A
并不知道Activity_B
的存在,但Activity_A
通过使用Intent
来启动Activity_B
,显式是通过指定类对象,隐式则更加显得强大,通过在AndroidManifest.xml
清单文件中使用的action
指定的Activity_B
的名字来启动。这个设计使Activity
耦合性很松散,模块化程度更高,之后维护和升级也更加方便些。
1.2 startActivityForResult()带有返回结果的开启Activity <p>
方法源码:
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,@Nullable Bundle options) {
if (mParent == null) {//mParent是ActvityGroup,API13后废弃,推荐由Framgment代替
Instrumentation.ActivityResult ar = mInstrumentation.execStartActivity(this, mMainThread.getApplicationThread(), mToken, this,
intent, requestCode, options);
if (ar != null) {
mMainThread.sendActivityResult(mToken, mEmbeddedID, requestCode, ar.getResultCode(),
ar.getResultData());
}
if (requestCode >= 0) {//当前Activity返回一个result,无论它发生了什么
mStartedActivity = true;
}
cancelInputsAndStartExitTransition(options);
// TODO Consider clearing/flushing other event sources and events for child windows.
} else {//mParent不为null
if (options != null) {
mParent.startActivityFromChild(this, intent, requestCode, options);
} else {兼容重载方法,以确保重载方法可以使用
mParent.startActivityFromChild(this, intent, requestCode);
}
}
}
上面的代码需要重点关注mParent==null
部分内的的逻辑,mParent
是一个ActivityGroup
,只是在API13
之后,被废弃,系统推荐另外一个坑,Frrgment
来替代。
mInstrumentation
是Activity
类中的一个成员变量,Instrumentation
可以看作是APP
和系统之间的监控器,用来监控应用程序和系统间的交互
mMainThread
类型是ActivityThread
,这里代表的就是程序的主线程。mMainThread.getApplicationThread()
获得是一个ActivityThread
的内部类ApplicationThread
对象。在Android
应用程序中,每一个进程就用一个ActivityThread
实例对象来表示
本篇博客学习挖的1号坑——
ActivityThread
,暂时不理解它的工作过程
1.3 Instrumentation的execStartActivity()方法 <p>
源码:
public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode) {
IApplicationThread whoThread = (IApplicationThread) contextThread;
if (mActivityMonitors != null) {...}
try {
int result = ActivityManagerNative.getDefault()
.startActivity(whoThread,intent,intent.resolveTypeIfNeeded(who.getContentResolver()), null, 0, token, target != null ? target.mEmbeddedID : null, requestCode, false, false); //才真正开始开启Activity
checkStartActivityResult(result, intent);//检查异常
} catch (RemoteException e) {
}
return null;
}
整个方法内关键之处在于ActivityManagerNative.getDefault().startActivity(...)
,真正启动一个Activity
便是这行代码。
ActivityManagerNative.getDefault()
返回的结果是一个IActivityManager
,是一个接口。ActivityManagerNative(AMN)
是ActivityManagerService(AMS)
的父类,AMN
继承之Binder
并实现了IActivityManager
这个Binder
接口,因此AMS
也是一个Binder
,它是IAcitityManager
的具体实现。由于ActivityManagerNative.getDefault()
结果其实是一个IActivityManager
类型的Binder
对象,最终的具体实现是AMS
,所以Activity
的启动也就转移到了AMS
中的startActivity()
方法。
checkStartActivityResult(result,intent)
用于检查启动Activity
的结果,当无法正常开启一个Activity
时,就会抛出一个异常。例如,一个Activity
没有在AnroidManifest.xml
中注册时,便会抛出:
Unable to find explict activity class ;
have you declared this activity in your AndroidManifest.xml ?
2号大坑——Binder,任教主推荐了两篇,Android深入浅出之Binder机制和Android Bander设计与实现 - 设计篇 ,一脸懵逼,属于有生年看懂系列
接下来看AMS
的startActivity()
方法
1.4 AMS的startActivity()方法
源码:
卒...
感觉再看下去属于浪费时间,再储备点知识后,再来学习
2. 最后 <p>
尺度太大,学不动,先放弃,这次学习没把握好尺度
写博客以来,第一次中途放弃,实在没有啥效率
2016.10.14 16:28
共勉 :)