有些文章声称Rx可以替代AsyncTask和AsyncTaskLoader。 看到Rx通常会缩短代码,我试着深入研究各种样本及其工作原理。
我发现的所有样本和文章,包括Github repos,似乎都没有真正取代AsyncTask和AsyncTaskLoader:
无法找到如何取消任务或多个任务(包括中断线程)。这对AsyncTask尤为重要,AsyncTask通常用于RecyclerView和ListView。这也可以在AsyncTaskLoader上完成,但需要更多的工作而不仅仅是调用"取消"。对于AsyncTask,它还提供了一个进度的发布,这是我在Rx中找不到的另一个例子。
无法在避免内存泄漏的情况下找到如何避免手动取消订阅,这完全破坏了使用Rx的整个过程,因为它应该更短。在某些示例中,还有比普通代码更多的回调。
以下是我读过有关Rx的一些链接:
https://stablekernel.com/replace-asynctask-and-asynctaskloader-with-rx-observable-rxjava-android-patterns/ - 这实际上提供了一种很酷的方式来处理AsyncTaskLoader,因为它会缓存结果。但是,样本完全不起作用(包括构建它们),因为它们已经很老了。
https://code.tutsplus.com/tutorials/getting-started-with-rxjava-20-for-android--cms-28345,https://code.tutsplus.com/tutorials/reactive-programming-operators-in-rxjava-20--cms-28396,https://code.tutsplus.com/tutorials/rxjava-for-android-apps-introducing-rxbinding-and-rxlifecycle--cms-28565 - 所有人都主要讨论RxJava,而不是替换AsyncTask或AsyncTaskLoader。
https://github.com/L4Digital/RxLoader - 需要取消订阅,即使它没有说它需要它。
如何使用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
}
}
}
对于AsyncTask,通常我们根据ViewHolder设置它,作为一个字段,我们在onBindViewHolder上取消它,并且当活动/片段被销毁时(遍历所有仍在等待或正在运行的那些)。
这样的事情(样本尽可能短,当然应该根据需要改变):
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)
}
}
}
答案 0 :(得分:0)
我先告诉你,我在RxJava的经历并不像有些人所说的那样。我只知道使用RxJava + RxAndroid替换AsyncTask
。例如,让我们使用AsyncTask
将您的Observable
代码转换为等效的RxJava2,这可以说是最受欢迎的流类型。
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
})
现在让我们逐行完成代码:
create
可让您自定义发射器行为。请注意,这不是创建流的唯一方法,还有just
,fromArray
,fromList
,defer
等。我们可以讨论更多如果你还有兴趣的话。subscribeOn(Schedulers.io())
告诉RxJava,#1将在I / O线程中执行。如果这是后台操作,Schedulers.newThread()
也有效(至少据我所知)。observeOn(AndroidSchedulers.mainThread())
告诉RxJava,#4将在Android主线程中执行。这也是RxAndroid填补空白的地方,因为RxJava没有任何Android的参考。subscribe()
onNext(i : Int)
- 相当于publishProgress()
。在较新的RxJava中,发出的值不能为空。onError(e : Throwable)
- 错误处理由RxJava的程序员长期赞美。在较新的RxJava中,必须提供onError()
,如果它是空的,则无关紧要。onComplete()
- 相当于onPostExecute()
。同样,我的回答可能会有很多错误信息。我希望有更好理解的人能够纠正它或提供更好的答案。
答案 1 :(得分:0)
似乎无法以更短或更简单的形式使用AsyncTask
实现RxJava
功能。使用RxJava
可以简化任务链,因此如果只有一个任务AsyncTask
可以是更好的解决方案,但是当您有几个连续的任务要做时 - RxJava
的界面是更方便。因此,对于每个任务而不是例如程序onCancelled
,您应该实现一些共同的逻辑。