关闭

第九章 多进程(multiprocess)

373人阅读 评论(0) 收藏 举报

一、多进程的基础知识

◆  为什么使用多进程?

        一个应用默认使用一个进程,这个进程(主进程)的名字就是应用的包名,进程是系统分配资源和调度的基本单位,每个进程都有自己独立的资源和内存空间,其他进程不能任意访问当前进程的内存和资源,系统给每个进程分配的内存会有限制。
        如果一个进程占用内存超过了这个内存限制,就会报OOM的问题。为了解决应用内存的问题,Android引入了多进程的概念,它允许在同一个应用内,废了分担主进程的压力,将占用内存的某些页面单独开一个进程,比如Flash、视频播放页面,频繁绘制的页面等。
        使用多进程,需要在AndroidMainfest.xml的声明中添加“android:process"属性;process分私有进程和全局进程两种,私有进程的名称前面有冒号,全部进程没有。
        <activity
            android:name=".aidl.AIDLActivity"
            android:label="@string/app_name"
            android:process=":other">
        </activity>
        为了节省系统内存,在退出该Activity的时候可以将其杀掉(如果没有人为杀掉该进程,在程序完全退出时该进程会被系统杀掉):
protected void onDestroy() {
        Process.killProcess(Process.myPid());
        System.exit(0);
}

◆  进程的等级

        我们可以将一些组件运行在其他进程中,并且可以为任意的进程添加线程。组件运行在哪个进程中是在manifest文件里设置的,其中<Activity>,<Service>,<receiver>和<provider>都有一个process属性来指定该组件运行在哪个进程之中。我们可以设置这个属性,使得每个组件运行在它们自己的进程中,或是几个组件共同享用一个进程,或是不共同享用。<application>元素也有一个process属性,用来指定所有的组件的默认属性。
        Android会根据进程中运行的组件类别以及组件的状态来判断该进程的重要性,Android会首先停止那些不重要的进程。按照重要性从高到低一共有五个级别:
1. 前台进程
        前台进程是用户当前正在使用的进程。只有一些前台进程可以在任何时候都存在。他们是最后一个被结束的,当内存低到根本连他们都不能运行时,设备才会进行内存调度,中止一些前台进程来保持对用户交互的响应。
2. 可见进程
        可见进程不包含前台的组件但是会在屏幕上显示一个可见的进程,除非前台进程需要获取它的资源,不然不会被中止。
3. 服务进程
运行着一个通过startService()方法启动的service,这个service不属于上面提到的两种。service所在进程虽然对用户不是直接可见的,但是他们执行了用户非常关心的任务(比如播放MP3,从网络下载数据)。只要前台进程和可见进程有足够的内存,系统不会回收他们。
4. 后台进程
运行着一个队用户不可见的activity(调用过onStop()方法),这些进程对用户体验没有直接的影响,可以在服务进程、可见进程、前台进程需要时回收。
5. 空进程
未运行任何程序组件。运行这些进程唯一的原因是作为一个缓存,缩短下次程序需要重新使用的启动时间。系统经常中止这些进程,这样可以调节程序缓存和系统缓存的平衡。

二、进程间的通信 IPC(inter process communication)

在应用中,进程相当于车间,而线程相当于车间里的生产线。进程之间的内存和资源是不共享的,所以我们在多进程的使用中,要实现进程之间的通信。进程间通信有两种实现方式:
 用Messenger ——>Handler (适用于多进程单线程的情况,此时不用考虑线程安全问题 )
 自己实现AIDL (Android Interface Definition Language,适用于多进程多线程)

1. messenger发送消息的方法

        Messenger的使用包括两个地方,一个是service端,一个是client端。
1. 先准备好一个Message,这个message可以通过Message.botain(Handler h,int what)获得,可以添加Bundle数据以及replyTo;
2. 准备一个Messenger,这个Messenger可以通过new Messenger-Handler()或者msg.replyTo获得;
3. Messenger.send(msg)发送Message数据;
4. 在Handler的handleMessage()函数中获得指定what的msg,进行处理。
注意:Messenger可以传递的数据类型由Message可以传递的数据类型决定,如果想传递一个自定义的类,那么必须要保证这个类通过Parcelable或者Serializable序列化,然后放到Bundle对象中通过Message传递。

MessengerService类的实现:
public class MessengerService extends Service {

