Android进程间和线程间通信方式

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android进程间和线程间通信方式相关的知识,希望对你有一定的参考价值。

参考技术A         进程:是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位。

  线程:是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。线程自己基本上不拥有系统资源,只拥有一些在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。

  区别:

  (1)、一个程序至少有一个进程,一个进程至少有一个线程;

  (2)、线程的划分尺度小于进程,使得多线程程序的并发性高;

  (3)、进程在执行过程中拥有独立的内存单元,而多个线程共享内存,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉。

---------------------

一、android进程间通信方式

1.Bundle

  由于Activity,Service,Receiver都是可以通过Intent来携带Bundle传输数据的,所以我们可以在一个进程中通过Intent将携带数据的Bundle发送到另一个进程的组件。

  缺点:无法传输Bundle不支持的数据类型。

2.ContentProvider

  ContentProvider是Android四大组件之一,以表格的方式来储存数据,提供给外界,即Content Provider可以跨进程访问其他应用程序中的数据。用法是继承ContentProvider,实现onCreate,query,update,insert,delete和getType方法,onCreate是负责创建时做一些初始化的工作,增删查改的方法就是对数据的查询和修改,getType是返回一个String,表示Uri请求的类型。注册完后就可以使用ContentResolver去请求指定的Uri。

3.文件

  两个进程可以到同一个文件去交换数据,我们不仅可以保存文本文件,还可以将对象持久化到文件,从另一个文件恢复。要注意的是,当并发读/写时可能会出现并发的问题。

4.Broadcast

  Broadcast可以向android系统中所有应用程序发送广播,而需要跨进程通讯的应用程序可以监听这些广播。

5.AIDL方式

  Service和Content Provider类似,也可以访问其他应用程序中的数据,Content Provider返回的是Cursor对象,而Service返回的是Java对象,这种可以跨进程通讯的服务叫AIDL服务。

         AIDL通过定义服务端暴露的接口,以提供给客户端来调用,AIDL使服务器可以并行处理,而Messenger封装了AIDL之后只能串行运行,所以Messenger一般用作消息传递。

6.Messenger

  Messenger是基于AIDL实现的,服务端(被动方)提供一个Service来处理客户端(主动方)连接,维护一个Handler来创建Messenger,在onBind时返回Messenger的binder。

  双方用Messenger来发送数据,用Handler来处理数据。Messenger处理数据依靠Handler,所以是串行的,也就是说,Handler接到多个message时,就要排队依次处理。

7.Socket

  Socket方法是通过网络来进行数据交换,注意的是要在子线程请求,不然会堵塞主线程。客户端和服务端建立连接之后即可不断传输数据,比较适合实时的数据传输

二、Android线程间通信方式

  一般说线程间通信主要是指主线程(也叫UI线程)和子线程之间的通信,主要有以下两种方式:

1.AsyncTask机制

  AsyncTask,异步任务,也就是说在UI线程运行的时候,可以在后台的执行一些异步的操作;AsyncTask可以很容易且正确地使用UI线程,AsyncTask允许进行后台操作,并在不显示使用工作线程或Handler机制的情况下,将结果反馈给UI线程。但是AsyncTask只能用于短时间的操作(最多几秒就应该结束的操作),如果需要长时间运行在后台,就不适合使用AsyncTask了,只能去使用Java提供的其他API来实现。

2.Handler机制

  Handler,继承自Object类,用来发送和处理Message对象或Runnable对象;Handler在创建时会与当前所在的线程的Looper对象相关联(如果当前线程的Looper为空或不存在,则会抛出异常,此时需要在线程中主动调用Looper.prepare()来创建一个Looper对象)。使用Handler的主要作用就是在后面的过程中发送和处理Message对象和让其他的线程完成某一个动作(如在工作线程中通过Handler对象发送一个Message对象,让UI线程进行UI的更新,然后UI线程就会在MessageQueue中得到这个Message对象(取出Message对象是由其相关联的Looper对象完成的),并作出相应的响应)。

