2018 Android 进程间通信与线程间通信总结

简述

一般来说,Android中为一个应用程序开启一个进程进行执行,在这个应用程序中的所有组件,通过单独的线程进行执行,而其中所有的线程,共享该应用程序进程的资源。当一个应用程序启动的时候,Android系统启动一个新的Linux应用程序的进程和一个执行线程。默认情况下,一个应用程序运行中的所有组件运行在相同的进程和线程中,这里的线程一般称为主线程。如果一个应用程序的组件开始的时候,已经存在一个进程,那么应用程序会在与它相同的执行线程中开始这个组件。

进程

如果需要控制某个组件所属的进程,则可在清单文件中执行以下操作
各类组件标签:< activity >、< service >、< receiver > 和 < provider >等均支持 android:process 属性,此属性可以指定该组件应在哪个进程运行,通过此属性可以使每个组件均在各自的进程中运行,或者使一些组件共享一个进程,而其他组件则不共享。 此外,还可以通过该属性使不同应用的组件在相同的进程中运行,但前提是这些应用共享相同的 Linux 用户 ID 并使用相同的证书进行签署
此外,< application > 元素也支持 android:process 属性,以设置适用于所有组件的默认值
如果内存不足而系统又需要内存时,系统可能会在某一时刻关闭某一进程,Android 系统将权衡所有进程对用户的相对重要程度来决定终止哪个进程,被终止的进程中运行的应用组件也会随之销毁, 当这些组件需要再次运行时,系统将为它们重启进程。

