qmsggg / qmsggg_BlogCollect

仅仅只是用于学习和记录使用,里面包括了自己学习android的点点滴滴,希望自己在以后的时间能把之前由于时间原因没有完成的完成了,以此自勉。
57 stars 18 forks source link

如何开启多进程?应用是否可以开启N个进程? #158

Open qmsggg opened 6 years ago

qmsggg commented 6 years ago

为何要开启多进程?

为何开启android应用要开启多进程,主要有以下几点: 单进程所分配的内存不够,需要更多的内存。在早期android系统只为一个单进程的应用分配了16M的可用内存,随着手机的硬件的提升和android系统的改进,虽然可分配内存越来越多,但仍旧可以通过开启多进程来获取更多的内存来处理自己App的业务 独立运行的组件,比如个推,它的服务会另开一个进程。 进行一些“不可告人”的操作的处理,比如双守护进程,来尽力使自己的应用不被系统杀死,或者获取用户的个人信息等其他信息。

开启多进程

  • 首先我们写一个Activity并启动一个service
    
    package com.example.qmsggg.apptest;

import android.content.Intent; import android.support.v7.app.AppCompatActivity; import android.os.Bundle;

public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Intent MyServiceIntent = new Intent(this, MyService.class);
    this.startService(MyServiceIntent);
}

}

- service的代码:

package com.example.qmsggg.apptest;

import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.support.annotation.Nullable; import android.util.Log;

/**

public class MyService extends Service {

private static final String TAG = "qmsggg";

@Override
public void onCreate() {
    Log.i(TAG, "MyService is oncreate");
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    Log.i(TAG, "MyProcessActivity is created: ");
    return START_STICKY;
}

@Override
public void onDestroy() {
    Log.i(TAG, "ODestroy");
}

@Nullable
@Override
public IBinder onBind(Intent intent) {
    return null;
}

}

- 最后我们只需要在AndroidManifest.xml中的配置 android:process就可以了
``
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.qmsggg.apptest">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <service android:name=".MyService" android:label="@string/app_name" android:process=":test"/>
    </application>

</manifest>
``
>这里选择”test”这个名字是随意主观的,你也可以取其他的名字。冒号“:”的含义是在当前进程名前面附上当前的包名。那么MyService的完整进程名为“com.example.qmsggg.apptest:test”。我们也可以设置 android:process=”com.example.qmsggg.apptest.test”,这是一种完整的命名方式。这两种命名也是有区别的,如果被设置的进程名是以“:”开头的,则这个新的进程对于这个应用来说是私有的,当它被需要或者这个服务需要在新进程中运行的时候,这个新进程将会被创建。如果这个进程的名字是以小写字符开头的,则这个服务将运行在一个以这个名字命名的全局的进程中,当然前提是它有相应的权限。这将允许在不同应用中的各种组件可以共享一个进程,从而减少资源的占用。
![image](https://user-images.githubusercontent.com/28669743/37895386-c06d6aa2-3113-11e8-8cba-62bc2547f3bb.png)

##

public class MyApplication extends Application { private static final String TAG = "wangshu"; @Override public void onCreate() { super.onCreate(); int pid = android.os.Process.myPid(); Log.i(TAG, "MyApplication is oncreate===="+"pid="+pid); } }

>log中显示MyApplication 的onCreate执行了两次
![image](https://user-images.githubusercontent.com/28669743/37896111-a7e7e1d6-3115-11e8-99fb-3f0199281fdc.png)
![image](https://user-images.githubusercontent.com/28669743/37896126-afd0ea6e-3115-11e8-81a2-c09507dff601.png)

>但是现在很多的开发者都习惯在Application 的子类里去做应用的初始化和数据存储的操作,如果我们开启多个进程而让Application 的子类的各个回调方法都执行多次这显然是不多的,所以我们就应该区分进程,如果是应用的进程则做应用的操作,其他的进程(在这里是一个服务)就做其他的操作

package com.example.qmsggg.apptest;

import android.app.ActivityManager; import android.app.Application; import android.util.Log;

/**

public class MyApplication extends Application { private static final String TAG = "qmsgggg"; @Override public void onCreate() { super.onCreate(); int pid = android.os.Process.myPid(); Log.i(TAG, "pid=" + pid);

    String processnameString = "";
    ActivityManager manager = (ActivityManager) this.getSystemService(getApplicationContext().ACTIVITY_SERVICE);
    for (ActivityManager.RunningAppProcessInfo appProcessInfo : manager.getRunningAppProcesses()) {
        if (appProcessInfo.pid == pid) {
            processnameString = appProcessInfo.processName;
            Log.i(TAG, "processName=" + processnameString);
        }
    }
    if ("com.example.qmsggg.apptest:test".equals(processnameString)) {
        Log.i(TAG, "processName = " + processnameString);
    }
}

}


![image](https://user-images.githubusercontent.com/28669743/37896428-55d795a2-3116-11e8-88ba-62d8775f175f.png)
>虚拟机上并分配了不同的地址空间,修改静态成员只会在自己的进程中有效,同样单例模式也是只有自己的进程中是单例,多个进程中就不能称之为单例了,因为很可能多个进程都会存在这个所谓的单例。第四条SharedPreferences并不支持并发的读取,多个进程可能存在并发的情况,这样SharedPreferences的读和写都变得不可靠。
qmsggg commented 6 years ago

n应用是否可以开启N个进程?

可以

eg


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.qmsggg.apptest">
<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:name=".MyApplication"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <activity android:name=".MainActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
    <service android:name=".MyService" android:label="@string/app_name" android:process=":test"/>
    <service android:name=".MyService2" android:process=":test2" android:label="123"/>
</application>


![image](https://user-images.githubusercontent.com/28669743/37896727-080d86e6-3117-11e8-88e2-43f766ed2138.png)
qmsggg commented 6 years ago

因为多进程首先会有多个Application,数据会被初始化多次,其次进程间通信比较麻烦,还有一个就是每个进程有单独的虚拟机,多个进程就会比较占内存