Android系统编程入门系列之服务Service齐头并进多线程任务

上篇文章中初步了解了Android系统的四大组件之一的服务Service,在服务内能够执行无用户交互的耗时操做任务,可是包括以前关于界面系列文章在内,生命周期方法都是在主线程内被系统回调的。若是直接在生命周期方法中执行耗时操做,一样可能会在主线程5s内无响应而触发系统对应用程序的ANR异常。为了解决这个问题,就须要使用多线程开发来执行耗时任务,在任务执行结束后将结果返回到主线程中响应。html

什么是线程呢?每一个应用程序在初始化时,默认运行在以其包名命名的进程中,同一进程中的内存是能够共享使用的。而每一个进程在建立时,都会随之建立一个java.lang.Thread实例的线程,用以执行Android系统对当前应用程序的生命周期方法回调,也就是一般意义上的UI界面绘制等任务,这也就是所谓的主线程。而每一个进程在主线程中,能够继续建立多个线程,理论上只要硬件内存支持,线程是能够无限建立的。这些新建立的线程,被称为子线程。子线程中能够执行耗时任务,以此使得主线程中的界面任务保持与用户的及时响应。
值得注意的是,子线程中是不容许执行更新界面相关操做,必须切换回主线程绘制界面。java

任务建立

新任务类须要实现java.lang.Runnable接口,在实现的run()方法中处理须要操做的任务。android

任务执行

在开发中启动新任务的方式主要有三种,其一是直接建立最基础的线程类,单独管理并执行耗时任务;其二是建立一个由一堆线程组成的线程池,将耗时任务放进去执行,剩下的由线程池管理;其三则是使用成熟的并发库,根据不一样的并发库建立及启动任务的方式也将不只限于Runnable类型的实例。另外在Android R即API30之前,还可使用android.os.AsyncTask建立异步任务,可是该方式在API30以后已废弃,故不推荐使用。下面将简单介绍以上三种主流方式。多线程

单独线程

一般使用Thread(Runnable target)构造方法建立子线程,参数 target 做为要执行的任务对象。
以后在须要执行任务的位置调用子线程对象的start()方法启动运行该线程便可。
因为建立的线程是依托于某个界面Activity或服务Service的一个组件,因此当该组件的生命周期方法销毁后,其中建立的子线程也就销毁了。因此子线程必需要在被销毁以前调用interrupt()方法中断运行并释放其占用的资源,以防止发生内存泄漏等问题。并发

线程池

经过线程池管理类java.util.concurrent.ExecutorsnewCachedThreadPool()等系列静态方法,能够直接建立java.util.concurrent.Executor接口定义的线程池类实例化对象。
以后在须要执行任务的位置调用线程池对象的execute(Runnable command)方法便可执行一次任务。
线程池类的优势在于当该组件的生命周期方法销毁后,该线程池及其中的线程都会被强制销毁,不须要手动管理。异步

并发库

关于Android系统的多线程开发,目前已有多个成熟的并发库能够直接使用,包括基于Java的RxJava、基于Kotlin的协程等,然而他们的底层原理都是与上述相似的。至于如何使用现有的多线程开发库,将在后续文章中详细介绍。oop

任务间通讯(多线程通讯)

因为不一样任务是运行在不一样线程中的,因此任务间通讯实际上也是线程间的通讯。这主要经过android.os.Handler类来实现的。说到通讯的话就是一方发送内容和另外一方接收内容的过程,Android系统将要通讯的内容封装为android.os.Message类,其中有 int arg1int arg2两个属性储存简单的数值内容、Object obj属性存储任意类型的对象、int what属性能够标记区分不一样的Message类型。post

通讯接收线程

在须要处理通讯内容的线程中,建立Handler实例化对象。
可使用Handler(Looper looper)构造方法或者createAsync(Looper looper)静态方法,建立处理任意内容的实例化对象。其中的参数 looper 标记当前Handler对象中的处理操做是在哪一个线程,若是是主线程可使用Looper.getMainLooper()静态方法获取android.os.Looper对象,若是是子线程,能够在子线程的run()方法中使用Looper.myLooper()静态方法获取当前线程的Looper对象。google

或者使用Handler(Looper looper, Handler.Callback callback)构造方法或者createAsync(Looper looper, Handler.Callback callback)静态方法,建立须要接收Message消息处理的实例化对象。参数 looper 一样是标记当前Handler对象中的处理操做是在哪一个线程。参数 callbackandroid.os.Handler.Callback接口实现的实例化对象,其中实现的handleMessage(Message msg)方法能够接收并处理通讯的结果。这里的参数 msg 就是收到的Message消息内容。线程

若是是经过Looper.myLooper()静态方法获取的Looper对象,也就是在子线程中处理通讯结果的话,在建立Handler对象先后还要特别调用两个方法。
在上面初始化Handler对象以前,必须在子线程中先调用Looper.prepare()静态方法以初始化Looper对象,以此保证在调用Looper.myLooper()方法时获取到的对象非空。
以及在初始化Handler对象以后,必须在当前子线程中及时调用Looper.loop()静态方法以准备Message消息队列供当前子线程使用。

通讯发送线程

在须要发送通讯内容的线程中,须要首先接收到上文建立的Handler实例化对象。

在切换线程处理的位置,调用Handler对象的post(Runnable r)系列方法,参数 r 就是要在Handler对象所在线程中处理的Runnable任务对象。

或者在须要发送消息的位置,调用Handler对象的obtainMessage()系列方法,能够获取到空闲可使用的Message消息对象,将要发送的消息体内容赋值给Message对象的不一样属性。最后再调用Handler对象的sendMessage(Message msg)系列方法,将消息体Message对象发送便可。

相关文章
相关标签/搜索