进程间通信的几种方式:

  1. Bundle/Intent传递数据:
    可传递基本类型,String,实现了Serializable或Parcellable接口的数据结构。Serializable是Java的序列化方法,Parcellable是Android的序列化方法,前者代码量少(仅一句),但I/O开销较大,一般用于输出到磁盘或网卡;后者实现代码多,效率高,一般用户内存间序列化和反序列化传输。

  2. 文件共享:
    对同一个文件先后写读,从而实现传输,Linux机制下,可以对文件并发写,所以要注意同步。顺便一提,Windows下不支持并发读或写。

  3. Messenger:
    Messenger是基于AIDL实现的,服务端(被动方)提供一个Service来处理客户端(主动方)连接,维护一个Handler来创建Messenger,在onBind时返回Messenger的binder。
    双方用Messenger来发送数据,用Handler来处理数据。Messenger处理数据依靠Handler,所以是串行的,也就是说,Handler接到多个message时,就要排队依次处理。

  4. AIDL:
    AIDL通过定义服务端暴露的接口,以提供给客户端来调用,AIDL使服务器可以并行处理,而Messenger封装了AIDL之后只能串行运行,所以Messenger一般用作消息传递。
    通过编写aidl文件来设计想要暴露的接口,编译后会自动生成响应的java文件,服务器将接口的具体实现写在Stub中,用iBinder对象传递给客户端,客户端bindService的时候,用asInterface的形式将iBinder还原成接口,再调用其中的方法。

  5. ContentProvider:
    系统四大组件之一,底层也是Binder实现,主要用来为其他APP提供数据,可以说天生就是为进程通信而生的。自己实现一个ContentProvider需要实现6个方法,其中onCreate是主线程中回调的,其他方法是运行在Binder之中的。自定义的ContentProvider注册时要提供authorities属性,应用需要访问的时候将属性包装成Uri.parse(“content://authorities”)。还可以设置permission,readPermission,writePermission来设置权限。 ContentProvider有query,delete,insert等方法,看起来貌似是一个数据库管理类,但其实可以用文件,内存数据等等一切来充当数据源,query返回的是一个Cursor,可以自定义继承AbstractCursor的类来实现。

  6. Socket:
    学过计算机网络的对Socket不陌生,所以不需要详细讲述。只需要注意,Android不允许在主线程中请求网络,而且请求网络必须要注意声明相应的permission。然后,在服务器中定义ServerSocket来监听端口,客户端使用Socket来请求端口,连通后就可以进行通信。

线程

应用启动时,系统会为应用创建一个名为“主线程”的执行线程。 此线程非常重要,因为它负责将事件分派给相应的用户界面小部件,其中包括绘图事件。此外,它也是应用与 Android UI 工具包组件(来自 android.widget 和 android.view 软件包的组件)进行交互的线程。因此,主线程也称为 UI 线程
系统不会为每个组件实例创建单独的线程。运行于同一进程的所有组件均在 UI 线程中实例化,并且对每个组件的系统调用均由该线程进行分派。 因此,响应系统回调的方法(比如报告用户操作的 onKeyDown() 或生命周期回调方法)始终在进程的 UI 线程中运行

此外,Android UI 工具包并非线程安全工具包。因此不能通过工作线程操纵 UI,而只能通过 UI 线程操纵用户界面。 因此,Android 的单线程模式必须遵守两条规则:

  • 不要阻塞 UI 线程
  • 不要在 UI 线程之外访问 Android UI 工具包

线程间通信的几种方式:

  1. 通过Handler机制
    主线程中定义Handler,子线程发消息,通知Handler完成UI更新,Handler对象必须定义在主线程中,如果是多个类直接互相调用,就不是很方便,需要传递content对象或通过接口调用。另外Handler机制与Activity生命周期不一致的原因,容易导致内存泄漏,不推荐使用。主线程中定义Handler,子线程发消息,通知Handler完成UI更新,Handler对象必须定义在主线程中,如果是多个类直接互相调用,就不是很方便,需要传递content对象或通过接口调用。另外Handler机制与Activity生命周期不一致的原因,容易导致内存泄漏,不推荐使用。
    private void handlerTest() {
        handler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                switch (msg.what) {
                    case 486:
                        tv.setText("" + msg.obj);
                        break;
                }
            }
        };
        new Thread() {
            @Override
            public void run() {
                super.run();
                for (int i = 0; i < 9; i++) {
                    try {
                        sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                Message message = new Message();
                message.what = 486;
                message.obj = "通过Handler机制";
                handler.sendMessage(message);
            }
        }.run();
    }
  1. runOnUiThread方法
    用Activity对象的runOnUiThread方法更新,在子线程中通过runOnUiThread()方法更新UI,强烈推荐使用。
  private void runOnUiThreadTest() {
        new Thread() {
            @Override
            public void run() {
                super.run();
                for (int i = 0; i < 9; i++) {
                    try {
                        sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        tv.setText("通过runOnUiThread方法");
                    }
                });
            }
        }.run();
    }
  1. View.post(Runnable runnable )
    这种方法更简单,但需要传递要更新的View过去,推荐使用
    private void postRunnableTest() {
        new Thread() {
            @Override
            public void run() {
                super.run();
                for (int i = 0; i < 9; i++) {
                    try {
                        sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                tv.post(new Runnable() {
                    @Override
                    public void run() {
                        tv.setText("通过View.post(Runnable runnable) 方法");
                    }
                });
            }
        }.run();
    }
  1. AsyncTask
    private void AsyncTaskTest() {
        new MyAsyncTask().execute("通过AsyncTask方法");
    }

	private class MyAsyncTask extends AsyncTask {
  	  @Override
  	  protected Object doInBackground(Object[] objects) {
     	   for (int i = 0; i < 3; i++) {
         	   try {
            	    sleep(1000);
           		 } catch (InterruptedException e) {
            	    e.printStackTrace();
            }
        }
        return objects[0].toString();
    }

	    @Override
  	  protected void onPostExecute(Object o) {
  	      super.onPostExecute(o);
   	     tv.setText(o.toString());
  	  }
}

借鉴查阅资料:
(https://www.jianshu.com/p/5d0e53d7761e)
(https://www.cnblogs.com/lizhengxian/p/5075635.html)
(https://blog.csdn.net/liuxingyuzaixian/article/details/78893392)

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值