Android 如何用Rx等价物替换AsyncTask和AsyncTaskLoader? 背景

Android 如何用Rx等价物替换AsyncTask和AsyncTaskLoader? 背景,android,android-asynctask,rx-android,asynctaskloader,Android,Android Asynctask,Rx Android,Asynctaskloader,一些文章声称Rx可以取代AsyncTask和AsyncTaskLoader。 看到Rx通常会使代码变短,我试着深入研究各种示例和它的工作原理 问题 我发现的所有示例和文章,包括Github repos,似乎都不能很好地取代AsyncTask和AsyncTaskLoader: 找不到如何取消一个或多个任务(包括中断线程)。这对于AsyncTask尤其重要,AsyncTask通常用于RecyclerView和ListView。这也可以在AsyncTaskLoader上完成,但需要比调用“cancel

一些文章声称Rx可以取代AsyncTask和AsyncTaskLoader。 看到Rx通常会使代码变短,我试着深入研究各种示例和它的工作原理

问题 我发现的所有示例和文章,包括Github repos,似乎都不能很好地取代AsyncTask和AsyncTaskLoader:

  • 找不到如何取消一个或多个任务(包括中断线程)。这对于AsyncTask尤其重要,AsyncTask通常用于RecyclerView和ListView。这也可以在AsyncTaskLoader上完成,但需要比调用“cancel”更多的工作。对于AsyncTask,它还提供进度发布,这是我在Rx中找不到的另一个示例

  • 无法找到如何在避免内存泄漏的同时避免手动取消订阅,这完全破坏了使用Rx的整个意义,因为它应该更短。在一些示例中,回调的次数甚至比普通代码还要多

  • 我试过的 以下是我读到的关于Rx的一些链接:

    • -这实际上为处理AsyncTaskLoader提供了一种很酷的方法,因为它可以缓存结果。但是,这些示例根本不起作用(包括构建它们),因为它们非常旧

    • ,-所有这些都主要讨论RxJava,而不是AsyncTask或AsyncTaskLoader的替换

    • -需要取消订阅,即使它没有说需要

    问题 如何使用Rx替代AsyncTask和AsyncTaskLoader

    例如,我将如何用Rx等效代码替换这个微小的AsyncTaskLoader示例代码:

    class MainActivity : AppCompatActivity() {
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
            supportLoaderManager.initLoader(1, Bundle.EMPTY, object : LoaderCallbacks<Int> {
                override fun onCreateLoader(id: Int, args: Bundle): Loader<Int> {
                    Log.d("AppLog", "onCreateLoader")
                    return MyLoader(this@MainActivity)
                }
    
                override fun onLoadFinished(loader: Loader<Int>, data: Int?) {
                    Log.d("AppLog", "done:" + data!!)
                }
    
                override fun onLoaderReset(loader: Loader<Int>) {}
            })
        }
    
        private class MyLoader(context: Context) : AsyncTaskLoader<Int>(context) {
    
            override fun onStartLoading() {
                super.onStartLoading()
                forceLoad()
            }
    
            override fun loadInBackground(): Int {
                Log.d("AppLog", "loadInBackground")
                try {
                    Thread.sleep(10000)
                } catch (e: InterruptedException) {
                    e.printStackTrace()
                }
                return 123
            }
        }
    }
    
    class MainActivity:AppCompatActivity(){
    重写创建时的乐趣(savedInstanceState:Bundle?){
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    initLoader(1,Bundle.EMPTY,对象:LoaderCallbacks{
    重写onCreateLoader(id:Int,args:Bundle):Loader{
    Log.d(“AppLog”、“onCreateLoader”)
    回程装载机(this@MainActivity)
    }
    覆盖乐趣onLoadFinished(加载程序:加载程序,数据:Int?){
    Log.d(“AppLog”,“done:+data!!)
    }
    重写有趣的onLoaderReset(加载程序:加载程序){}
    })
    }
    私有类MyLoader(上下文:上下文):AsyncTaskLoader(上下文){
    覆盖启动加载()的乐趣{
    super.onStartLoading()
    力载荷()
    }
    覆盖乐趣加载背景():Int{
    日志d(“应用日志”、“加载背景”)
    试一试{
    线程。睡眠(10000)
    }捕获(e:中断异常){
    e、 printStackTrace()
    }
    返回123
    }
    }
    }
    
    对于AsyncTask,通常我们将它设置为每个ViewHolder的一个字段,并在onBindViewHolder上以及当activity/fragment被销毁时取消它(检查所有仍然挂起或运行的)

    类似这样的内容(样本尽可能短,当然应该根据需要进行更改):

    class AsyncTaskActivity:AppCompatActivity(){
    内部val mTasks=HashSet()
    重写创建时的乐趣(savedInstanceState:Bundle?){
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity\u async\u任务)
    val recyclerView=findviewbyd(R.id.recyclerView)
    recyclerView.layoutManager=LinearLayoutManager(此,LinearLayoutManager.VERTICAL,false)
    recyclerView.adapter=对象:adapter(){
    重写CreateViewHolder(父级:ViewGroup,viewType:Int):MyViewHolder{
    返回MyViewHolder(LayoutFlater.from(this@AsyncTaskActivity).充气(android.R.layout.simple_list_item_1,父项,false))
    }
    @SuppressLint(“StaticFieldLeak”)
    覆盖onBindViewHolder(holder:MyViewHolder,位置:Int){
    holder.tv.text=“正在加载…”
    if(holder.task!=null){
    holder.task!!.cancel(真)
    mTasks.remove(holder.task!!)
    }
    holder.task=对象:AsyncTask(){
    覆盖有趣的背景(vararg voids:Void):Void{
    对于(0..100中的i)
    试一试{
    线程。睡眠(5)
    出版进度(一)
    }捕获(e:中断异常){
    e、 printStackTrace()
    }
    返回空
    }
    重写进程更新(vararg值:Int?){
    super.onProgressUpdate(*值)
    holder.tv.text=“进度:”+值[0]
    }
    重写onPostExecute(避免:无效?){
    super.onPostExecute(避免)
    mTasks.remove(holder.task)
    holder.tv.text=“完成:”+位置
    holder.task=null
    }
    }.execute()
    }
    重写getItemCount():Int{
    返回1000
    }
    }
    }
    重写onDestroy(){
    super.ondestory()
    用于(mTasks中的任务)
    任务。取消(true)
    }
    私有类MyViewHolder(itemView:View):ViewHolder(itemView){
    内部var电视:文本视图
    内部变量任务:AsyncTask?=null
    初始化{
    tv=itemView.findViewById(android.R.id.text1)
    }
    }
    }
    
    让我提前告诉你,我在RxJava方面的经验并不像有些人所说的那样先进。我只知道用RxJava+RxAndroid替换
    AsyncTask
    。例如,让我们转换您的
    AsyncTask
    class AsyncTaskActivity : AppCompatActivity() {
        internal val mTasks = HashSet<AsyncTask<Void, Int, Void>>()
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_async_task)
            val recyclerView = findViewById<RecyclerView>(R.id.recyclerView)
            recyclerView.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
            recyclerView.adapter = object : Adapter<MyViewHolder>() {
                override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
                    return MyViewHolder(LayoutInflater.from(this@AsyncTaskActivity).inflate(android.R.layout.simple_list_item_1, parent, false))
                }
    
                @SuppressLint("StaticFieldLeak")
                override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
                    holder.tv.text = "loading..."
                    if (holder.task != null) {
                        holder.task!!.cancel(true)
                        mTasks.remove(holder.task!!)
                    }
                    holder.task = object : AsyncTask<Void, Int, Void>() {
                        override fun doInBackground(vararg voids: Void): Void? {
                            for (i in 0..100)
                                try {
                                    Thread.sleep(5)
                                    publishProgress(i)
                                } catch (e: InterruptedException) {
                                    e.printStackTrace()
                                }
    
                            return null
                        }
    
                        override fun onProgressUpdate(vararg values: Int?) {
                            super.onProgressUpdate(*values)
                            holder.tv.text = "progress:" + values[0]
                        }
    
                        override fun onPostExecute(aVoid: Void?) {
                            super.onPostExecute(aVoid)
                            mTasks.remove(holder.task)
                            holder.tv.text = "done:" + position
                            holder.task = null
                        }
                    }.execute()
                }
    
                override fun getItemCount(): Int {
                    return 1000
                }
            }
        }
    
        override fun onDestroy() {
            super.onDestroy()
            for (task in mTasks)
                task.cancel(true)
        }
    
        private class MyViewHolder(itemView: View) : ViewHolder(itemView) {
            internal var tv: TextView
            internal var task: AsyncTask<Void, Int, Void>? = null
    
            init {
                tv = itemView.findViewById(android.R.id.text1)
            }
        }
    }
    
    Observable
        .create <Int> { emitter ->
            try { 
                for (i in 0..100) {
                    Thread.sleep(5) 
                    emitter.onNext(i) 
                }
            } catch (e: InterruptedException) {
                emitter.onError(e)
            }
            emitter.onComplete()
        ‎}
        ‎.subscribeOn(Schedulers.io())
        ‎.observeOn(AndroidSchedulers.mainThread())
        ‎.subscribe({ i ->
        ‎    holder.tv.text = "progress:" + i
         }, { e ->
         ‎   e.printStackTrace()
         ‎}, {
         ‎   holder.tv.text = "done:" + position
         ‎})