三、Android两个子线程之间通信

  面试的过程中,有些面试官可能会问Android子线程之间的通信方式,由于绝大部分程序员主要关注的是Android主线程和子线程之间的通信,所以这个问题很容易让人懵逼。

  主线程和子线程之间的通信可以通过主线程中的handler把子线程中的message发给主线程中的looper,或者,主线程中的handler通过post向looper中发送一个runnable。但looper默认存在于main线程中,子线程中没有Looper,该怎么办呢?其实原理很简单,把looper绑定到子线程中,并且创建一个handler。在另一个线程中通过这个handler发送消息,就可以实现子线程之间的通信了。

  子线程创建handler的两种方式:

  方式一:给子线程创建Looper对象:

new Thread(new Runnable()

            public void run()  

                Looper.prepare();  // 给这个Thread创建Looper对象,一个Thead只有一个Looper对象

                Handler handler = new Handler() 

                    @Override 

                    public void handleMessage(Message msg)  

                        Toast.makeText(getApplicationContext(), "handleMessage", Toast.LENGTH_LONG).show(); 

                     

                ; 

                handler.sendEmptyMessage(1); 

                Looper.loop(); // 不断遍历MessageQueue中是否有消息

            ; 

        ).start();

---------------------

       方式二:获取主线程的looper,或者说是UI线程的looper:

new Thread(new Runnable()

            public void run()  

                Handler handler = new Handler(Looper.getMainLooper()) // 区别在这!!! 

                    @Override 

                    public void handleMessage(Message msg)  

                        Toast.makeText(getApplicationContext(), "handleMessage", Toast.LENGTH_LONG).show(); 

                     

                ; 

                handler.sendEmptyMessage(1); 

            ; 

        ).start();

---------------------

Android进程间的通信之Messenger

Android进程间的通信方式可以通过以下两种方式完成:

1 Android接口定义语言(AIDL)
2 使用Messenger绑定服务

本文我们将学习使用Messenger绑定服务的方式进行进程间的通信。

Android AIDL和Messenger区别

使用Messenger是执行进程间通信最简单的方法,因为Messenger会在单一线程中创建包含所有请求的队列,这样您就不必对服务进行线程安全设计。而纯粹的AIDL接口会同时向服务发送多个请求,服务随后必须应对多线程处理。AIDL通常应用在服务被设计到单独的应用中的场景(即服务端可客户端不属于同一个app的情况),而Messenger通常应用在同一app的不同进程的场景中。

Messenger基本思想

服务端(被动方)提供一个Service来处理客户端(主动方)连接,维护一个Handler(具体来讲:是Handler的子类)来创建Messenger,在onBind时返回Messenger的binder(调用Messenger的getBinder()方法,该方法返回一个IBinder对象,客户端将通过该对象作为参数创建一个Messenger对象用于与服务端进行通信)。

Messenger使用步骤

1、服务端实现一个Handler,由其接收来自客户端的每个调用的回调
2、使用第1步的Handler的实例作为target创建Messenger对象(即该Messenger持有了对Handler的引用)
3、使用Messenger创建一个IBinder(通过调用Messenger的getBinder()方法),服务端的onBind()方法中将其返回到客户端
4、客户端使用IBinder将Messenger(引用服务端的Handler实例)实例化,然后使用后者将Message对象发送给服务端
5、服务端在其Handler中接收每个Message

这样,客户端并没有调用服务端的“方法”,而客户端传递的消息(Message对象)是服务端在其Handler中接收到的。

如果想让服务端对客户端发回响应,则还需要在客户端中创建一个持有客户端Handler实现类的Messenger,当客户端收到onServiceConnected()回调时,在向服务发送的Message时,send()方法的replyTo参数中需包含客户端的Messenger。这样,客户端就可在其Handler实现类中接收到来自服务端的响应消息。

简单示例

AndroidMainfest.xml

<application
    android:allowBackup="true"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme" >
    <activity
        android:name="yf.exam.client.MainActivity"
        android:label="@string/app_name" >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
    <service android:name=".MessengerService" android:process=":custom_process"/>
</application>

 

在上面的配置文件中,service的android:process属性用于在一个单独进程中启动service,看如下图片:

技术分享

布局文件很简单,这里只有一个按钮,用于向服务端发送消息并显示服务端响应内容,这里不再给出。

