原文出處——>[Android應用程序在新的進程中啟動新的Activity的方法和過程分析](http://blog.csdn.net/luoshengyang/article/details/6720261)
前面我們在分析Activity啟動過程的時候,看到同一個應用程序的Activity一般都是在同一個進程中啟動,事實上,Activity也可以像Service一樣在新的進程中啟動,這樣,一個應用程序就可以跨越好幾個進程了,本文就分析一下在新的進程中啟動Activity的方法和過程。
在前面Android進程間通信(IPC)機制Binder簡要介紹和學習計劃一文中,我們提到,在Android系統中,每一個應用程序都是由一些Activity和Service組成的,一般Service運行在獨立的進程中,而Activity有可能運行在同一個進程中,也有可能運行在不同的進程中。在前面Android系統在新進程中啟動自定義服務過程(startService)的原理分析一文中,我們已經介紹了使用Activity.startService接口來在新進程中啟動Service的過程,然后又在前面Android應用程序內部啟動Activity過程(startActivity)的源代碼分析一文中介紹了使用Activity.startActivity接口來在原來的進程中啟動Activity的過程,現在,我們就來看一下同一個Android應用程序如何在新的進程中啟動新的Activity。
老規矩,我們通過例子來介紹Android應用程序在新的進程中啟動新的Activity的方法以及分析其過程。首先在Android源代碼工程中創建一個Android應用程序工程,名字就稱為Process吧。關于如何獲得Android源代碼工程,請參考在Ubuntu上下載、編譯和安裝Android最新源代碼一文;關于如何在Android源代碼工程中創建應用程序工程,請參考在Ubuntu上為Android系統內置Java應用程序測試Application Frameworks層的硬件服務一文。這個應用程序工程定義了一個名為shy.luo.process的package,這個例子的源代碼主要就是實現在這里了。下面,將會逐一介紹這個package里面的文件。
應用程序的默認Activity定義在**src/shy/luo/process/MainActivity.java**文件中:
~~~
package shy.luo.process;
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.process.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.process.subactivity");
startActivity(intent);
}
}
}
~~~
和前面文章的例子一樣,它的實現很簡單,當點擊它上面的一個按鈕的時候,就會啟動另外一個名字為“shy.luo.process.subactivity”的Actvity。
名字為“shy.luo.process.subactivity”的Actvity實現在src/shy/luo/process/SubActivity.java文件中:
~~~
package shy.luo.process;
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.process.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中去。
再來重點看一下應用程序的配置文件AndroidManifest.xml:
~~~
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="shy.luo.task"
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">
android:process=":shy.luo.process.main"
<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"
android:process=":shy.luo.process.sub">
<intent-filter>
<action android:name="shy.luo.task.subactivity"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
</application>
</manifest>
~~~
為了使MainActivity和SubActivity在不同的進程中啟動,我們分別配置了這兩個Activity的android:process屬性。在官方文檔http://developer.android.com/guide/topics/manifest/activity-element.html 中,是這樣介紹Activity的android:process屬性的:
> The name of the process in which the activity should run. Normally, all components of an application run in the default process created for the application. It has the same name as the application package. The `<application> `element's process attribute can set a different default for all components. But each component can override the default, allowing you to spread your application across multiple processes.
> If the name assigned to this attribute begins with a colon (':'), a new process, private to the application, is created when it's needed and the activity runs in that process. If the process name begins with a lowercase character, the activity will run in a global process of that name, provided that it has permission to do so. This allows components in different applications to share a process, reducing resource usage.
大意為,一般情況下,同一個應用程序的Activity組件都是運行在同一個進程中,但是,如果Activity配置了android:process這個屬性,那么,它就會運行在自己的進程中。如果android:process屬性的值以":"開頭,則表示這個進程是私有的;如果android:process屬性的值以小寫字母開頭,則表示這是一個全局進程,允許其它應用程序組件也在這個進程中運行。
因此,這里我們以":"開頭,表示創建的是私有的進程。事實上,這里我們不要前面的":"也是可以的,但是必須保證這個屬性性字符串內至少有一個"."字符,具體可以看一下解析AndroidManiefst.xml文件的源代碼,在frameworks/base/core/java/android/content/pm/PackageParser.java文件中:
~~~
public class PackageParser {
......
private boolean parseApplication(Package owner, Resources res,
XmlPullParser parser, AttributeSet attrs, int flags, String[] outError)
throws XmlPullParserException, IOException {
final ApplicationInfo ai = owner.applicationInfo;
final String pkgName = owner.applicationInfo.packageName;
TypedArray sa = res.obtainAttributes(attrs,
com.android.internal.R.styleable.AndroidManifestApplication);
......
if (outError[0] == null) {
CharSequence pname;
if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.FROYO) {
pname = sa.getNonConfigurationString(
com.android.internal.R.styleable.AndroidManifestApplication_process, 0);
} else {
// Some older apps have been seen to use a resource reference
// here that on older builds was ignored (with a warning). We
// need to continue to do this for them so they don't break.
pname = sa.getNonResourceString(
com.android.internal.R.styleable.AndroidManifestApplication_process);
}
ai.processName = buildProcessName(ai.packageName, null, pname,
flags, mSeparateProcesses, outError);
......
}
......
}
private static String buildProcessName(String pkg, String defProc,
CharSequence procSeq, int flags, String[] separateProcesses,
String[] outError) {
if ((flags&PARSE_IGNORE_PROCESSES) != 0 && !"system".equals(procSeq)) {
return defProc != null ? defProc : pkg;
}
if (separateProcesses != null) {
for (int i=separateProcesses.length-1; i>=0; i--) {
String sp = separateProcesses[i];
if (sp.equals(pkg) || sp.equals(defProc) || sp.equals(procSeq)) {
return pkg;
}
}
}
if (procSeq == null || procSeq.length() <= 0) {
return defProc;
}
return buildCompoundName(pkg, procSeq, "process", outError);
}
private static String buildCompoundName(String pkg,
CharSequence procSeq, String type, String[] outError) {
String proc = procSeq.toString();
char c = proc.charAt(0);
if (pkg != null && c == ':') {
if (proc.length() < 2) {
outError[0] = "Bad " + type + " name " + proc + " in package " + pkg
+ ": must be at least two characters";
return null;
}
String subName = proc.substring(1);
String nameError = validateName(subName, false);
if (nameError != null) {
outError[0] = "Invalid " + type + " name " + proc + " in package "
+ pkg + ": " + nameError;
return null;
}
return (pkg + proc).intern();
}
String nameError = validateName(proc, true);
if (nameError != null && !"system".equals(proc)) {
outError[0] = "Invalid " + type + " name " + proc + " in package "
+ pkg + ": " + nameError;
return null;
}
return proc.intern();
}
private static String validateName(String name, boolean requiresSeparator) {
final int N = name.length();
boolean hasSep = false;
boolean front = true;
for (int i=0; i<N; i++) {
final char c = name.charAt(i);
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
front = false;
continue;
}
if (!front) {
if ((c >= '0' && c <= '9') || c == '_') {
continue;
}
}
if (c == '.') {
hasSep = true;
front = true;
continue;
}
return "bad character '" + c + "'";
}
return hasSep || !requiresSeparator
? null : "must have at least one '.' separator";
}
......
}
~~~
從調用parseApplication函數解析application標簽開始,通過調用buildProcessName函數對android:process屬性進解析,接著又會調用buildCompoundName進一步解析,這里傳進來的參數pkg就為"shy.luo.process",參數procSeq為MainActivity的屬性android:process的值":shy.luo.process.main",進一步將這個字符串保存在本地變量proc中。如果proc的第一個字符是":",則只需要調用validateName函數來驗證proc字符串里面的字符都是合法組成就可以了,即以大小寫字母或者"."開頭,后面可以跟數字或者"_"字符;如果proc的第一個字符不是":",除了保證proc字符里面的字符都是合法組成外,還要求至少有一個"."字符。
MainActivity和SubActivity的android:process屬性配置就介紹到這里了,其它更多的信息讀者可以參考官方文檔http://developer.android.com/guide/topics/manifest/activity-element.html 或者源代碼文件frameworks/base/core/java/android/content/pm/PackageParser.java。
再來看界面配置文件,它們定義在res/layout目錄中,main.xml文件對應MainActivity的界面:
~~~
<?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的界面:
~~~
<?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文件中:
~~~
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Process</string>
<string name="sub_activity">Sub Activity</string>
<string name="start">Start activity in new process</string>
<string name="finish">Finish activity</string>
</resources>
~~~
最后,我們還要在工程目錄下放置一個編譯腳本文件Android.mk:
~~~
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := Process
include $(BUILD_PACKAGE)
~~~
接下來就要編譯了。有關如何單獨編譯Android源代碼工程的模塊,以及如何打包system.img,請參考如何單獨編譯Android源代碼中的模塊一文。
執行以下命令進行編譯和打包:
~~~
USER-NAME@MACHINE-NAME:~/Android$ mmm packages/experimental/Process
USER-NAME@MACHINE-NAME:~/Android$ make snod
~~~
這樣,打包好的Android系統鏡像文件system.img就包含我們前面創建的Process應用程序了。
再接下來,就是運行模擬器來運行我們的例子了。關于如何在Android源代碼工程中運行模擬器,請參考在Ubuntu上下載、編譯和安裝Android最新源代碼一文。
執行以下命令啟動模擬器:
~~~
USER-NAME@MACHINE-NAME:~/Android$ emulator
~~~
模擬器啟動起,就可以App Launcher中找到Process應用程序圖標,接著把它啟動起來:

點擊中間的按鈕,就會在新的進程中啟動SubActivity:

現在,我們如何來確認SubActivity是不是在新的進程中啟動呢?Android源代碼工程為我們準備了adb工具,可以查看模擬器上系統運行的狀況,執行下面的命令查看:
~~~
USER-NAME@MACHINE-NAME:~/Android$ adb shell dumpsys activity
~~~
這個命令輸出的內容比較多,這里我們只關心系統中的任務和進程部分:
~~~
......
Running activities (most recent first):
TaskRecord{40770440 #3 A shy.luo.process}
Run #2: HistoryRecord{406d4b20 shy.luo.process/.SubActivity}
Run #1: HistoryRecord{40662bd8 shy.luo.process/.MainActivity}
TaskRecord{40679eb8 #2 A com.android.launcher}
Run #0: HistoryRecord{40677570 com.android.launcher/com.android.launcher2.Launcher}
......
PID mappings:
......
PID #416: ProcessRecord{4064b720 416:shy.luo.process:shy.luo.process.main/10037}
PID #425: ProcessRecord{406ddc30 425:shy.luo.process:shy.luo.process.sub/10037}
......
~~~
這里我們看到,雖然MainActivity和SubActivity都是在同一個應用程序并且運行在同一個任務中,然而,它們卻是運行在兩個不同的進程中,這就可以看到Android系統中任務這個概念的強大之處了,它使得我們在開發應用程序的時候,可以把相對獨立的模塊放在獨立的進程中運行,以降低模塊之間的耦合性,同時,我們又不必去考慮一個應用程序在兩個進程中運行的細節的問題,Android系統中的任務會為我們打點好一切。
在啟動Activity的時候,系統是如何做到在新的進程中來啟動這個Activity的呢?在前面兩篇文章Android應用程序啟動過程源代碼分析和Android應用程序內部啟動Activity過程(startActivity)的源代碼分析中,分別在Step 22和Step 21中分析了Activity在啟動過程中與進程相關的函數ActivityStack.startSpecificActivityLocked函數中,它定義在frameworks/base/services/java/com/android/server/am/ActivityStack.java文件中:
~~~
public class ActivityStack {
......
private final void startSpecificActivityLocked(ActivityRecord r,
boolean andResume, boolean checkConfig) {
// Is this activity's application already running?
ProcessRecord app = mService.getProcessRecordLocked(r.processName,
r.info.applicationInfo.uid);
......
if (app != null && app.thread != null) {
try {
realStartActivityLocked(r, app, andResume, checkConfig);
return;
} catch (RemoteException e) {
......
}
}
mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
"activity", r.intent.getComponent(), false);
}
......
}
~~~
從這個函數可以看出,決定一個Activity是在新的進程中啟動還是在原有的進程中啟動的因素有兩個,一個是看這個Activity的process屬性的值,另一個是這個Activity所在的應用程序的uid。應用程序的UID是由系統分配的,而Activity的process屬性值,如前所述,是可以在AndroidManifest.xml文件中進行配置的,如果沒有配置,它默認就為application標簽的process屬性值,如果application標簽的process屬性值也沒有配置,那么,它們就默認為應用程序的package名。這里就是根據processName和uid在系統查找是否已有相應的進程存在,如果已經有了,就會調用realStartActivityLocked來直接啟動Activity,否則的話,就要通過調用ActivityManagerService.startProcessLocked函數來創建一個新的進程,然后在新進程中啟動這個Activity了。對于前者,可以參考Android應用程序內部啟動Activity過程(startActivity)的源代碼分析一文,而后者,可以參考Android應用程序啟動過程源代碼分析一文。
至此,Android應用程序在新的進程中啟動新的Activity的方法和過程分析就結束了。在實際開發中,一個應用程序一般很少會在一個新的進程中啟動另外一個Activity,如果真的需要這樣做,還要考慮如何與應用程序中其它進程的Activity進行通信,這時候不妨考慮使用Binder進程間通信機制。寫這篇文章的目的,更多是讓我們去了解Android應用程序的架構,這種架構可以使得應用程序組件以松耦合的方式組合在一起,便于后續的擴展和維護,這是非常值得我們學習的。
- 前言
- Android組件設計思想
- Android源代碼開發和調試環境搭建
- Android源代碼下載和編譯
- Android源代碼情景分析法
- Android源代碼調試分析法
- 手把手教你為手機編譯ROM
- 在Ubuntu上下載、編譯和安裝Android最新源代碼
- 在Ubuntu上下載、編譯和安裝Android最新內核源代碼(Linux Kernel)
- 如何單獨編譯Android源代碼中的模塊
- 在Ubuntu上為Android系統編寫Linux內核驅動程序
- 在Ubuntu上為Android系統內置C可執行程序測試Linux內核驅動程序
- 在Ubuntu上為Android增加硬件抽象層(HAL)模塊訪問Linux內核驅動程序
- 在Ubuntu為Android硬件抽象層(HAL)模塊編寫JNI方法提供Java訪問硬件服務接口
- 在Ubuntu上為Android系統的Application Frameworks層增加硬件訪問服務
- 在Ubuntu上為Android系統內置Java應用程序測試Application Frameworks層的硬件服務
- Android源代碼倉庫及其管理工具Repo分析
- Android編譯系統簡要介紹和學習計劃
- Android編譯系統環境初始化過程分析
- Android源代碼編譯命令m/mm/mmm/make分析
- Android系統鏡像文件的打包過程分析
- 從CM刷機過程和原理分析Android系統結構
- Android系統架構概述
- Android系統整體架構
- android專用驅動
- Android硬件抽象層HAL
- Android應用程序組件
- Android應用程序框架
- Android用戶界面架構
- Android虛擬機之Dalvik虛擬機
- Android硬件抽象層
- Android硬件抽象層(HAL)概要介紹和學習計劃
- Android專用驅動
- Android Logger驅動系統
- Android日志系統驅動程序Logger源代碼分析
- Android應用程序框架層和系統運行庫層日志系統源代碼分析
- Android日志系統Logcat源代碼簡要分析
- Android Binder驅動系統
- Android進程間通信(IPC)機制Binder簡要介紹和學習計劃
- 淺談Service Manager成為Android進程間通信(IPC)機制Binder守護進程之路
- 淺談Android系統進程間通信(IPC)機制Binder中的Server和Client獲得Service Manager接口之路
- Android系統進程間通信(IPC)機制Binder中的Server啟動過程源代碼分析
- Android系統進程間通信(IPC)機制Binder中的Client獲得Server遠程接口過程源代碼分析
- Android系統進程間通信Binder機制在應用程序框架層的Java接口源代碼分析
- Android Ashmem驅動系統
- Android系統匿名共享內存Ashmem(Anonymous Shared Memory)簡要介紹和學習計劃
- Android系統匿名共享內存Ashmem(Anonymous Shared Memory)驅動程序源代碼分析
- Android系統匿名共享內存Ashmem(Anonymous Shared Memory)在進程間共享的原理分析
- Android系統匿名共享內存(Anonymous Shared Memory)C++調用接口分析
- Android應用程序進程管理
- Android應用程序進程啟動過程的源代碼分析
- Android系統進程Zygote啟動過程的源代碼分析
- Android系統默認Home應用程序(Launcher)的啟動過程源代碼分析
- Android應用程序消息機制
- Android應用程序消息處理機制(Looper、Handler)分析
- Android應用程序線程消息循環模型分析
- Android應用程序輸入事件分發和處理機制
- Android應用程序鍵盤(Keyboard)消息處理機制分析
- Android應用程序UI架構
- Android系統的開機畫面顯示過程分析
- Android幀緩沖區(Frame Buffer)硬件抽象層(HAL)模塊Gralloc的實現原理分析
- SurfaceFlinger
- Android系統Surface機制的SurfaceFlinger服務
- SurfaceFlinger服務簡要介紹和學習計劃
- 啟動過程分析
- 對幀緩沖區(Frame Buffer)的管理分析
- 線程模型分析
- 渲染應用程序UI的過程分析
- Android應用程序與SurfaceFlinger服務的關系
- 概述和學習計劃
- 連接過程分析
- 共享UI元數據(SharedClient)的創建過程分析
- 創建Surface的過程分析
- 渲染Surface的過程分析
- Android應用程序窗口(Activity)
- 實現框架簡要介紹和學習計劃
- 運行上下文環境(Context)的創建過程分析
- 窗口對象(Window)的創建過程分析
- 視圖對象(View)的創建過程分析
- 與WindowManagerService服務的連接過程分析
- 繪圖表面(Surface)的創建過程分析
- 測量(Measure)、布局(Layout)和繪制(Draw)過程分析
- WindowManagerService
- WindowManagerService的簡要介紹和學習計劃
- 計算Activity窗口大小的過程分析
- 對窗口的組織方式分析
- 對輸入法窗口(Input Method Window)的管理分析
- 對壁紙窗口(Wallpaper Window)的管理分析
- 計算窗口Z軸位置的過程分析
- 顯示Activity組件的啟動窗口(Starting Window)的過程分析
- 切換Activity窗口(App Transition)的過程分析
- 顯示窗口動畫的原理分析
- Android控件TextView的實現原理分析
- Android視圖SurfaceView的實現原理分析
- Android應用程序UI硬件加速渲染
- 簡要介紹和學習計劃
- 環境初始化過程分析
- 預加載資源地圖集服務(Asset Atlas Service)分析
- Display List構建過程分析
- Display List渲染過程分析
- 動畫執行過程分析
- Android應用程序資源管理框架
- Android資源管理框架(Asset Manager)
- Asset Manager 簡要介紹和學習計劃
- 編譯和打包過程分析
- Asset Manager的創建過程分析
- 查找過程分析
- Dalvik虛擬機和ART虛擬機
- Dalvik虛擬機
- Dalvik虛擬機簡要介紹和學習計劃
- Dalvik虛擬機的啟動過程分析
- Dalvik虛擬機的運行過程分析
- Dalvik虛擬機JNI方法的注冊過程分析
- Dalvik虛擬機進程和線程的創建過程分析
- Dalvik虛擬機垃圾收集機制簡要介紹和學習計劃
- Dalvik虛擬機Java堆創建過程分析
- Dalvik虛擬機為新創建對象分配內存的過程分析
- Dalvik虛擬機垃圾收集(GC)過程分析
- ART虛擬機
- Android ART運行時無縫替換Dalvik虛擬機的過程分析
- Android運行時ART簡要介紹和學習計劃
- Android運行時ART加載OAT文件的過程分析
- Android運行時ART加載類和方法的過程分析
- Android運行時ART執行類方法的過程分析
- ART運行時垃圾收集機制簡要介紹和學習計劃
- ART運行時Java堆創建過程分析
- ART運行時為新創建對象分配內存的過程分析
- ART運行時垃圾收集(GC)過程分析
- ART運行時Compacting GC簡要介紹和學習計劃
- ART運行時Compacting GC堆創建過程分析
- ART運行時Compacting GC為新創建對象分配內存的過程分析
- ART運行時Semi-Space(SS)和Generational Semi-Space(GSS)GC執行過程分析
- ART運行時Mark-Compact( MC)GC執行過程分析
- ART運行時Foreground GC和Background GC切換過程分析
- Android安全機制
- SEAndroid安全機制簡要介紹和學習計劃
- SEAndroid安全機制框架分析
- SEAndroid安全機制中的文件安全上下文關聯分析
- SEAndroid安全機制中的進程安全上下文關聯分析
- SEAndroid安全機制對Android屬性訪問的保護分析
- SEAndroid安全機制對Binder IPC的保護分析
- 從NDK在非Root手機上的調試原理探討Android的安全機制
- APK防反編譯
- Android視頻硬解穩定性問題探討和處理
- Android系統的智能指針(輕量級指針、強指針和弱指針)的實現原理分析
- Android應用程序安裝過程源代碼分析
- Android應用程序啟動過程源代碼分析
- 四大組件源代碼分析
- Activity
- Android應用程序的Activity啟動過程簡要介紹和學習計劃
- Android應用程序內部啟動Activity過程(startActivity)的源代碼分析
- 解開Android應用程序組件Activity的"singleTask"之謎
- Android應用程序在新的進程中啟動新的Activity的方法和過程分析
- Service
- Android應用程序綁定服務(bindService)的過程源代碼分析
- ContentProvider
- Android應用程序組件Content Provider簡要介紹和學習計劃
- Android應用程序組件Content Provider應用實例
- Android應用程序組件Content Provider的啟動過程源代碼分析
- Android應用程序組件Content Provider在應用程序之間共享數據的原理分析
- Android應用程序組件Content Provider的共享數據更新通知機制分析
- BroadcastReceiver
- Android系統中的廣播(Broadcast)機制簡要介紹和學習計劃
- Android應用程序注冊廣播接收器(registerReceiver)的過程分析
- Android應用程序發送廣播(sendBroadcast)的過程分析