Activity组件简析
发布日期:2021-05-07 13:27:21 浏览次数:22 分类:精选文章

本文共 11622 字,大约阅读时间需要 38 分钟。

本文学习拜读自罗升阳老师的《Android系统源代码情景分析》

本文实验环境为 Android6.0

一 概述
二 Activity组件应用实例(隐式)
  • 2.1 MainActivity.java
  • 2.2 SubActivityInProcess.java
  • 2.3 SubActivityInNewProcess.java
  • 2.4 配置
    • 2.4.1 main.xml
    • 2.4.2 sub.xml
    • 2.4.3 strings.xml
    • 2.2.4 icon.png
    • 2.4.5 AndroidManifest.xml
    • 2.4.6
三 Activity组件的启动过程

待续…


一 概述

Activity是Android应用程序的四大组件之一,他负责管理Android应用程序的用户界面。一个应用程序一般会包含若干个Activity组件,每一个Activity组件负责一个用户界面的展现,它们可能运行在同一个进程中,也可能运行在不同的进程中。运行在不同的进程中的Actity组件通过Binder进程间通信机制来协作完成应用程序的功能。

从应用程序的角度出发,我们可以将Activity组件划分为两种类型:一种是根Activity,另一种是子Activity。根Activity以跨界图标的形式显示在应用程序启动器中,它的启动过程就代表了一个Android应用程序的启动过程。子Activity由根Activity或者其他子Activity启动,它们有可能与启动它们的Activity运行在同一个进程中,也有可能运行在不同的进程中,这取决于它们的配置和启动参数。

Android组件的启动方式分为显示和隐式两种,对于显示启动Activity组件来说,我么必须事先知道用来实现它们类的名称。对于隐式启动Activity来说,我们只需要知道它们组件的名称即可,而不需要知道它们是由哪一个类来实现的。无论是显示启动Activity组件,还是隐式启动Activity组件,它们的启动过程都是类似的,唯一的区别在于系统是根据类名还是组件名称

来找到它们。但是从软件工程的角度来看,隐式启动Activity组件可以减少Android应用程序组件间的依赖,因此,本文主要分析Activity隐式。

二 Activity组件应用实例(隐式)

在本文中,我们将开发一个名称为 Activity 的 Android应用程序,他由三个Activity组件 MainActivity、SubActivityInProcess和SubActivityInNewProcess组成,其中MainActivity是跟Activity,SubActivityInProcess和SubActivityInNewProcess是子Activity。SubActivityInProcess与MainActivity运行在同一个进程中,而SubActivityInNewProcess运行在一个独立的进程中。

应用程序 Activity 的目录结构如下:

Android/packages/apps/Activity-----AndroidManifest.xml-----Android.mk-----src	-----com/android/activity		-----MainActivity.java		-----SubActivityInProcess.java		-----SubActivityInNewProcess.java-----res	-----layout		-----main.xml		-----sub.xml	-----values		-----strings.xml	-----drawable		-----icon.png
2.1 MainActivity.java

MainActivity是应用程序 Activity的根Activity组件,它的用户界面有两个按钮,分别用来启动 SubActivityInProcess和SubActivityInNewProcess这两个子Activity。SubActivityInProcess和SubActivityInNewProcess的组件名称分别被配置为 “haoran.ma.activity.in.process” 和 “haoran.ma.activity.in.new.process” ,因此代码中调用 startActivity()启动它们时,只需要分别指定这两个名称即可,而不需要知道它们是哪一个类实现的。

package com.android.activity; import android.app.Activity;import android.content.Intent;import android.os.Bundle;	import android.util.Log;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button; public class MainActivity extends Activity  implements OnClickListener {	private final static String LOG_TAG = "haoran.ma.activity.MainActivity"; 	private Button startInProcessButton = null;	private Button startInNewProcessButton = null;		@Override	public void onCreate(Bundle savedInstanceState) {		super.onCreate(savedInstanceState);		setContentView(R.layout.main); 		startInProcessButton = (Button)findViewById(R.id.button_start_in_process);		startInNewProcessButton = (Button)findViewById(R.id.button_start_in_new_process);		startInProcessButton.setOnClickListener(this);		startInNewProcessButton.setOnClickListener(this); 		Log.i(LOG_TAG, "Main Activity Created.");	} 	@Override	public void onClick(View v) {		if(v.equals(startInProcessButton)) {			Intent intent = new Intent("haoran.ma.activity.subactivity.in.process");			startActivity(intent);		}else if(v.equals(startInNewProcessButton)){			Intent intent = new Intent("haoran.ma.activity.subactivity.in.new.process");			startActivity(intent);		}	}}
2.2 SubActivityInProcess.java

SubActivityInProcess是应用程序 Activity 的一个子 Activity组件,它是由 MainActivity组件启动起来的,当我们点击它的用户界面上的一个 finish按钮时,就可以返回到 MainActivity 组件中。

