Activity组件简析

本文学习拜读自罗升阳老师的《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 Android.mk
三 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 Android.mk
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := Activity
LOCAL_CERTIFICATE := platform
include $(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.mk

LOCAL_PATH:= $(call my-dir)  //后面不能以后空格!!!! 否则报错,举一反三 尽量都不要有空格
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := Activity
LOCAL_CERTIFICATE := platform
include $(BUILD_PACKAGE)
# Use the folloing include to make our test apk.
include $(call all-makefiles-under,$(LOCAL_PATH))



xml 文件开头的

   开头不能有空格 否则报错

启动界面:

Activity组件简析_第1张图片

Activity组件简析_第2张图片

Activity组件简析_第3张图片

三 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.java

public 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系统分析篇)