客户端:MainActivity

 1 public class MainActivity extends Activity {
 2     private static final int REPLY_MSG_ID = 2;
 3     private boolean mServiceConnected = false;
 4     private Button btn = null;
 5     //用于向Service端发送消息的Messenger
 6     private Messenger mBoundServiceMessenger = null;
 7     //用于接收Service发送消息的Messenger
 8     private final Messenger mReceiveMessenger = new Messenger(new ReceiveMessHandler(this));
 9     private ServiceConnection conn = new ServiceConnection() {
10         @Override
11         public void onServiceDisconnected(ComponentName name) {
12             mBoundServiceMessenger = null;
13             mServiceConnected = false;
14         }
15         
16         @Override
17         public void onServiceConnected(ComponentName name, IBinder service) {
18             mBoundServiceMessenger = new Messenger(service);
19             mServiceConnected = true;
20         }
21     };
22     @Override
23     protected void onCreate(Bundle savedInstanceState) {
24         super.onCreate(savedInstanceState);
25         setContentView(R.layout.activity_main);
26         btn = (Button)findViewById(R.id.button);
27         bindService(new Intent(this, MessengerService.class), conn, Context.BIND_AUTO_CREATE);
28         btn.setOnClickListener(new View.OnClickListener() {
29             @Override
30             public void onClick(View v) {
31                 if(mServiceConnected){
32                     //获取消息对象
33                     Message msg = Message.obtain(null, 1, 0, 0);
34                     try{
35                         //replyTo参数包含客户端Messenger
36                         msg.replyTo = mReceiveMessenger;
37                         //向Service端发送消息
38                         mBoundServiceMessenger.send(msg);
39                     }catch(RemoteException re){
40                         re.printStackTrace();
41                     }
42                 }
43             }
44         });
45     }
46     @Override
47     protected void onDestroy() {
48         super.onDestroy();
49         if(mServiceConnected){
50             unbindService(conn);
51             mServiceConnected = false;
52         }
53     }
54     /**
55      * 客户端实现一个Handler用于接收服务端返回的响应
56      * @author Administrator
57      *
58      */
59     static class ReceiveMessHandler extends Handler{
60         //持有当前Activity的弱引用,避免内存泄露
61         private final WeakReference<MainActivity> mActivity;
62         public ReceiveMessHandler(MainActivity activity){
63             mActivity = new WeakReference<MainActivity>(activity);
64         }
65         @Override
66         public void handleMessage(Message msg) {
67             switch(msg.what){
68             case REPLY_MSG_ID:
69                 Toast.makeText(mActivity.get(), msg.getData().getString("msg"), Toast.LENGTH_SHORT).show();
70                 break;
71             }
72         }
73     }
74 }

服务端:MessengerService.java

 1 public class MessengerService extends Service {
 2     private static final int REPLY_MSG_ID = 2;
 3     private static final int MSG_ID = 1;
 4     static class BoundServiceHandler extends Handler{
 5         private final WeakReference<MessengerService> mService;
 6         public BoundServiceHandler(MessengerService service){
 7             mService = new WeakReference<MessengerService>(service);
 8         }
 9         @Override
10         public void handleMessage(Message msg) {
11             switch(msg.what){
12             case MSG_ID:
13                 Messenger replyMessenger = msg.replyTo;
14                 Message replyMsg = Message.obtain(null, REPLY_MSG_ID);
15                 //向客户端响应的消息内容
16                 Bundle b = new Bundle();
17                 b.putString("msg", "this is the message reply from service");
18                 replyMsg.setData(b);
19                 try{
20                     replyMessenger.send(replyMsg);
21                 }catch(RemoteException re){
22                     re.printStackTrace();
23                 }
24                 break;
25                 default:
26                     super.handleMessage(msg);
27             }
28         }
29     }
30     private final Messenger mMessenger = new Messenger(new BoundServiceHandler(this));
31     @Override
32     public IBinder onBind(Intent intent) {
33         Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show();
34         return mMessenger.getBinder();
35     }
36 }

此外,上述例子中所有的Handler的实现类都被声明为static并使用Service或Activity的WeakReference。如果不这样做,编译器会给出警告信息“This handler class should be static or leaks might occur”。通过使用弱引用的方式,就允许Service或Activity进行垃圾收集了。



以上是关于Android进程间和线程间通信方式的主要内容,如果未能解决你的问题,请参考以下文章

进程与线程的区别,进程间通信方式,线程间通信方式

Android 线程间通信

Android开发——进程间通信之AIDL

Android进程间的通信之Messenger

Android进程间的通信之Messenger

线程间的通信同步方式与进程间通信方式