package com.android.activity; import android.app.Activity;import android.os.Bundle;import android.util.Log;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button; public class SubActivityInProcess extends Activity implements OnClickListener {	private final static String LOG_TAG = "haoran.ma.activity.SubActivityInProcess"; 	private Button finishButton = null; 	@Override	public void onCreate(Bundle savedInstanceState) {		super.onCreate(savedInstanceState);		setContentView(R.layout.sub); 		finishButton = (Button)findViewById(R.id.button_finish);		finishButton.setOnClickListener(this);				Log.i(LOG_TAG, "Sub Activity In Process Created.");	} 	@Override	public void onClick(View v) {		if(v.equals(finishButton)) {			finish();		}	}}
2.3 SubActivityInNewProcess.java

SubActivityInNewProcess是应用程序Activity的另外一个子Activity组件,它也是由MainActivity组件启动起来的,不过它是在一个新的进程中启动,当我们点击它的用户界面 finish时候,同样可以返回MainActivity组件中。

package com.android.activity;import android.app.Activity;import android.os.Bundle;import android.util.Log;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button; public class SubActivityInNewProcess extends Activity implements OnClickListener {	private final static String LOG_TAG = "haoran.ma.activity.SubActivityInNewProcess";	private Button finishButton = null; 	@Override	public void onCreate(Bundle savedInstanceState) {		super.onCreate(savedInstanceState);		setContentView(R.layout.sub); 		finishButton = (Button)findViewById(R.id.button_finish);		finishButton.setOnClickListener(this);				Log.i(LOG_TAG, "Sub Activity In New Process Created.");	} 	@Override	public void onClick(View v) {		if(v.equals(finishButton)) {			finish();		}	}}
2.4 配置
2.4.1 main.xml

这是 MainActivity组件的界面配置文件,它在屏幕中间显示两个按钮

android:orientation=“vertical” :指定是 垂直布局

android:gravity=“center”> :指的是上下居中

2.4.2 sub.xml

这是 SubActivityInProcess组件和SubActivityInNewProcess组件的界面配置文件,它在屏幕中间显示一个按钮。

2.4.3 strings.xml

这是应用程序Activity的字符串资源文件,定义了在应用程序中用到的各个字符串。

Activity
Sub Activity
Start sub-activity in process
Start sub-activity in new process
Finish Activity
2.4.4 icon.png

这是应用程序Activity的图标,可以根据需要来放置不同的图片文件

2.4.5 AndroidManifest.xml

这是应用程序Activity的配置文件。由于在程序中使用到了三个Activity组件 :MainActivity、SubActivityInProcess和SubActivityInNewProcess,因此我们需要对他们进行配置。

我们将MainActivity组件的 action 名称和 category名称分别设置为"android.intent.action.MAIN" 和 “android.intent.category.LAUNCHER”,使得它们可以作为应用程序Activity的根Activity组件。

将SubActivityInProcess和SubActivityInNewProcess组件的action分别设置为自定义的"haoran.ma.activity.subactivity.in.process"和"haoran.ma.activity.subactivity.in.new.process"因此,可以通过这两个名称来隐式的启动它们。

此外,我们还将 MainActivity组件和SubActivityInProcess组件的 android:process 属性 设置为为"haoran.ma.activity.mainprocess",以便它们可以运行在同一个进程中。而将SubActivityInNewProcess组件的 android:process 属性设置为 “haoran.ma.activity.newprocess”,以便它可以运行在另外一个进程中。

2.4.6
LOCAL_PATH:= $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE_TAGS := optionalLOCAL_SRC_FILES := $(call all-java-files-under, src)LOCAL_PACKAGE_NAME := ActivityLOCAL_CERTIFICATE := platforminclude $(BUILD_PACKAGE)# Use the folloing include to make our test apk.include $(call all-makefiles-under,$(LOCAL_PATH))

此为RK3128 Android6.0平台 需要在 build/target/product/core.mk中添加 应用名称

最后执行 mmm ./packages/experimental/MhrActivity/

注意

rk3288_7.1_mid\packages\experimental\Activity\Android.mkLOCAL_PATH:= $(call my-dir)  //后面不能以后空格!!!! 否则报错,举一反三 尽量都不要有空格include $(CLEAR_VARS)LOCAL_MODULE_TAGS := optionalLOCAL_SRC_FILES := $(call all-java-files-under, src)LOCAL_PACKAGE_NAME := ActivityLOCAL_CERTIFICATE := platforminclude $(BUILD_PACKAGE)# Use the folloing include to make our test apk.include $(call all-makefiles-under,$(LOCAL_PATH))xml 文件开头的
开头不能有空格 否则报错

启动界面:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

三 Activity组件的启动过程

以上面的应用程序 Activity的MainActivity组件的启动过程为例,分析Android应用程序的根Activity组件的启动过程,即Android应用程序

的驱动过程。

由于根Activity组件代表了一个Android应用程序,因此,它一般是在一个新的进程中启动起来的。由于 MainActivity组件的 android:process设置

成了 “haoran.ma.activity.mainprocess”,因此,Activity管理服务 ActivityManagerService 在启动 MainActivity组件时,就会发现系统中并不存在

一个名称为 "haoran.ma.activity.mainprocess"的应用程序进程,这时候它会先创建这个应用程序进程,然后再将 MainActivity组件启动起来。

