Android開發(fā)之多進程詳解

相信很多做Android開發(fā)的同學對進程在Android中這個概念,都不怎么說的清楚,網路上有的說是一個應用程序,這其實是不對的,為了研究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("當前申請的總內存:"+Runtime.getRuntime().totalMemory()/1024/1024+"M");
        tv6.setText("單個進程分配的內存上限:"+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("當前申請的總內存:"+Runtime.getRuntime().totalMemory()/1024/1024+"M");
        tv6.setText("單個進程分配的內存上限:"+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()));
    }
}
20160614170632383.png
20160614170700180.png
20160614170842872.png
20160614170911138.png
下面我們逐一進行分析:

1.這兩個activity雖然屬于不同的進程(text.a和text.b),但是我們看到打印出來的線程ID是一樣的,都是主線程的ID,說明四大組件不管屬于哪個進程,都一定是運行在主線程中的。

2.大家可以看到,我這個手機,分配給單個進程的內存上限是192M,但是如果是兩個進程,142+142>192M,每個進程上限都是192M,互相獨立不影響;如果app特別復雜,可以考慮多開進程,提高內存分配上限。

3.關于全局變量,Text.i,這是一個靜態(tài)變量,我在A里面設置成了1,但是在B里面引用,仍然初始化為0,說明不同進程之間不能共享全局變量。

4.關于application的創(chuàng)建問題,從最后的截圖可以看到,每個進程被加載,都會創(chuàng)建一個application對象,所以一個app里面不一定只有一個application對象。

5.關于application再說一點,同一個進程之間的全局變量的保存也最好不要用application對象來保存,因為如果app切換到后臺被殺死過后,application是會重建的,這個時候你保存的變量就會初始化。
同一個進程,當我們退出應用程序過后,application其實并沒有立刻被殺死,這時你再點擊應用進入,application并不會再次被重建,里面的還會保留以前的全局數據,那么我們要怎么才能保證在退出程序的時候,把數據清空呢?
在退出的時候,關閉進程即可。

@Override
protected void onDestroy() {
    // TODO Auto-generated method stub
    super.onDestroy();
    System.exit(0);
}

值得注意的是,System.exit(0);只能關閉當前進程。

另外,還有兩種方法可以關閉進程,分別是通過包名和PID。

//第一種
ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); 
manager.killBackgroundProcesses(package);
//第二種
android.os.Process.killProcess(android.os.Process.myPid());

6.關于多進程之間數據傳遞的問題,這里我并沒有寫出demo,但是大體思路就是以下幾種:

a。通過Intent在四大組件中傳值。(這一點不管是同一個app里面的多進程還是不同app之間的多進程都可以)

值得注意的是,intent不能直接傳遞對象,如果要傳遞對象則要實現序列化的接口Parcelable或者是Serializable接口,本質上都是轉化成字節(jié)流傳輸,這兩個接口不同之處在于Parcelable是內存中讀寫速度較快但是占用內存,Serializable是文件讀寫速度較慢但是內存占用少。

b.通過本地存儲共享數據.
數據庫或者xml都行。

c.關于網路上有的人說的什么多進程訪問本地文件,會有線程不安全的問題,這個其實并不正確,只要保證是在主線程中操作,就一定是線程安全的(原理參考第1點),當然如果你新建一個線程來讀寫,那就要用handler來保證線程安全了。

最后,我試著解釋下Android開發(fā)里面的進程的概念吧,其實谷歌官方是把Android里面的進程概念給弱化掉了,讓我們更加關心主線程,四大組件,不過強行要解釋的話,可以認為一個aplication對應一個進程。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容