2011-9-27 21:15:52

 

2011-9-27 21:15:52

 


  首先在Android源代碼工程中創建一個Android應用程序工程,名字就稱爲Process吧。
 
  關於如何獲得Android源代碼工程,請參考在Ubuntu上下載、編譯和安裝Android最新源代碼一文;
 
  關於如何在Android源代碼工程中創建應用程序工程,請參考在Ubuntu上爲Android系統內置Java應用程序測試Application Frameworks層的硬件服務一文。
 
  這個應用程序工程定義了一個名爲shy.luo.process的package,這個例子的源代碼主要就是實現在這裏了。下面,將會逐一介紹這個package裏面的文件。

    應用程序的默認Activity定義在src/shy/luo/process/MainActivity.java文件中:


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

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屬性。

這樣保證這2個不在同一個進程中。


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屬性的值以小寫字母開頭,則表示這是一個全局進程,
       
        允許其它應用程序組件也在這個進程中運行。

        因此,這裏我們以":"開頭,表示創建的是私有的進程。事實上,這裏我們不要前面的":"也是可以的,但是必須保證這個屬性性字符串內至少有一個"."字符,
       

全局 私有

 

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 =
   
   
(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>         

 

<?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源代碼中的模塊一文。
       執行以下命令進行編譯和打包:

view plaincopy to clipboardprint?
01.USER-NAME@MACHINE-NAME:~/Android$ mmm packages/experimental/Process       
02.USER-NAME@MACHINE-NAME:~/Android$ make snod    
USER-NAME@MACHINE-NAME:~/Android$ mmm packages/experimental/Process     
USER-NAME@MACHINE-NAME:~/Android$ make snod

         這樣,打包好的Android系統鏡像文件system.img就包含我們前面創建的Process應用程序了。
       再接下來,就是運行模擬器來運行我們的例子了。關於如何在Android源代碼工程中運行模擬器,請參考在Ubuntu上下載、編譯和安裝Android最新源代碼一文。
       執行以下命令啓動模擬器:


在源碼環境下進行編譯

 

發佈了363 篇原創文章 · 獲贊 11 · 訪問量 37萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章