`

Android应用程序的Activity启动过程简要介绍和学习计划

阅读更多

 在Android系统中,Activity和Service是应用程序的核心组件,它们以松藕合的方式组合在一起构成了一个完整的应用程序,这得益于应用程序框架层提供了一套完整的机制来协助应用程序启动这些Activity和Service,以及提供Binder机制帮助它们相互间进行通信。在前面的文章Android进程间通信(IPC)机制Binder简要介绍和学习计划Android系统在新进程中启动自定义服务过程(startService)的原理分析中,我们已经系统地介绍了Binder机制和Service的启动过程了,在本文中,简要介绍Activity的启动过程以及后续学习计划。

        在Android系统中,有两种操作会引发Activity的启动,一种用户点击应用程序图标时,Launcher会为我们启动应用程序的主Activity;应用程序的默认Activity启动起来后,它又可以在内部通过调用startActvity接口启动新的Activity,依此类推,每一个Activity都可以在内部启动新的Activity。通过这种连锁反应,按需启动Activity,从而完成应用程序的功能。

        这里,我们通过一个具体的例子来说明如何启动Android应用程序的Activity。Activity的启动方式有两种,一种是显式的,一种是隐式的,隐式启动可以使得Activity之间的藕合性更加松散,因此,这里只关注隐式启动Activity的方法。

        首先在Android源代码工程的packages/experimental目录下创建一个应用程序工程目录Activity。关于如何获得Android源代码工程,请参考在Ubuntu上下载、编译和安装Android最新源代码一文;关于如何在Android源代码工程中创建应用程序工程,请参考在Ubuntu上为Android系统内置Java应用程序测试Application Frameworks层的硬件服务一文。这里,工程名称就是Activity了,它定义了一个路径为shy.luo.activity的package,这个例子的源代码主要就是实现在这里了。下面,将会逐一介绍这个package里面的文件。

       应用程序的默认Activity定义在src/shy/luo/activity/MainActivity.java文件中:

 

  1. package shy.luo.activity;  
  2.   
  3. import shy.luo.activity.R;  
  4.   
  5. import android.app.Activity;  
  6. import android.content.Intent;  
  7. import android.os.Bundle;  
  8. import android.util.Log;  
  9. import android.view.View;  
  10. import android.view.View.OnClickListener;  
  11. import android.widget.Button;  
  12.   
  13. public class MainActivity extends Activity  implements OnClickListener {  
  14.     private final static String LOG_TAG = "shy.luo.activity.MainActivity";  
  15.   
  16.     private Button startButton = null;  
  17.   
  18.     @Override  
  19.     public void onCreate(Bundle savedInstanceState) {  
  20.         super.onCreate(savedInstanceState);  
  21.         setContentView(R.layout.main);  
  22.   
  23.         startButton = (Button)findViewById(R.id.button_start);  
  24.         startButton.setOnClickListener(this);  
  25.   
  26.         Log.i(LOG_TAG, "Main Activity Created.");  
  27.     }  
  28.   
  29.     @Override  
  30.     public void onClick(View v) {  
  31.         if(v.equals(startButton)) {  
  32.             Intent intent = new Intent("shy.luo.activity.subactivity");  
  33.             startActivity(intent);  
  34.         }  
  35.     }  
  36. }  
package shy.luo.activity;

import shy.luo.activity.R;

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 = "shy.luo.activity.MainActivity";

	private Button startButton = null;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		startButton = (Button)findViewById(R.id.button_start);
		startButton.setOnClickListener(this);

		Log.i(LOG_TAG, "Main Activity Created.");
	}

	@Override
	public void onClick(View v) {
		if(v.equals(startButton)) {
			Intent intent = new Intent("shy.luo.activity.subactivity");
			startActivity(intent);
		}
	}
}

        它的实现很简单,当点击它上面的一个按钮的时候,就会启动另外一个名字为“shy.luo.activity.subactivity”的Actvity。

 

        名字为“shy.luo.activity.subactivity”的Actvity实现在src/shy/luo/activity/SubActivity.java文件中:

 

  1. package shy.luo.activity;  
  2.   
  3. import android.app.Activity;  
  4. import android.os.Bundle;  
  5. import android.util.Log;  
  6. import android.view.View;  
  7. import android.view.View.OnClickListener;  
  8. import android.widget.Button;  
  9.   
  10. public class SubActivity extends Activity implements OnClickListener {  
  11.     private final static String LOG_TAG = "shy.luo.activity.SubActivity";  
  12.   
  13.     private Button finishButton = null;  
  14.   
  15.     @Override  
  16.     public void onCreate(Bundle savedInstanceState) {  
  17.         super.onCreate(savedInstanceState);  
  18.         setContentView(R.layout.sub);  
  19.   
  20.         finishButton = (Button)findViewById(R.id.button_finish);  
  21.         finishButton.setOnClickListener(this);  
  22.           
  23.         Log.i(LOG_TAG, "Sub Activity Created.");  
  24.     }  
  25.   
  26.     @Override  
  27.     public void onClick(View v) {  
  28.         if(v.equals(finishButton)) {  
  29.             finish();  
  30.         }  
  31.     }  
  32. }  
package shy.luo.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 SubActivity extends Activity implements OnClickListener {
	private final static String LOG_TAG = "shy.luo.activity.SubActivity";

	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 Created.");
	}

	@Override
	public void onClick(View v) {
		if(v.equals(finishButton)) {
			finish();
		}
	}
}

        它的实现也很简单,当点击上面的一个铵钮的时候,就结束自己,回到前面一个Activity中去。

 

        这里我们可以看到,Android应用程序架构中非常核心的一点:MainActivity不需要知道SubActivity的存在,即它不直接拥有SubActivity的接口,但是它可以通过一个字符串来告诉应用程序框架层,它要启动的Activity的名称是什么,其它的事情就交给应用程序框架层来做,当然,应用程序框架层会根据这个字符串来找到其对应的Activity,然后把它启动起来。这样,就使得Android应用程序中的Activity藕合性很松散,从而使得Android应用程序的模块性程度很高,并且有利于以后程序的维护和更新,对于大型的客户端软件来说,这一点是非常重要的。

        当然,应用程序框架能够根据名字来找到相应的Activity,是需要应用程序本身来配合的,这就是要通过应用程序的配置文件AndroidManifest.xml来实现了:

 

  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     package="shy.luo.activity"  
  4.     android:versionCode="1"  
  5.     android:versionName="1.0">  
  6.     <application android:icon="@drawable/icon" android:label="@string/app_name">  
  7.         <activity android:name=".MainActivity"  
  8.               android:label="@string/app_name">  
  9.             <intent-filter>  
  10.                 <action android:name="android.intent.action.MAIN" />  
  11.                 <category android:name="android.intent.category.LAUNCHER" />  
  12.             </intent-filter>  
  13.         </activity>  
  14.         <activity android:name=".SubActivity"  
  15.                   android:label="@string/sub_activity">  
  16.             <intent-filter>  
  17.                 <action android:name="shy.luo.activity.subactivity"/>  
  18.                 <category android:name="android.intent.category.DEFAULT"/>  
  19.             </intent-filter>  
  20.         </activity>  
  21.     </application>  
  22. </manifest>  
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
	package="shy.luo.activity"
	android:versionCode="1"
	android:versionName="1.0">
	<application android:icon="@drawable/icon" android:label="@string/app_name">
		<activity android:name=".MainActivity"
			  android:label="@string/app_name">
			<intent-filter>
				<action android:name="android.intent.action.MAIN" />
				<category android:name="android.intent.category.LAUNCHER" />
			</intent-filter>
		</activity>
		<activity android:name=".SubActivity"
		          android:label="@string/sub_activity">
			<intent-filter>
				<action android:name="shy.luo.activity.subactivity"/>
				<category android:name="android.intent.category.DEFAULT"/>
			</intent-filter>
		</activity>
	</application>
</manifest>

        从这个配置文件中,我们可以看到,MainActivity被配置成了应用程序的默认Activity,即用户在手机屏幕上点击Activity应用程序图标时,Launcher就会默认启动MainActivity这个Activity:

 

 

  1. <activity android:name=".MainActivity"  
  2.       android:label="@string/app_name">  
  3.        <intent-filter>  
  4.         <action android:name="android.intent.action.MAIN" />  
  5.         <category android:name="android.intent.category.LAUNCHER" />  
  6.     </intent-filter>  
  7. </activity>  
<activity android:name=".MainActivity"
	  android:label="@string/app_name">
       <intent-filter>
		<action android:name="android.intent.action.MAIN" />
		<category android:name="android.intent.category.LAUNCHER" />
	</intent-filter>
</activity>

        这个配置文件也将名字“shy.luo.activity.subactivity”和SubActivity关联了起来,因此,应用程序框架层能够根据名字来找到它:

 

 

  1. <activity android:name=".SubActivity"  
  2.       android:label="@string/sub_activity">  
  3.     <intent-filter>  
  4.         <action android:name="shy.luo.activity.subactivity"/>  
  5.         <category android:name="android.intent.category.DEFAULT"/>  
  6.     </intent-filter>  
  7. </activity>  
<activity android:name=".SubActivity"
	  android:label="@string/sub_activity">
	<intent-filter>
		<action android:name="shy.luo.activity.subactivity"/>
		<category android:name="android.intent.category.DEFAULT"/>
	</intent-filter>
</activity>

        下面再列出这个应用程序的界面配置文件和字符串文件。

 

        界面配置文件在res/layout目录中,main.xml文件对应MainActivity的界面:

 

  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:orientation="vertical"  
  4.     android:layout_width="fill_parent"  
  5.     android:layout_height="fill_parent"   
  6.     android:gravity="center">  
  7.         <Button   
  8.             android:id="@+id/button_start"  
  9.             android:layout_width="wrap_content"  
  10.             android:layout_height="wrap_content"  
  11.             android:gravity="center"  
  12.             android:text="@string/start" >  
  13.         </Button>  
  14. </LinearLayout>  
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" 
    android:gravity="center">
        <Button 
            android:id="@+id/button_start"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text="@string/start" >
        </Button>
</LinearLayout>

 

        而sub.xml对应SubActivity的界面:

 

  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:orientation="vertical"  
  4.     android:layout_width="fill_parent"  
  5.     android:layout_height="fill_parent"   
  6.     android:gravity="center">  
  7.         <Button   
  8.             android:id="@+id/button_finish"  
  9.             android:layout_width="wrap_content"  
  10.             android:layout_height="wrap_content"  
  11.             android:gravity="center"  
  12.             android:text="@string/finish" >  
  13.         </Button>  
  14. </LinearLayout>  
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" 
    android:gravity="center">
        <Button 
            android:id="@+id/button_finish"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text="@string/finish" >
        </Button>
</LinearLayout>

        字符串文件位于res/values/strings.xml文件中:

 

 

  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <resources>  
  3.     <string name="app_name">Activity</string>  
  4.     <string name="sub_activity">Sub Activity</string>  
  5.     <string name="start">Start sub-activity</string>  
  6.     <string name="finish">Finish activity</string>  
  7. </resources>  
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">Activity</string>
    <string name="sub_activity">Sub Activity</string>
    <string name="start">Start sub-activity</string>
    <string name="finish">Finish activity</string>
</resources>

        最后,我们还要在工程目录下放置一个编译脚本文件Android.mk:

 

 

  1. LOCAL_PATH:= $(call my-dir)  
  2. include $(CLEAR_VARS)  
  3.   
  4. LOCAL_MODULE_TAGS :optional  
  5.   
  6. LOCAL_SRC_FILES := $(call all-subdir-java-files)  
  7.   
  8. LOCAL_PACKAGE_NAME :Activity  
  9.   
  10. include $(BUILD_PACKAGE)  
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_MODULE_TAGS := optional

LOCAL_SRC_FILES := $(call all-subdir-java-files)

LOCAL_PACKAGE_NAME := Activity

include $(BUILD_PACKAGE)

        这样,整个例子的源代码实现就介绍完了,接下来就要编译了。有关如何单独编译Android源代码工程的模块,以及如何打包system.img,请参考如何单独编译Android源代码中的模块一文。
        执行以下命令进行编译和打包:

  1. USER-NAME@MACHINE-NAME:~/Android$ mmm packages/experimental/Activity    
  2. USER-NAME@MACHINE-NAME:~/Android$ make snod   
USER-NAME@MACHINE-NAME:~/Android$ mmm packages/experimental/Activity  
USER-NAME@MACHINE-NAME:~/Android$ make snod 

       这样,打包好的Android系统镜像文件system.img就包含我们前面创建的Activity应用程序了。
       再接下来,就是运行模拟器来运行我们的例子了。关于如何在Android源代码工程中运行模拟器,请参考在Ubuntu上下载、编译和安装Android最新源代码一文。
       执行以下命令启动模拟器:

  1. USER-NAME@MACHINE-NAME:~/Android$ emulator    
USER-NAME@MACHINE-NAME:~/Android$ emulator  

       模拟器启动起,就可以在屏幕上看到Activity应用程序图标了:

 

         点击Activity这个应用程序图标后,Launcher就会把MainActivity启动起来:

        点击上面的Start sub-activity铵钮,MainActivity内部就会通过startActivity接口来启动SubActivity:

 

  1. Intent intent = new Intent("shy.luo.activity.subactivity");  
  2. startActivity(intent);  
Intent intent = new Intent("shy.luo.activity.subactivity");
startActivity(intent);

        如下图所示:

 

        无论是通过点击应用程序图标来启动Activity,还是通过Activity内部调用startActivity接口来启动新的Activity,都要借助于应用程序框架层的ActivityManagerService服务进程。在前面一篇文章Android系统在新进程中启动自定义服务过程(startService)的原理分析中,我们已经看到,Service也是由ActivityManagerService进程来启动的。在Android应用程序框架层中,ActivityManagerService是一个非常重要的接口,它不但负责启动Activity和Service,还负责管理Activity和Service。

        Android应用程序框架层中的ActivityManagerService启动Activity的过程大致如下图所示:

         在这个图中,ActivityManagerService和ActivityStack位于同一个进程中,而ApplicationThread和ActivityThread位于另一个进程中。其中,ActivityManagerService是负责管理Activity的生命周期的,ActivityManagerService还借助ActivityStack是来把所有的Activity按照后进先出的顺序放在一个堆栈中;对于每一个应用程序来说,都有一个ActivityThread来表示应用程序的主进程,而每一个ActivityThread都包含有一个ApplicationThread实例,它是一个Binder对象,负责和其它进程进行通信。

        下面简要介绍一下启动的过程:

        Step 1. 无论是通过Launcher来启动Activity,还是通过Activity内部调用startActivity接口来启动新的Activity,都通过Binder进程间通信进入到ActivityManagerService进程中,并且调用ActivityManagerService.startActivity接口; 

        Step 2. ActivityManagerService调用ActivityStack.startActivityMayWait来做准备要启动的Activity的相关信息;

        Step 3. ActivityStack通知ApplicationThread要进行Activity启动调度了,这里的ApplicationThread代表的是调用ActivityManagerService.startActivity接口的进程,对于通过点击应用程序图标的情景来说,这个进程就是Launcher了,而对于通过在Activity内部调用startActivity的情景来说,这个进程就是这个Activity所在的进程了;

        Step 4. ApplicationThread不执行真正的启动操作,它通过调用ActivityManagerService.activityPaused接口进入到ActivityManagerService进程中,看看是否需要创建新的进程来启动Activity;

        Step 5. 对于通过点击应用程序图标来启动Activity的情景来说,ActivityManagerService在这一步中,会调用startProcessLocked来创建一个新的进程,而对于通过在Activity内部调用startActivity来启动新的Activity来说,这一步是不需要执行的,因为新的Activity就在原来的Activity所在的进程中进行启动;

        Step 6. ActivityManagerServic调用ApplicationThread.scheduleLaunchActivity接口,通知相应的进程执行启动Activity的操作;

        Step 7. ApplicationThread把这个启动Activity的操作转发给ActivityThread,ActivityThread通过ClassLoader导入相应的Activity类,然后把它启动起来。

        这样,Android应用程序的Activity启动过程就简要介绍到这里了

原博客链接:http://blog.csdn.net/luoshengyang/article/details/6685853

 

本文节选自Android系统源代码情景分析》

电子工业出版社出版

罗升阳

分享到:
评论

相关推荐

    Android应用程序的Activity启动过程简要介绍和学习计划.doc

    Android应用程序的Activity启动过程简要介绍和学习计划.docAndroid应用程序的Activity启动过程简要介绍和学习计划.docAndroid应用程序的Activity启动过程简要介绍和学习计划.docAndroid应用程序的Activity启动过程...

    Android应用程序启动过程源代码分析

    在上一篇文章Android应用程序的Activity启动过程简要介绍和学习计划中,我们举例子说明了启动Android应用程序中的Activity的两种情景,其中,在手机屏幕中点击应用程序图标的情景就会引发Android应用程序中的默认...

    分析Android Activity的启动过程

     对于Android Activity 的启动过程,我在Android源码中读了好久的源码,以下是我整理出来的Activity启动过程和大家分享下: Activity作为Android的四大组件之一,也是最基本的组件,负责与用户交互的所有功能。...

    android_应用程序开发

    简单理解,Activity代表一个用户所能看到的屏幕,主要用于处理应用程序的整体性工作,例如监听系统事件,为用户显示指定的View,启动其他Activity等。所有应用的Activity都继承于android.app.Activity类,该类是...

    Android高级编程--源代码

    3.1 Android应用程序的组成部分 43 3.2 程序清单简介 44 3.3 使用清单编辑器 47 3.4 Android应用程序生命周期 48 3.5 理解应用程序的优先级和进程状态 49 3.6 分离资源 50 3.6.1 创建资源 50 3.6.2 使用资源...

    如何设计android锁屏程序.pptx

    如何实现锁屏程序 刘飞 如何设计android锁屏程序全文共27页,当前为第1... 设计自己的Service 屏幕关闭时锁屏程序启动 Android的framework会广播一些常用的消息 Answer,screen on,screen off,battery changed等 应用

    简单介绍Android开发中的Activity控件的基本概念

    简单理解,Activity代表一个用户所能看到的屏幕,主要用于处理应用程序的整体性工作,例如监听系统事件,为用户显示指定的View,启动其他Activity等。所有应用的Activity都继承于android.app.Activity类,该类是...

    简单介绍Android中Activity的四种启动模式

    在Android中每个界面都是一个Activity,切换界面操作其实是多个不同Activity之间的实例化操作。本文给大家介绍Android中Activity的四种启动模式,需要的朋友参考下吧

    androidkit(android应用开发工具包)

    androidkit是一个android应用开发工具包,包含SQLiteOpenHelper的简单实现类、获取指定URL中返回的内容的String对象、View控件的截图、获取 本程序的图标、名字、版本、包名等信息、再按一次退出、抽象类,继承并...

    kan3an:开发Android应用程序时将使用的简单bash脚本,以将应用程序从AndroidStudio项目启动到测试设备

    开发Android应用程序时将使用的简单bash脚本,以将应用程序从AndroidStudio项目启动到测试设备。 ###装备 研究生课程通常在Android Studio项目目录中找到。 首先可能需要运行一次以进行设置。 亚行程序如果在SDK...

    《Android高级编程》

    2.5 小结 第3章 创建应用程序和活动 3.1 Android应用程序的组成部分 3.2 程序清单简介 3.3 使用清单编辑器 3.4 Android应用程序生命周期 3.5 理解应用程序的优先级和进程状态 3.6 分离资源 3.6.1 创建资源 3.6.2 ...

    Android高级编程 part1

    Android高级编程《Android高级编程》有清华大学出版社出版,书中对Android做了简单介绍,并对创建应用程序,用户见面编程做了介绍。并对一些新功能。如:地图,P2P通信,蓝牙以及后台和用Android访问硬件,分章节做...

    Android高级编程 part2

    Android高级编程《Android高级编程》有清华大学出版社出版,书中对Android做了简单介绍,并对创建应用程序,用户见面编程做了介绍。并对一些新功能。如:地图,P2P通信,蓝牙以及后台和用Android访问硬件,分章节做...

    Google Android SDK开发范例大全(完整版)

    虽然没有 Eclipse 和 Android Developer Tools 插件也可以开发 Android 应用程序,但是那样就需要熟悉 Android SDK。 Android SDK 是作为一个 ZIP 文件发布的,可以将该文件解压到硬盘上的一个目录中。由于有多个 ...

    Android移动应用开发实验指导书.docx

    《Android移动应用开发》 实验指导书 课程代码: 总课时数: 适用专业: 院(系)名称: Android移动应用开发实验指导书全文共13页,当前为第1页。 Android移动应用开发实验指导书全文共13页,当前为第1页。 实验一...

    webex-teams-sdk-wrapper-sample:示例应用程序演示如何使用Webex Teams Android SDK包装器将视频嵌入Android应用程序

    它提供了一种简单的方法,可将Webex Teams视频呼叫添加到您的Android应用程序中。 该库提供了Activity类的一小部分,可用于启动Webex Teams视频通话,而无需了解基础Webex Teams SDK的详细信息。 本应用程序演示了...

    Android编程入门很简单.(清华出版.王勇).part1

    第8章Android应用程序组成 8.1深入理解Activity 8.1.1使用Intent连接Activity 8.1.2 Activity的生命周期 …… 第9章Android中的数据存储 第10章绚丽的多媒体技术 第11章Android网上冲浪 第12章Android地图服务 第4篇...

Global site tag (gtag.js) - Google Analytics