IT虾米网

安卓线程异步处理的小结

qq123 2022年05月05日 手机开发 309 0

安卓线程异步处理的小结

概念了解

Android会存在两种线程:一种是UI主线(UI Thread)程一种是工作线程(Work Thread)
在子线程中处理耗时的任务,任务完成后通过Handler通知UI主线程更新UI界面
主线程不允许进行耗时的操作(比如说网络请求和访问),否则容易出现ANR现象
ANR
anr:application not reponse:应用程序无响应
主线程:UI线程
anr产生的原因:主线程需要做很多重要的事情,响应点击事件,更新ui,如果在主线程里面阻塞时间过久,应用程序就会无响应,为了避免应用程序出现anr,所有的耗时的操作,都应该放在子线程中执行。

Android 异步消息处理机制解析

Android异步消息处理主要分为四个部分,MessageHandlerMessageQueueLooper

Message

Message 是在线程之间传递的消息,它可以在内部携带少量的信息,用于在不同线程之间交换数据。通常使用 Message 的 what 字段携带命令,除此之外还可以使用 arg1 和arg2 字段来携带一些整形数据,使用 obj 字段携带一个 Object 对象
使用示例

var message=Message() 
message.what=0x123 
message.obj=1 
handlerMess.sendMessage(message) 
 //在主线程中创建一个Handler 
    var handlerMess: Handler = object : Handler() {
   
     
        //处理消息 
        override fun handleMessage(msg: Message) {
   
     
            super.handleMessage(msg) 
            when (msg.what) {
   
     
                0x123 -> {
   
     
                    Log.i("Message","Message="+msg.obj) 
                } 
            } 
        } 
    } 

返回结果:
Message=1

Handler

Handler 顾名思义也就是处理者的意思,它主要是用于发送和处理消息的。发送消息一般是使用 Handler 的 sendMessage()方法,而发出的消息经过一系列地辗转处理后,最终会传递到 Handler 的 handlerMessage()方法中。

MessageQueue

MessageQueue 是消息队列的意思,它主要用于存放所有通过 Handler 发送的消息。这部分消息会一直存在于消息队列中,等待被处理。每个线程中只会有一个 MessageQueue 对象。

Looper

Looper 是每个线程中的 MessageQueue 的管家,调用 Looper 的 loop() 方法后,就会进入到一个无限循环当中,然后每当发现 MessageQueue 中存在一条消息,就会将它取出,并传递到 Handler 的 handleMessage() 方法中。每个线程中也只会有一个 Looper 对象。

Android提供了四种常用的操作多线程的方式

1. Thread

使用示例

  Thread{
   
     
      tv_statue.post(Runnable {
   
     
         tv_statue.text = "下载中" 
         ToastUtils.show(baseContext, "下载中") 
      }) 
      Thread.sleep(2000) 
      tv_statue.post(Runnable {
   
     
         tv_statue.text = "下载完成" 
         ToastUtils.show(baseContext, "下载完成") 
      }) 
  }.start() 

2. Thread+Handler

优点
1. Handler用法简单明了,可以将多个异步任务更新UI的代码放在一起,清晰明了。
2. 处理单个异步任务代码略显多。
适用范围
3. 多个异步任务的更新UI。
使用示例

Thread {
   
     
    handler.sendEmptyMessage(0) 
    Thread.sleep(3000) 
    handler.sendEmptyMessage(1) 
  }.start() 
---------------------------------------- 
    var handler = object : Handler() {
   
     
        override fun handleMessage(msg: Message) {
   
     
            super.handleMessage(msg) 
            when (msg.what) {
   
     
                0 -> {
   
     
                    ToastUtils.show(baseContext, "开始下载") 
                } 
                1 -> {
   
     
                    ToastUtils.show(baseContext, "下载完成") 
                } 
 
            } 
 
        } 
 
    } 

3. AsyncTask

异步任务 执行完一个,再执行下一个。 在线程池中执行后台任务

优点

方便实现异步通信,节省资源 
1. 处理单个异步任务简单,可以获取到异步任务的进度 
2. 可以通过cancel方法取消还没执行完的AsyncTask 
3. 处理多个异步任务代码显得较多 

适用范围

1. 单个异步任务的处理 

