关于android进程间通信(handler、messenger、AIDL)

关于进程间通信,首先需要思考几个问题:

 

1.进程间通信适用什么场合?

2.进程和线程区别是什么?

3.Handler用于线程间通信,可以实现进程间通信吗?

4.跨进程通信messager

5.跨进程通信AIDL



就按照上边的步骤我们去开始了解并且熟悉进程间通信。


1.进程间通信


进程间通信就是在不同进程之间传播或交换信息,那么不同进程之间存在着什么双方都可以访问的介质呢?进程的用户空间是互相独立的,一般而言是不能互相访问的,唯一的例外是共享内存区。但是,系统空间却是“公共场所”,所以内核显然可以提供这样的条件。除此以外,那就是双方都可以访问的外设了。

进程间通信(IPC,Interprocess communication)是一组编程接口,让程序员能够协调不同的程序进程,使之能在一个操作系统里同时运行。这使得一个程序能够在同一时间里处理许 多用户的要求。因为即使只有一个用户发出要求,也可能导致一个操作系统中多个进程的运行,进程之间必须互相通话。IPC接口就提供了这种可能性。每个 IPC方法均有它自己的优点和局限性,因此,对于单个程序而言使用所有的IPC方法是不常见的。

进程通信使用场合:

1)数据传输:一个进程需要将它的数据发送给另一个进程,发送的数据量在一个字节到几兆字节之间。

2)共享数据:多个进程想要操作共享数据,一个进程对共享数据的修改,别的进程应该立刻看到。

3)通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止时要通知父进程)。

4) 资源共享:多个进程之间共享同样的资源。为了作到这一点,需要内核提供锁和同步机制。

5)进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另一个进程的所有陷入和异常,并能够及时知道它的状态改变。

进程通过与内核及其它进程之间的互相通信来协调它们的行为。

 

 

综上所述,对于android开发人员来说,就是你开发了两个app,要数据共享,而又不能对其他app共享,比如账号密码。

 

2.进程和线程

进程是具有一定独立功能的程序,是系统进行资源分配和调度的一个独立单位。

线程是进程中的一个实体,是cpu分配资源和调度的基本单位

一个程序至少有一个进程,一个进程至少有一个线程,线程的划分尺度小于进程。

进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。

     线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。

    从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配。这就是进程和线程的重要区别。

 

 

3.Handler

 

 

主要接受子线程发送的数据, 并用此数据配合主线程更新UI

 

handler可以分发Message对象和Runnable对象到主线程中, 每个Handler实例,都会绑定到创建他的线程中(一般是位于主线程),它有两个作用:

(1)安排消息或Runnable 在某个主线程中某个地方执行;

(2)安排一个动作在不同的线程中执行

 使用:

首先,我们定义两个service,一个默认进程,一个在remote进程。



默认进程service


public class ThreadHandlerService extends Service {
    public ThreadHandlerService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        return new ThreadLocalBinder();
    }


    public void sayHi(){
        Toast.makeText(ThreadHandlerService.this, "Hi,I'm thread service!", Toast.LENGTH_SHORT).show();
    }

    public class ThreadLocalBinder extends Binder{

        public ThreadHandlerService getService(){

            return ThreadHandlerService.this;
        }
    }
}


remote service



<span style="font-size:18px;">public class ProHandlerService extends Service {
    public ProHandlerService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        return new ProLocalBinder();
    }


    public void sayHi(){
        Toast.makeText(ProHandlerService.this, "Hi,I'm pro service!", Toast.LENGTH_SHORT).show();
    }

    public class ProLocalBinder extends Binder{

        public ProHandlerService getService(){

            return ProHandlerService.this;
        }
    }
}</span>

他们的代码基本相似,区别不在这里,而是在配置文件

<span style="font-size:18px;"><service
            android:name=".service.ThreadHandlerService"
            android:enabled="true"
            android:exported="true" />
        <service
            android:name=".service.ProHandlerService"
            android:enabled="true"
            android:exported="true"
            android:process=":remote" /></span>


接下来我们创建两个activity去绑定这两个service,进行连接


public class ThreadConHandlerActivity extends AppCompatActivity {

