用Coroutine替代AsyncTask

使用Coroutine可以避免异步任务中的回调,首先想到的就是可以把AsyncTask给替换掉。废话少说,先看东西:

AsyncTask


用AsyncTask实现的一段逻辑:点击Button后,TextView依次显示

Start -->  1 ... 10 --> end
class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        button.setOnClickListener {
            MyAsyncTask().execute()
        }
    }

    inner class MyAsyncTask : AsyncTask<Void, Int, Void>() {

        override fun onPreExecute() {
            text.setText("Start")
            Thread.sleep(800)
        }

        override fun doInBackground(vararg param: Void?): Void? {
            for (i in 1..10) {
                publishProgress(i)
                Thread.sleep(800)
            }
            return null
        }

        override fun onProgressUpdate(vararg values: Int?) {
            text.setText(values[0].toString())
        }

        override fun onPostExecute(result: Void?) {
            text.setText("Finish")
        }
    	
    	override fun onCancelled() {
            Log.e(localClassName, "Cancelled")
    	}

    }
}

一个简单的异步任务要实现四个回调,实在不优雅。


Coroutine


同样的需求用Coroutine实现如下:

class MainActivity : AppCompatActivity() {

    val scope = CoroutineScope(Dispatchers.Default)

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }

    override fun onResume() {
        super.onResume()
        button.setOnClickListener {
            scope.launch {
                myTask()
            }
        }
    }

    override fun onPause() {
        super.onPause()
        scope.coroutineContext.cancel()
    }


    private suspend fun myTask() {
        try {
            // 相当于onPreExecute,withContext可以在切换线程的同时进行线程同步
            withContext(Dispatchers.Main) {
               text.text = "Start"
            }

            // 相当于doInBackground
            Thread.sleep(800)
            for (i in 1..10) {
                //相当于onProgressUpdate
                withContext(Dispatchers.Main) {
                    text.text = i.toString()
                }
                Thread.sleep(800)
            }

            // 相当于onPostExecute
            withContext(Dispatchers.Main) {
                text.text = "Finish"
            }
        } catch (e: Exception) {
            // 相当于onCancelled
            Log.e(localClassName, "Cancelled", e)
        }
    }
}

一气呵成,困扰我多年的便秘终于被治好了。


CoroutineScope


Coroutine版本的代码中Activity中多了针对CoroutineScope的处理。CoroutineScope是Coroutine运行的基础,它提供了创建并启动Coroutine的常用方法,例如我们常用的launchasync等,虽然是扩展方法。
每个CoroutineScope管理一个CoroutineContext,通过launch或者async启动协程会返回一个句柄Job存放在CoroutineContext进行管理。

在这里插入图片描述

CoroutineDispatcher

val scope = CoroutineScope(Dispatchers.Default)

CoroutineScope创建时可以通过CoroutineDispatcher指定其被派发到哪个线程执行,CoroutineDispatcher其实也是CoroutineContext的子类。

CoroutineDispatchersDescription
Dispatchers.MainMainThread中执行
Dispatchers.Default使用CommonPool执行,共享一个后台线程池
Dispatchers.IO启动新线程执行
Dispatchers.Unconfined无指定派发线程, 有可能在任意线程派发,要根据运行时的CoroutineContext决定,因为有不确定性不推荐使用

Cancel

在生命周期结束时,执行了以下代码

scope.coroutineContext.cancel()

调用CoroutineContext的cancel()后,内部所有的Job都会被结束,从而有效避免内存泄漏。这与AsyncTask的cancel类似,但是现在有了一个几种cancel的地方,不需要一个一个单独调用cancel了。
Coroutine被cancel后内部会抛出JobCancellationException,可以通过try…catch捕捉并实现异常处理。

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

fundroid

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值