安卓线程异步处理的小结

安卓线程异步处理的小结

概念了解

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多线程的四种方式

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值