MainActivity组件是由Launcher组件来启动的,而Launcher组件又是通过Activity管理服务ActivityManagerService来启动MainActivity组件的。由

于MainActivity组件、Launcher组件、ActivityManagerService 是分别运行在不同的进程中的,因此,MainActivity组件的驱动过程就涉及到了三个进程。

这三个进程是通过Binder进程间通信机制来完成 MainActivity组件的启动过程的。

Launcher组件启动MainActivity组件的过程如下所示:

1 Launcher组件向ActivityManagerService发送一个启动MainActivity组件的进程间通信请求。

2 ActivityManagerService首先将要启动的MainActivity组件的信息保存下来,然后向Launcher组件发送一个进入中止状态的进程间通信请求。
3 Launcher组件进入中止状态之后,就会向ActivityManagerService发送一个已经进入中止状态的进程间通信请求,以便ActivityManagerService可以继续
执行启动MainActivity组件的操作。
4 ActivityManagerService发现用来运行MainActivity组件的应用程序进程不存在,因此,它就会先启动一个新的应用程序进程。
5 新的应用程序进程启动完成之后,就会向ActivityManagerService发送一个完成的进程间通信请求,以便ActivityManagerService可以继续执行启动
MainActivity组件的操作。
6 ActivityManagerService将第二步保存下来的MainActivity组件的信息发送个第四步创建的应用程序进程,以便它可以将 MainActivity组件启动起来。

注意:ActivityManagerService是一个系统关键服务,它运行在系统进程System中,负责启动和调度应用程序组件。

当我们在应用程序启动器Launcher的界面上点击一个应用程序的快捷图标的时候,Launcher组件的成员函数startActivitySafely就会被调用来启动这个应用程序的根Avctivity,其中

要启动的根Activity的信息包含在参数intent中。

packages/apps/Launcher2/src/com/android/launcher2/Launcher.java

public final class Launcher extends Activity		implements View.OnClickListener, OnLongClickListener, LauncherModel.Callbacks,View.OnTouchListener {						......					boolean startActivitySafely(View v, Intent intent, Object tag) {		boolean success = false;		try {			/*				调用父类Activity的成员函数 startActivity()来启动单数所描述的 Activity组件			*/			success = startActivity(v, intent, tag);		} catch (ActivityNotFoundException e) {			Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();			Log.e(TAG, "Unable to launch. tag=" + tag + " intent=" + intent, e);		}		return success;	}		......	}当应用程序Activity的ManiActivity组件被Launcher组件启动时,参数intent所包含的Activity组件信息如下:

action android:name=“android.intent.action.MAIN” 和 category android:name=“android.intent.category.LAUNCHER” 表示要启动的Activity组件的Action名称和Category名称。

cmd = “haoran.ma.activity.MainActivity” 表示Activity组件是由 haoran.ma.activity.MainActivity 类来实现的。

action android:name="android.intent.action.MAIN" category android:name="android.intent.category.LAUNCHER" cmd = "haoran.ma.activity.MainActivity"那么Launcher组件是如何获得这些信息的呢?系统在启动时,回启动一个Package管理服务PackageManagerService,并通过它来安装系统中的应用程序。PackageManagerService在

安装一个应用程序的过程中,会对它的配置文件 AndroidManifest.xml进行解析,从而得到它里面的组件信息。系统在启动完成之后,就会将Launcher组件启动起来。Launcher组件在启

动过程中,会向PackageManagerService查询所有Action名称等于 xxx.Intent.ACTION_MAIN,以及 Category名称等于 "xxx.Intent.CATEGORY_LAUNCHER"的Activity组件,最后为每一个
Activity创建一个快捷图标,并且将它们的信息与各自的快捷图标关联起来,以便用户点击它们时可以将对应的Activity组件启动起来。

Launcher组件的成员函数 startActivitySafely()中,调用父类Activity的成员函数 startActivity()来启动单数所描述的 Activity组件。frameworks\base\core\java\android\app\Activity.javapublic class Activity extends ContextThemeWrapper    implements LayoutInflater.Factory2,    Window.Callback, KeyEvent.Callback,    OnCreateContextMenuListener, ComponentCallbacks2,    Window.OnWindowDismissedCallback, WindowControllerCallback {		......			public void startActivity(Intent intent, @Nullable Bundle options) {		if (options != null) {			startActivityForResult(intent, -1, options);		} else {			/*				启动参数intent所描述的Activity组件,第二个参数 -1 表示Launcher组件不需要知道即将启动的Activity组件的执行结果			*/			startActivityForResult(intent, -1);		}	}				......    public void startActivityForResult(String who, Intent intent, int requestCode, @Nullable Bundle options) {		Uri referrer = onProvideReferrer();		if (referrer != null) {			intent.putExtra(Intent.EXTRA_REFERRER, referrer);		}		options = transferSpringboardActivityOptions(options);		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);	}	}

…待续…

上一篇:中断脉冲触发设备休眠唤醒--输入子系统+中断机制+队列
下一篇:Android 修改属性权限小技巧

发表评论

最新留言

第一次来,支持一个
[***.219.124.196]2025年04月13日 15时29分52秒