2018 Android 进程间通信与线程间通信总结_安卓多线程与ui通信实验心得总结-程序员宅基地

技术标签: java  进程间通信  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)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Sqq_yj/article/details/85328903

智能推荐

几个最短路径算法Floyd、Dijkstra、Bellman-Ford、SPFA的比较_请设计测试dijkstra算法,floyd算法,bellman-ford算法性能的python代码,-程序员宅基地

文章浏览阅读1.4k次。几个最短路径算法的比较:Floyd 求多源、无负权边的最短路。用矩阵记录图。时效性较差,时间复杂度O(V^3)。 Floyd-Warshall算法(Floyd-Warshall algorithm)是解决任意两点间的最短路径的一种算法,可以正确处理有向图或负权的最短路径问题。Floyd-Warshall算法的时间复杂度为O(N^3),空间复杂度为O(N^2)_请设计测试dijkstra算法,floyd算法,bellman-ford算法性能的python代码,三种算法各

AI 虚拟试衣 论文汇总-程序员宅基地

文章浏览阅读240次。猜您喜欢:深入浅出stable diffusion:AI作画技术背后的潜在扩散模型论文解读戳我,查看GAN的系列专辑~!一顿午饭外卖,成为CV视觉的前沿弄潮儿!最新最全100篇汇总!生成扩散模型Diffusion ModelsECCV2022 | 生成对抗网络GAN部分论文汇总CVPR 2022 | 25+方向、最新50篇GAN论文ICCV 2021 | 35个主题GAN论文汇总超110篇!C..._ai试穿论文参考文献近三年怎么写

SpringBoot+Mybatis+MySQL实现读写分离_springboot+mybatisplus+mysql主从读写分离-程序员宅基地

文章浏览阅读218次。在Springboot中使用数据库主从复制实现读写分离,操作数据时操作主表,查询操作使用从表。我就直接跳过创建SpringBoot应用的步骤了,直接开始操作如何配置读写分离。1、我的Maven依赖如下,大家可以复制<?xmlversion="1.0"encoding="UTF-8"?><projectxmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema..._springboot+mybatisplus+mysql主从读写分离

搜索引擎有哪些,搜索引擎网站大全_链接搜索引擎-程序员宅基地

文章浏览阅读9.1k次。通过搜索引擎网站搜索,可以帮助我们快速找到自己需要的内容。很多同学只知道百度搜索,不知道还有其他什么搜索引擎网站。小编就来和大家分享搜索引擎网站有哪些,搜索引擎网站大全。_链接搜索引擎

vue监听浏览器网页关闭和网页刷新_vue监听网页关闭浏览器关闭事件-程序员宅基地

文章浏览阅读3.3k次。vue监听浏览器网页关闭和网页刷新_vue监听网页关闭浏览器关闭事件

sonar 检测 Call “Optional#isPresent()“ before accessing the value.(java 8 版本)_call "optional#ispresent()" before accessing the v-程序员宅基地

文章浏览阅读8.7k次,点赞4次,收藏11次。目录问题代码解决问题的背景知识java8 Optional 的使用规范要求的规则。Java 8 Stream修改策略java8方法1方式2问题代码public class demoUtil { public static Long methdName(List<EnterpriseSolutionsSeq> seqList){ if(CollUtil.isEmpty(seqList)){ return null; } // 下面这行代码会被sonar检测有问题,因为在对O_call "optional#ispresent()" before accessing the value.

随便推点

ES深分页、浅分页_es中scroll分页原理-程序员宅基地

文章浏览阅读3.8k次。ES深分页、浅分页_es中scroll分页原理

韩文T9宫格输入法的实现_韩语键盘九宫格-程序员宅基地

文章浏览阅读2.9k次。韩文输入法(HANGUL)以及韩文9宫格输入法的实现过程_韩语键盘九宫格

浅谈WPF之控件拖拽与拖动-程序员宅基地

文章浏览阅读434次。使用过office的visio软件画图的小伙伴都知道,画图软件分为两部分,左侧图形库,存放各种图标,右侧是一个画布,将左侧图形库的图标控件拖拽到右侧画布,就会生成一个新的控件,并且可以自由拖动。那如何在WPF程序中,实现类似的功能呢?今天就以一个简单的小例子,简述如何在WPF中实现控件的拖拽和拖动,仅供学习分享使用,如有不足之处,还请指正。涉及知识点WPF控件的拖拽与拖动,主要涉及的知识点如下所示..._wpf中如何拖动按钮

Flutter笔记:拖拽手势_flutter 手动拖拽-程序员宅基地

文章浏览阅读926次。在 Flutter 中,GestureDetector 组件可以识别和处理各种手势,包括拖拽手势。GestureDetector 提供了一系列的回调函数,这些函数在不同的手势事件发生时被调用,例如当手势开始、更新或结束时。对于拖拽手势,GestureDetector 提供了专门的回调函数来处理垂直拖拽、水平拖拽和二维拖拽。在构建交互式应用程序时,处理用户的手势输入是至关重要的一部分。Flutter 提供了一套丰富的手势识别系统,使得开发者可以轻松地实现各种手势操作,如点击、双击、拖拽、缩放等。_flutter 手动拖拽

198、仿真-基于51单片机函数波形发生器调幅度频率波形Proteus仿真(程序+Proteus仿真+原理图+流程图+元器件清单+配套资料等)_proteus平衡调幅电路仿真-程序员宅基地

文章浏览阅读608次。方案一:STM32系列单片机控制,该型号单片机为LQFP44封装,内部资源足够用于本次设计。STM32F103系列芯片最高工作频率可达72MHZ,在存储器的01等等待周期仿真时可达到1.25Mip/MHZ(Dhrystone2.1)。内部128k字节的闪存程序存储器,也就是说代码量可以写到128k字节,本次设计足够,内部高达20K字节的SRAM。_proteus平衡调幅电路仿真

启动tomcat不用安装jdk_启动tomcat 不用安装jdk-程序员宅基地

文章浏览阅读4.2k次。本人使用的tomcat6.0.411.找一个安装好的jre(我的jre7),把jre整个文件夹复制放入tomcat的目录中2.打开bin/Catalina.bat 加入 set JRE_HOME=..\jre73.打开bin/setclasspath.bat 加入 set JRE_HOME=..\jre74.打开bin/startup.bat_启动tomcat 不用安装jdk

推荐文章

热门文章

相关标签