使用示例

 var time = 3 
 val asyncTask: AsyncTask<Int, Int, String?> = 
 object : AsyncTask<Int, Int, String?>() {
   
     
     override fun doInBackground(vararg params: Int?): String? {
   
     
         for (i in params[0]!! downTo 1) {
   
     
            try {
   
     
              Thread.sleep(1000) 
              publishProgress(i) //调用onProgressUpdate方法 
             } catch (e: InterruptedException) {
   
     
                e.printStackTrace() 
              } 
            } 
             return "计时结束" 
          } 
 
     override fun onPostExecute(result: String?) {
   
    //结束--返回doInBackground里面返回的信息 
         super.onPostExecute(result) 
           tv_statue.text = result 
           Log.i("AsyncTask==","onPostExecute"+result) 
        } 
 
     override fun onProgressUpdate(vararg values: Int?) {
   
    //过程更新 
         super.onProgressUpdate(*values) 
           tv_statue.text = values[0].toString() 
           Log.i("AsyncTask==","onProgressUpdate"+values[0].toString()) 
           } 
       } 
     asyncTask.execute(time) 

返回:
AsyncTask==: onProgressUpdate3
AsyncTask==: onProgressUpdate2
AsyncTask==: onProgressUpdate1
AsyncTask==: onPostExecute计时结束

4.ThreadPoolExecutor

线程池:可以管理多个线程并行执行
虽然线程的创建销毁的开销相对较小,但是频繁得创建和销毁也会消耗有限的资源,从而带来性能上的浪费,也不够高效。因此线程池的出现就是为了解决这一问题,即在初始状态创建并维护一定数量的空闲线程,当有需要执行的任务,就交付给线程中的一个线程,任务执行结束后,该线程也不会死亡,而是回到线程池中重新变为空闲状态。

优点

减少线程频繁创建销毁的资源开销,同时能够有效控制系统中并发线程的数量,防止系统性能的剧烈下降。 

适用范围

1. 批处理任务 
newSingleThreadExecutor

单个线程的线程池,即线程池中每次只有一个线程工作,单线程串行执行任务 这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行。
使用示例

  inner class MyThread : Thread() {
   
     
        override fun run() {
   
     
            super.run() 
            var name=currentThread().name 
            println(name + "正在执行...."); 
        } 
 
    } 
 
                //创建一个可重用固定线程数的线程池 
                val pool: ExecutorService = Executors.newSingleThreadExecutor() 
                //创建实现了Runnable接口对象,Thread对象当然也实现了Runnable接口; 
                val t1: Thread = MyThread() 
                val t2: Thread = MyThread() 
                val t3: Thread = MyThread() 
                val t4: Thread = MyThread() 
                val t5: Thread = MyThread() 
                //将线程放到池中执行; 
                pool.execute(t1) 
                pool.execute(t2) 
                pool.execute(t3) 
                pool.execute(t4) 
                pool.execute(t5) 
                //关闭线程池 
                pool.shutdown() 

返回结果:
pool-1-thread-1正在执行…
pool-1-thread-1正在执行…
pool-1-thread-1正在执行…
pool-1-thread-1正在执行…
pool-1-thread-1正在执行…

newFixedThreadPool

创建固定大小的线程池。每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。 线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。
使用示例

                //创建一个可重用固定线程数的线程池 
                var pool: ExecutorService? = 
                    Executors.newFixedThreadPool(3) 
                //创建实现了Runnable接口对象,Thread对象当然也实现了Runnable接口; 
                val t1: Thread = MyThread() 
                val t2: Thread = MyThread() 
                val t3: Thread = MyThread() 
                val t4: Thread = MyThread() 
                val t5: Thread = MyThread() 
                //将线程放到池中执行; 
                pool.execute(t1) 
                pool.execute(t2) 
                pool.execute(t3) 
                pool.execute(t4) 
                pool.execute(t5) 
                //关闭线程池 
                pool.shutdown() 

返回结果:
pool-2-thread-2正在执行…
pool-2-thread-3正在执行…
pool-2-thread-1正在执行…
pool-2-thread-2正在执行…
pool-2-thread-3正在执行…

newCachedThreadPool

创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程,那么就会回收部分空闲(60秒不执行任务)的线程,当任务数增加时,此线程池又可以智能的添加新线程来处理任务。此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小。
使用示例

                //创建一个可重用固定线程数的线程池 
                val pool = 
                    Executors.newCachedThreadPool() 
                //创建实现了Runnable接口对象,Thread对象当然也实现了Runnable接口; 
                val t1: Thread = MyThread() 
                val t2: Thread = MyThread() 
                val t3: Thread = MyThread() 
                val t4: Thread = MyThread() 
                val t5: Thread = MyThread() 
                //将线程放到池中执行; 
                pool.execute(t1) 
                pool.execute(t2) 
                pool.execute(t3) 
                pool.execute(t4) 
                pool.execute(t5) 
                //关闭线程池 
                pool.shutdown() 

