相信很多做Android開發(fā)的同學對進程在Android中這個概念,都不怎么說的清楚,網(wǎng)路上有的說是一個應(yīng)用程序,這其實是不對的,為了研究Android中進程的概念,我這里寫了一個很簡單的代碼:
<application
android:name="com.example.nine.MyApplication"
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@android:style/Theme.Light.NoTitleBar" >
<activity
android:name=".MyProcessActivityA"
android:label="@string/app_name"
android:process=":text.a" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.example.nine.MyProcessActivityB"
android:process=":text.b" >
</activity>
</application>
這里我在aciticyA和B里分別加入了process標簽,意思就是讓這兩個activity運行在不同的進程里面。
下面是具體代碼:
package com.example.nine;
import java.util.ArrayList;
import java.util.List;
import android.app.Activity;
import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class MyProcessActivityA extends Activity {
private TextView tv1, tv2, tv3, tv4, tv5, tv6;
private Button bt;
private List<String> list;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_a);
initViews();
initData();
}
private void initViews() {
tv1 = (TextView) findViewById(R.id.tv1);
tv2 = (TextView) findViewById(R.id.tv2);
tv3 = (TextView) findViewById(R.id.tv3);
tv4 = (TextView) findViewById(R.id.tv4);
tv5 = (TextView) findViewById(R.id.tv5);
tv6 = (TextView) findViewById(R.id.tv6);
bt = (Button) findViewById(R.id.bt);
bt.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
startActivity(new Intent(MyProcessActivityA.this,MyProcessActivityB.class));
}
});
}
private void initData() {
list = new ArrayList<String>();
for (int i = 0; i <1000000; i++) {
list.add(i+"aaaaaaaaaaaaaaaaaaa");
}
Text.i = 1;
tv1.setText("當前線程id:"+Thread.currentThread().getId());
tv2.setText("當前進程Pid:"+android.os.Process.myPid());
tv3.setText("當前進程名稱:"+MyUtil.getCurProcessName(this));
tv4.setText("全局靜態(tài)變量i:"+Text.i);
tv5.setText("當前申請的總內(nèi)存:"+Runtime.getRuntime().totalMemory()/1024/1024+"M");
tv6.setText("單個進程分配的內(nèi)存上限:"+Runtime.getRuntime().maxMemory()/1024/1024+"M");
}
}
package com.example.nine;
import java.util.ArrayList;
import java.util.List;
import android.app.Activity;
import android.app.ActivityManager;
import android.content.Context;
import android.os.Bundle;
import android.widget.TextView;
public class MyProcessActivityB extends Activity{
private TextView tv1, tv2, tv3, tv4, tv5, tv6;
private List<String> list;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_b);
initViews();
initData();
}
private void initViews() {
tv1 = (TextView) findViewById(R.id.tv1);
tv2 = (TextView) findViewById(R.id.tv2);
tv3 = (TextView) findViewById(R.id.tv3);
tv4 = (TextView) findViewById(R.id.tv4);
tv5 = (TextView) findViewById(R.id.tv5);
tv6 = (TextView) findViewById(R.id.tv6);
}
private void initData() {
list = new ArrayList<String>();
for (int i = 0; i <1000000; i++) {
list.add(i+"aaaaaaaaaaaaaaaaaaa");
}
tv1.setText("當前線程id:"+Thread.currentThread().getId());
tv2.setText("當前進程Pid:"+android.os.Process.myPid());
tv3.setText("當前進程名稱:"+MyUtil.getCurProcessName(this));
tv4.setText("全局靜態(tài)變量i:"+Text.i);
tv5.setText("當前申請的總內(nèi)存:"+Runtime.getRuntime().totalMemory()/1024/1024+"M");
tv6.setText("單個進程分配的內(nèi)存上限:"+Runtime.getRuntime().maxMemory()/1024/1024+"M");
}
}
package com.example.nine;
import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
public class MyUtil {
public static String getCurProcessName(Context context) {
int pid = android.os.Process.myPid();
ActivityManager mActivityManager = (ActivityManager) context
.getSystemService(Context.ACTIVITY_SERVICE);
for (ActivityManager.RunningAppProcessInfo appProcess : mActivityManager
.getRunningAppProcesses()) {
if (appProcess.pid == pid) {
return appProcess.processName;
}
}
return null;
}
}
package com.example.nine;
import android.app.ActivityManager;
import android.app.Application;
import android.content.Context;
import android.util.Log;
public class MyApplication extends Application{
@Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
Log.e("ttext","Application onCreate"+"進程名稱"+MyUtil.getCurProcessName(getApplicationContext()));
}
}
下面我們逐一進行分析:
1.這兩個activity雖然屬于不同的進程(text.a和text.b),但是我們看到打印出來的線程ID是一樣的,都是主線程的ID,說明四大組件不管屬于哪個進程,都一定是運行在主線程中的。
2.大家可以看到,我這個手機,分配給單個進程的內(nèi)存上限是192M,但是如果是兩個進程,142+142>192M,每個進程上限都是192M,互相獨立不影響;如果app特別復(fù)雜,可以考慮多開進程,提高內(nèi)存分配上限。
3.關(guān)于全局變量,Text.i,這是一個靜態(tài)變量,我在A里面設(shè)置成了1,但是在B里面引用,仍然初始化為0,說明不同進程之間不能共享全局變量。
4.關(guān)于application的創(chuàng)建問題,從最后的截圖可以看到,每個進程被加載,都會創(chuàng)建一個application對象,所以一個app里面不一定只有一個application對象。
5.關(guān)于application再說一點,同一個進程之間的全局變量的保存也最好不要用application對象來保存,因為如果app切換到后臺被殺死過后,application是會重建的,這個時候你保存的變量就會初始化。
同一個進程,當我們退出應(yīng)用程序過后,application其實并沒有立刻被殺死,這時你再點擊應(yīng)用進入,application并不會再次被重建,里面的還會保留以前的全局數(shù)據(jù),那么我們要怎么才能保證在退出程序的時候,把數(shù)據(jù)清空呢?
在退出的時候,關(guān)閉進程即可。
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
System.exit(0);
}
值得注意的是,System.exit(0);只能關(guān)閉當前進程。
另外,還有兩種方法可以關(guān)閉進程,分別是通過包名和PID。
//第一種
ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
manager.killBackgroundProcesses(package);
//第二種
android.os.Process.killProcess(android.os.Process.myPid());
6.關(guān)于多進程之間數(shù)據(jù)傳遞的問題,這里我并沒有寫出demo,但是大體思路就是以下幾種:
a。通過Intent在四大組件中傳值。(這一點不管是同一個app里面的多進程還是不同app之間的多進程都可以)
值得注意的是,intent不能直接傳遞對象,如果要傳遞對象則要實現(xiàn)序列化的接口Parcelable或者是Serializable接口,本質(zhì)上都是轉(zhuǎn)化成字節(jié)流傳輸,這兩個接口不同之處在于Parcelable是內(nèi)存中讀寫速度較快但是占用內(nèi)存,Serializable是文件讀寫速度較慢但是內(nèi)存占用少。
b.通過本地存儲共享數(shù)據(jù).
數(shù)據(jù)庫或者xml都行。
c.關(guān)于網(wǎng)路上有的人說的什么多進程訪問本地文件,會有線程不安全的問題,這個其實并不正確,只要保證是在主線程中操作,就一定是線程安全的(原理參考第1點),當然如果你新建一個線程來讀寫,那就要用handler來保證線程安全了。
最后,我試著解釋下Android開發(fā)里面的進程的概念吧,其實谷歌官方是把Android里面的進程概念給弱化掉了,讓我們更加關(guān)心主線程,四大組件,不過強行要解釋的話,可以認為一個aplication對應(yīng)一個進程。