    private Handler messengerHandler = new Handler() {
       //创建Handler用于处理MessengerActivity中传递的Message对象
        public void handleMessage(Message message) {
            switch (message.what) {
                case 0:
                    //获取内容并Toast
                    Toast.makeText(MessengerService.this, message.getData().getString("content"), Toast.LENGTH_SHORT).show();
                    //获取MessengerActivity中replyMessenger对象,用来返回消息
                    Messenger messenger = message.replyTo;
                    //创建返回消息对象
                    Message replyMessage = Message.obtain(null, 0);
                    Bundle bundle = new Bundle();
                    bundle.putString("reply", "我已经收到消息");
                    replyMessage.setData(bundle);
                    try {
                        //给MessengerActivity发送消息
                        messenger.send(replyMessage);
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                    break;
                default:
                    break;
            }
        }
    };

    private Messenger mMessenger = new Messenger(messengerHandler);

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        //返回IBinder对象
        return mMessenger.getBinder();
    }
}
MessengerActivity类的实现:
public class MessengerActivity extends Activity {

    private ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            //通过服务返回的IBinder对象创建Messenger对象
            Messenger messenger = new Messenger(service);
            //创建消息对象
            Message message = new Message();
            message.what = 0;
            Bundle bundle = new Bundle();
            bundle.putString("content","通过Messenger进行跨进程通信");
            message.setData(bundle);
            //将接受消息的replyMessenger传递给MessengerService
            message.replyTo = replyMessenger;
            try {
                messenger.send(message);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

    /**
     * 用于接收MessengerService传递来的数据Message对象
     */
    private Messenger replyMessenger = new Messenger(new Handler(){
        public  void handlerMessage(Message message){
            switch (message.what){
                case 0:
                    //获取信息内容并Toast
                    Toast.makeText(MessengerActivity.this,message.getData().getString("reply"),Toast.LENGTH_SHORT).show();
                    break;
                default:
                    break;
            }
        }
    });

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_messenger);
        //绑定服务
        bindService(new Intent(this,MessengerService.class),mServiceConnection, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(mServiceConnection);
    }
}

2. AIDL(Android Interface definition language安卓接口定义语言)实现通信

因为Messenger只适用于跨进程的单线程通讯,当处理多线程问题时,我们就需要使用AIDL进行通讯。
1. 定义AIDL文件
我们可以在main文件夹下创建一个aidle文件夹,在该文件夹下面点击NEW选择新建AIDL文件,系统会自动生成一个名叫IMyAidInterface.aidl的文件(如下)。保存后Android编译器会在gen目录下自动生成IMyAidInterface.java文件,确保这些AIDL使用的环境创建完成;
// IMyAidlInterface.aidl
package com.example.administrator.threadexercise;

// Declare any non-default types here with import statements

interface IMyAidlInterface {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
            double aDouble, String aString);
<span style="white-space:pre">	</span>//以上为系统自动生成代码,也可以自己增加方法
    String getName(String nickName);
}
2. 定义服务类AIDLService
public class AIDLService extends Service {
    /**
     * 实例化Stub类,Stub是该接口的一个内部类,继承自bundle
     */
    IMyAidlInterface.Stub mStub = new IMyAidlInterface.Stub() {
        //实现IMyAidInterface.aidl中的方法,这样就可以通过IMyAidlInterface接口实现对Service的控制
        @Override
        public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {

        }

        @Override
        public String getName(String nickName) throws RemoteException {
            return nickName + "aidl_hahaha";
        }
    };

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        //返回IBinder对象
        return mStub;
    }
}
3. 定义AIDLActivity类
public class AIDLActivity extends Activity {

    private ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            //通过服务返回的IBinder创建IMyAidInterface对象
            mIMyAidlInterface = IMyAidlInterface.Stub.asInterface(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };
    private IMyAidlInterface mIMyAidlInterface;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_aidl);

        findViewById(R.id.button2).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mIMyAidlInterface != null){
                    try {
                        //调用getName方法
                        String name = mIMyAidlInterface.getName("nice_know_maco");
                        Toast.makeText(AIDLActivity.this,name+"",Toast.LENGTH_SHORT).show();
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                }
            }
        });

        bindService(new Intent(this, AIDLService.class),mServiceConnection, Context.BIND_AUTO_CREATE);
    }
}








0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:8374次
    • 积分:369
    • 等级:
    • 排名:千里之外
    • 原创:29篇
    • 转载:0篇
    • 译文:0篇
    • 评论:0条
    文章分类