本文将对Activity的工作过程进行分析。
主要学习以下内容:
(1)系统内部是如何启动一个Activity的
(2)新Activity的对象是何时创建的
(3)Activity的各个生命周日是被系统何时回调的
Activity启动流程分两种,一种是启动正在运行的app的Activity,即启动子Activity。如无特殊声明默认和启动该activity的activity处于同一进程。如果有声明在一个新的进程中,则处于两个进程。另一种是打开新的app,即为Launcher启动新的Activity。后边启动Activity的流程是一样的,区别是前边判断进程是否存在的那部分。
Activity的启动流程整体如下:
一Activity启动阶段
(一)涉及到的概念
进程:Android系统为每个APP分配至少一个进程
IPC:跨进程通信,Android中采用Binder机制。
(二)涉及到的类
ActivityStack:Activity在AMS的栈管理,用来记录已经启动的Activity的先后关系,状态信息等。通过ActivityStack决定是否需要启动新的进程。
ActivitySupervisor:管理 activity 任务栈
ActivityThread:ActivityThread 运行在UI线程(主线程),App的真正入口。
ApplicationThread:用来实现AMS和ActivityThread之间的交互。
ApplicationThreadProxy:ApplicationThread 在服务端的代理。AMS就是通过该代理与ActivityThread进行通信的。
IActivityManager:继承与IInterface接口,抽象出跨进程通信需要实现的功能
AMN:运行在server端(SystemServer进程)。实现了Binder类,具体功能由子类AMS实现。
AMS:AMN的子类,负责管理四大组件和进程,包括生命周期和状态切换。AMS因为要和ui交互,所以极其复杂,涉及window。
AMP:AMS的client端代理(app进程)。了解Binder知识可以比较容易理解server端的stub和client端的proxy。AMP和AMS通过Binder通信。
Instrumentation:仪表盘,负责调用Activity和Application生命周期。测试用到这个类比较多。
(三)涉及到的进程
(1)Launcher所在的进程
(2)AMS所在的SystemServer进程
(3)要启动的Activity所在的app进程
如果是启动根Activity,就涉及上述三个进程。
如果是启动子Activity,那么就只涉及AMS进程和app所在进程。
(四)具体流程
Launcher:Launcher通知AMS要启动activity。
startActivitySafely->startActivity->InstrumentationexecStartActivity()(AMPstartActivity)->AMSstartActivity
AMS:PMS的resoveIntent验证要启动activity是否匹配。如果匹配,通过ApplicationThread发消息给Launcher所在的主线程,暂停当前Activity(即Launcher)。
暂停完,在该activity还不可见时,通知AMS,根据要启动的Activity配置ActivityStack。然后判断要启动的Activity进程是否存在
存在:发送消息LAUNCH_ACTIVITY给需要启动的Activity主线程,执行handleLaunchActivity
不存在:通过socket向zygote请求创建进程。进程启动后,ActivityThreadattach
判断Application是否存在,若不存在,通过LoadApkmakeApplication创建一个。在主线程中通过threadattach方法来关联ApplicationThread。
在通过ActivityStackSupervisor来获取当前需要显示的ActivityStack。
继续通过ApplicationThread来发送消息给主线程的Handler来启动Activity (handleLaunchActivity)。
handleLauchActivity:调用了performLauchActivity,里边Instrumentation生成了新的activity对象,继续调用activity生命周期。
IPC过程:
双方都是通过对方的代理对象来进行通信。
1app和AMS通信:app通过本进程的AMP和AMS进行Binder通信
2AMS和新app通信:通过ApplicationThreadProxy来通信,并不直接和ActivityThread通信
(五)参考函数流程
Activity启动流程(从Launcher开始):
第一阶段: Launcher通知AMS要启动新的Activity(在Launcher所在的进程执行)
第二阶段:AMS先校验一下Activity的正确性,如果正确的话,会暂存一下Activity的信息。然后,AMS会通知Launcher程序pause Activity(在AMS所在进程执行)
第三阶段:pause Launcher的Activity,并通知AMS已经paused(在Launcher所在进程执行)
第四阶段:检查activity所在进程是否存在,如果存在,就直接通知这个进程,在该进程中启动Activity;不存在的话,会调用Processstart创建一个新进程(执行在AMS进程)
第五阶段: 创建ActivityThread实例,执行一些初始化 *** 作,并绑定Application。如果Application不存在,会调用LoadedApkmakeApplication创建一个新的Application对象。之后进入Loop循环。(执行在新创建的app进程)
第六阶段:处理新的应用进程发出的创建进程完成的通信请求,并通知新应用程序进程启动目标Activity组件(执行在AMS进程)
第七阶段: 加载MainActivity类,调用onCreate声明周期方法(执行在新启动的app进程)
从另一个角度下图来概括:
下面简要介绍一下启动的过程:
Step 1 无论是通过Launcher来启动Activity,还是通过Activity内部调用startActivity接口来启动新的Activity,都通过Binder进程间通信进入到ActivityManagerService进程中,并且调用ActivityManagerServicestartActivity接口;
Step 2 ActivityManagerService调用ActivityStackstartActivityMayWait来做准备要启动的Activity的相关信息;
Step 3 ActivityStack通知ApplicationThread要进行Activity启动调度了,这里的ApplicationThread代表的是调用ActivityManagerServicestartActivity接口的进程,对于通过点击应用程序图标的情景来说,这个进程就是Launcher了,而对于通过在Activity内部调用startActivity的情景来说,这个进程就是这个Activity所在的进程了;
Step 4 ApplicationThread不执行真正的启动 *** 作,它通过调用ActivityManagerServiceactivityPaused接口进入到ActivityManagerService进程中,看看是否需要创建新的进程来启动Activity;
Step 5 对于通过点击应用程序图标来启动Activity的情景来说,ActivityManagerService在这一步中,会调用startProcessLocked来创建一个新的进程,而对于通过在Activity内部调用startActivity来启动新的Activity来说,这一步是不需要执行的,因为新的Activity就在原来的Activity所在的进程中进行启动;
Step 6 ActivityManagerServic调用ApplicationThreadscheduleLaunchActivity接口,通知相应的进程执行启动Activity的 *** 作;
Step 7 ApplicationThread把这个启动Activity的 *** 作转发给ActivityThread,ActivityThread通过ClassLoader导入相应的Activity类,然后把它启动起来。
MainActivity 通过 startActivityForResult 启动 MainActivity2 ,同时传递一个 Bundle 对象给 MainActivity2 ,在 MainActivity2 中通过 getIntent 获取到传递过来的 Bundle ,进而得到 MainActivity 传递过来的String 数据并打印。
在 MainActivity2 中通过 setResult 设置需要传递给 MainActivity 的 Bundle 数据,在 MainActivity 的 onActivityResult 函数中就可以得到相关的 Bundle 数据。
每一个Android应用都有一个 Application 对象,这个 Application 会贯穿整个Android应用,在其中定义的变量,它的生命周期也是和整个应用的生命周期一样。
在 MainActivity 中定义了一个 伴生变量 ,它相当于 Java中的静态变量 ,而在 MainActivity2 中可以获取此静态变量,并对其进行修改。
通过 Fragment 的 setArguments(bundle) 实现 Activity 想 Fragment 传值。
通过 onAttach(activity: Activity) 方法获得 activity 实例,直接调用 activity 中的方法获得数据。
Service 的 onBind 方法需要返回一个 Binder 对象,而这个对象在 ServiceConnectiononServiceConnected 中可以获取,从而实现 Service 和 Activity 之间的通信。
startService 时,传入参数 intent 可以携带部分参数给 Service ,我们可以在 Service 的 onStartCommand 方法中得到 startService 传递过来的 intent 数据。
在service中持有 callback 接口,并在binder中定义方法得到service的实例。activity中实现 ServiceConnection ,通过绑定启动service,这样会回调 ServiceConnection 接口的 onServiceConnected 方法,从而得到service实例,对service中的 callback 进行赋值,在service中可进行耗时 *** 作并见数据通过callback接口,传递给activity进行其他 *** 作。
除了上面说的常用方法外,还有很多其他方法,比如广播机制,事件总汇(eventbus)等。
// 获得PackageManager对象
PackageManager pm = contextgetPackageManager();
ActivityManager am = (ActivityManager) context
getSystemService(ContextACTIVITY_SERVICE);
List<RunningTaskInfo> tasks = amgetRunningTasks(100);
if (!tasksisEmpty()) {
ComponentName topActivity = tasksget(0)topActivity;
for (RunningTaskInfo info : tasks) {
// 查询这个后台任务的 启动Activity
Intent mainIntent = new Intent(IntentACTION_MAIN);
mainIntentsetPackage(topActivitygetPackageName());
mainIntentaddCategory(IntentCATEGORY_LAUNCHER);
// 通过查询,获得所有ResolveInfo对象
List<ResolveInfo> resolveInfos = pmqueryIntentActivities(
mainIntent, PackageManagerMATCH_DEFAULT_ONLY);
ResolveInfo reInfo = resolveInfosget(0);
// 获得该应用程序的启动Activity的name
String activityName = reInfoactivityInfoname;
// 获得应用程序的包名
String pkgName = reInfoactivityInfopackageName;
// 获得应用程序的Label
String appLabel = (String) reInfoloadLabel(pm);
Drawable icon = reInfoloadIcon(pm); // 获得应用程序图标
// 为应用程序的启动Activity 准备Intent
Intent launchIntent = new Intent();
launchIntentsetComponent(new ComponentName(pkgName,
activityName));
}
}
MainActivity继承的父类AppCompatActivity是有版本Android限制的,低于多少版本不支持,具体你去查一下,这边没有找到支持的依赖包。看报错信息也是没有版本支持,可能你的项目配置信息没弄好,重新梳理一下,把sdk的版本和支持依赖包版本统一适配起来。
functionselection_sort($array){
$count=count($array);
for($i=0;$i<$count-1;$i++){
/findtheminest/
$min=$i;
echo'$min-->'$array[$min]'-->';
for($j=$i+1;$j<$count;$j++){
//由小到大排列
if($array[$min]>$array[$j]){
//表明当前最小的还比当前的元素大
$min=$j;
//赋值新的最小的
}
}
echo$array[$min]'coco<br/>';
/swap$array[$i]and$array[$min]即将当前内循环的最小元素放在$i位置上/
if($min!=$i){
$temp=$array[$min];
$array[$min]=$array[$i];
$array[$i]=$temp;
}
}
return$array;
}
$old_array=array(3,4,5,6,8,2,12);
$new_array=selection_sort($old_array);
print_r($new_array);
使用Broadcast广播即可
android系统中,BroadcastReceiver的设计初衷就是从全局考虑的,可以方便应用程序和系统、应用程序之间、应用程序内的通信
在获取消息activity中建立BroadcastReceiver内部类,并且注册广播
示例代码如下
//接受消息的activitypublic class MainActivity extends Activity {
private InnerReceiver receiver = new InnerReceiver();
@Override
protected void onCreate(Bundle savedInstanceState) {
superonCreate(savedInstanceState);
setContentView(Rlayoutactivity_main);
}
@Override
protected void onRestart() {
superonRestart();
//注册广播
IntentFilter filter = new IntentFilter("test");
registerReceiver(receiver, filter);
}
@Override
protected void onStop() {
superonStop();
取消广播
unregisterReceiver(receiver);
}
public class InnerReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
//使用intent获取发送过来的数据
String msg = intentgetStringExtra("msg");
}
}
}package comexampledemo;
import androidappActivity;
import androidcontentIntent;
import androidosBundle;
import androidviewView;
import androidviewViewOnClickListener;
import androidwidgetButton;
import androidwidgetEditText;
//发送消息的activity
public class SendActivity extends Activity {
private Button btn;
private EditText text;
@Override
protected void onCreate(Bundle savedInstanceState) {
superonCreate(savedInstanceState);
setContentView(Rlayoutactivity_main);
btn = (Button)findViewById(Ridbutton);
text = (EditText)findViewById(Ridtext);
btnsetOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent("test");
intentputExtra("msg", textgetText()toString());
sendBroadcast(intent);
}
});
}
}
以上就是关于全面解析Activity: Activity的工作过程全部的内容,包括:全面解析Activity: Activity的工作过程、Android四大组件之Activity(2)组件间通信、Android 有没有什么方法能够得到所有正在后台运行的Activity。等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)