    private ServiceConnection serviceConnection;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_thread_con);
        initVIew();
    }

    private void initVIew() {
        serviceConnection = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                Log.d("", "service connected");
                ThreadHandlerService threadHandlerService = ((ThreadHandlerService.ThreadLocalBinder)service).getService();
                threadHandlerService.sayHi();
            }

            @Override
            public void onServiceDisconnected(ComponentName name) {
                Log.d("", "service disconnected");
            }
        };
    }

    @Override
    protected void onStart() {
        super.onStart();
        Intent service = new Intent(this.getApplicationContext(),ThreadHandlerService.class);
        this.bindService(service, serviceConnection, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onStop() {
        super.onStop();
        this.unbindService(serviceConnection);
    }
}


你会发现handler是无法在跨进程的线程中传递message的。原因?下篇博文介绍,这里就不重点说了。



4.Messenger




Messager实现IPC通信,底层使用了AIDL方式。和AIDL方式不同的是,Messager方式是利用Handler形式处理,因 此,它是线程安全的,这也表示它不支持并发处理;而AIDL方式是非线程安全的,支持并发处理,因此,我们使用AIDL方式时需要保证代码的线程安全。

大部分情况下,我们应用中不需要并发处理,只需要使用Messager方式



接入代码:

service

public class ProConMessagerService extends Service {

    public static final int MSG_SAY_HELLO = 1;

    public ProConMessagerService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        return messenger.getBinder();
    }



    Handler incomingHandler = new Handler() {

        @Override
        public void handleMessage(Message msg) {
            if(msg.replyTo != null){
                Message msg_client = this.obtainMessage();
                msg_client.what = ProConMessagerActivity.SAY_HELLO_TO_CLIENT;
                msg_client.replyTo = messenger;
                try {
                    ((Messenger) msg.replyTo).send(msg_client);
                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            switch (msg.what) {
                case MSG_SAY_HELLO:
//                    Toast.makeText(ProConMessagerService.this.getApplicationContext(), "Hello World Remote Service!",
//                            Toast.LENGTH_SHORT).show();
                    break;
                default:
                    super.handleMessage(msg);
            }
        }

    };

    Messenger messenger =new Messenger(incomingHandler);

}

activity

public class ProConMessagerActivity extends AppCompatActivity {

    String TAG = "ProConMessagerActivity";
    private ServiceConnection mSc;
    public static final int SAY_HELLO_TO_CLIENT = 1;
    private ListView remoteLv;
    private MessageAdapter messageAdapter;
    private List<MessageInfo> list = new ArrayList<MessageInfo>();
    private int count =0;
    Messenger messenger_reciever = new Messenger(new IncomingHandler());

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_pro_con_messager);
        initView();
    }
    private void initView() {
        remoteLv = (ListView)findViewById(R.id.activity_pro_con_messager_lv);
        messageAdapter = new MessageAdapter(this);
        remoteLv.setAdapter(messageAdapter);
        mSc = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                MessageInfo info = new MessageInfo();
                info.setSender("system");
                info.setReceiver("server,client");
                info.setContent("Hello,service connected");
                info.setCreateTime(String.valueOf(System.currentTimeMillis()));
                list.add(info);
                messageAdapter.setList(list);
                Messenger messenger = new Messenger(service);
                Message msg = new Message();
                msg.what = ProConMessagerService.MSG_SAY_HELLO;
                msg.replyTo = messenger_reciever;
                try {
                    messenger.send(msg);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void onServiceDisconnected(ComponentName name) {
                // 在同service的连接意外丢失时调用这个.比如当service崩溃了或被强杀了.当客户端解除绑定时,这个方法不会被调用.
                Log.d(TAG, "service disconnected");
                MessageInfo info = new MessageInfo();
                info.setSender("system");
                info.setReceiver("server,client");
                info.setContent("Hello,service disconnected");
                info.setCreateTime(String.valueOf(System.currentTimeMillis()));
                list.add(info);
                messageAdapter.setList(list);
            }
        };
    }

    class IncomingHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case SAY_HELLO_TO_CLIENT:
                    MessageInfo info = new MessageInfo();
                    info.setSender("client");
                    info.setReceiver("server");
                    info.setContent("Hello,Server");
                    info.setCreateTime(String.valueOf(System.currentTimeMillis()));
                    list.add(info);
                    messageAdapter.setList(list);
//                    Toast.makeText(ProConMessagerActivity.this.getApplicationContext(), "Hello World Remote Client!",
//                            Toast.LENGTH_SHORT).show();
                    Message msgToServer = new Message();
                    msgToServer.what = ProConMessagerService.MSG_SAY_HELLO;
                    msgToServer.replyTo = messenger_reciever;
                    try {
                        if(count<5){
                            count++;
                            ((Messenger) (msg.replyTo)).send(msgToServer);
                            info = new MessageInfo();
                            info.setSender("server");
                            info.setReceiver("client");
                            info.setContent("Hello,Client!" );
                            info.setCreateTime(String.valueOf(System.currentTimeMillis()));
                            list.add(info);
                            messageAdapter.setList(list);
                        }else{
                            try {
                                ProConMessagerActivity. this.unbindService(mSc);
                                Log.d(TAG, "service disconnected");
                                info = new MessageInfo();
                                info.setSender("system");
                                info.setReceiver("server,client");
                                info.setContent("Hello,service disconnected");
                                info.setCreateTime(String.valueOf(System.currentTimeMillis()));
                                list.add(info);
                                messageAdapter.setList(list);
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        }

                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    }


    @Override
    protected void onStart() {
        super.onStart();
        Log.d(TAG, this.getApplicationContext().getPackageCodePath());
        Intent service = new Intent(this.getApplicationContext(),ProConMessagerService.class);
        this.bindService(service, mSc, Context.BIND_AUTO_CREATE);
    }


    @Override
    protected void onPause() {
        super.onPause();
        try {
            this.unbindService(mSc);
            Log.d(TAG, "service disconnected");
            MessageInfo info = new MessageInfo();
            info.setSender("system");
            info.setReceiver("server,client");
            info.setContent("Hello,service disconnected");
            info.setCreateTime(String.valueOf(System.currentTimeMillis()));
            list.add(info);
            messageAdapter.setList(list);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

5.AIDL


AIDL(Android Interface Definition Language)是一种接口定义语言,编译器通过*.aidl文件的描述信息生成符合通信协议的Java代码,我们无需自己去写这段繁杂的代码,只需要在需要的时候调用即可,通过这种方式我们就可以完成进程间的通信工作。

首先,你需要熟悉一下AIDL的使用,


server端:

创建.aidl文件

实现接口(如果你是使用android studio,发现找不到接口类,你可以先clean下)

client端:

copy server端的aidl到client端aidl下,包名用server端的。

调用远端接口的步骤:

1.         声明.aidl文件中定义的接口类型的变量。

2.         实现ServiceConnection

3.         调用Context.bindService(),传递ServiceConnection的实现

4.         在ServiceConnection.onServiceConnected()方法中会接收到IBinder对象,调用YourInterfaceName.Stub.asInterface((IBinder)service)将返回值转换为YourInterface类型

5.         调用接口中定义的方法。应该总是捕获连接被打断时抛出的DeadObjectException异常,这是远端方法唯一的异常。

6.         调用Context.unbindService()断开连接


贴上部分代码:

public class ProConAidlActivity extends AppCompatActivity implements View.OnClickListener{

    private Button bindBtn,greetBtn,unbindBtn;

    private IPerson person;
    private ServiceConnection mSc;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_pro_con_aidl);
        initView();
    }

    private void initView() {
        bindBtn = (Button)findViewById(R.id.activity_pro_con_aidl_bind);
        greetBtn = (Button)findViewById(R.id.activity_pro_con_aidl_greet);
        unbindBtn = (Button)findViewById(R.id.activity_pro_con_aidl_unbind);
        bindBtn.setOnClickListener(this);
        greetBtn.setOnClickListener(this);
        unbindBtn.setOnClickListener(this);
        bindBtn.setEnabled(true);
        greetBtn.setEnabled(false);
        unbindBtn.setEnabled(false);
        mSc = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                person = IPerson.Stub.asInterface(service);
            }

            @Override
            public void onServiceDisconnected(ComponentName name) {

            }
        };
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.activity_pro_con_aidl_bind:
                Intent intent = new Intent("android.intent.action.AIDLService");
                bindService(intent, mSc, Context.BIND_AUTO_CREATE);
                Log.e("","service connected!");
                bindBtn.setEnabled(false);
                greetBtn.setEnabled(true);
                unbindBtn.setEnabled(true);
                break;
            case R.id.activity_pro_con_aidl_greet:
                try {
                    String retVal = person.greet("aidl ,no do no die");
                    Toast.makeText(ProConAidlActivity.this, retVal, Toast.LENGTH_SHORT).show();
                } catch (RemoteException e) {
                    Toast.makeText(ProConAidlActivity.this, "error", Toast.LENGTH_SHORT).show();
                }
                break;
            case R.id.activity_pro_con_aidl_unbind:
                unbindService(mSc);
                Log.e("", "service disconnected!");
                bindBtn.setEnabled(true);
                greetBtn.setEnabled(false);
                unbindBtn.setEnabled(false);
                break;
        }
    }
}

项目下载地址:下载页面














展开阅读全文

没有更多推荐了,返回首页