范湖结果:
pool-3-thread-4正在执行…
pool-3-thread-3正在执行…
pool-3-thread-2正在执行…
pool-3-thread-5正在执行…
pool-3-thread-1正在执行…

newScheduledThreadPool

大小无限制的线程池,支持定时和周期性的执行线程
使用示例

  var exec: ScheduledThreadPoolExecutor = ScheduledThreadPoolExecutor(1) 
                exec.scheduleAtFixedRate( 
                    Runnable //每隔一段时间就触发异常 
                    {
   
     
                        // TODO Auto-generated method stub 
                        println("111111111111") 
                    }, 1000, 5000, TimeUnit.MILLISECONDS 
                ) 
 
                exec.scheduleAtFixedRate( 
                    Runnable //每隔一段时间打印系统时间,证明两者是互不影响的 
                    {
   
     
                        // TODO Auto-generated method stub 
                        println(System.nanoTime()) 
                    }, 1000, 2000, TimeUnit.MILLISECONDS 
                ) 

返回结果:
111111111111
23119318857491
23121319071841
23129318176148
23123319007891
111111111111
23125318176937
23127318190359
111111111111
23131318344312
23133318465896
111111111111
23135319645812

5.IntentService

IntentService继承自Service,是一个经过包装的轻量级的Service,用来接收并处理通过Intent传递的异步请求。客户端通过调用startService(Intent)启动一个IntentService,利用一个work线程依次处理顺序过来的请求,处理完成后自动结束Service。
IntentService封装了HandlerThread和Handler,但是它继承了Service,所以导致它的优先级比单纯线程要高,所以IntentService适合执行一些高优先级的后台任务。

特点

一个可以处理异步任务的简单Service 
当任务执行完后,IntentService 会自动停止,不需要我们去手动结束。 

使用示例

public class MyIntentService extends IntentService {
   
     
    private int count = 10; 
    private LocalBroadcastManager mLocalBroadcastManager; 
 
    public MyIntentService(String name) {
   
     
        super(name); 
    } 
    public MyIntentService() {
   
     
        super("someName");// 关键是这句话 
    } 
    @Override 
    public void onCreate() {
   
     
        super.onCreate(); 
        mLocalBroadcastManager = LocalBroadcastManager.getInstance(this); 
    } 
 
    @Override 
    protected void onHandleIntent(@Nullable Intent intent) {
   
     
        try {
   
     
            Thread.sleep(1000); 
            while (count!=0){
   
     
                count--; 
                sendThreadStatus("倒计时中...", count); 
                Thread.sleep(1000); 
            } 
 
        } catch (InterruptedException e) {
   
     
            e.printStackTrace(); 
        } 
 
 
    } 
    /** 
     * 发送进度消息 
     */ 
    private void sendThreadStatus(String status, int progress) {
   
     
        Intent intent = new Intent("action.type.thread"); 
        intent.putExtra("status", status); 
        intent.putExtra("progress", progress); 
        mLocalBroadcastManager.sendBroadcast(intent); 
    } 
 
} 
//注册广播--IntentService 
        mLocalBroadcastManager = LocalBroadcastManager.getInstance(this) 
        mBroadcastReceiver = MyBroadcastReceiver() 
        val intentFilter = IntentFilter() 
        intentFilter.addAction("action.type.thread") 
        mLocalBroadcastManager.registerReceiver(mBroadcastReceiver, intentFilter) 
 
 
 
 /** 
     * 非静态内部类,关键字inner 
     *可以访问外部类的成员变量 
     */ 
    inner class MyBroadcastReceiver : BroadcastReceiver() {
   
     
        override fun onReceive(context: Context?, intent: Intent) {
   
     
            when (intent.action) {
   
     
                "action.type.thread" -> {
   
     
                    //更改UI 
                    val progress = intent.getIntExtra("progress", 0) 
                    tv_statue.text = progress.toString() 
                    if (progress == 0) {
   
     
                        tv_statue.text = "下载结束" 
                    } 
                } 
            } 
        } 
    } 
 
//开启 
 val intent = Intent(this, MyIntentService::class.java) 
 startService(intent) 

返回结果:
下载
9
8
7
6
5
4
3
2
1
下载结束

参考文献

Java-线程池 ThreadPool 专题详解 (美团面试题)

Android多线程的四种方式


评论关闭
IT虾米网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!

# 安卓五大存储方式之SQlite