从自定义视图启动AsyncTask的最佳实践 [英] Best practice to launch AsyncTask from custom view
问题描述
这是很常见的催生一个耗时的计算线程。后来,我们需要更新活动
或片段
与计算结果。
在这期间,我跟随下面的指导方针。它很适合我到现在。
的AsyncTask需要onPostExecute UI片段
- 使用
setRetainInstance(真)
UI少片段。 - 使用
setTargetFragment
和getTargetFragment
技术 - 请参见 http://stackoverflow.com/a/12303649/72437
的AsyncTask需要onPostExecute界面活性
- 使用
setRetainInstance(真)
UI少片段。 - 使用
onAttach
和onDetach
来保存引用活动
。谷歌似乎不鼓励使用getActivity
。 http://developer.android.com/guide/components/fragments.html - 请参见 http://stackoverflow.com/a/16305029/72437
然而,怎么样的情况下从查看
派生的类?我计划从自定义查看
推出的AsyncTask
。但是,我怎么能 onPostExecute
回查看
我问所以,在我的自定义视图的原因,某些触摸事件将触发其与新的位图重绘自身。产生新的位图是耗时的。因此,我计划推出的AsyncTask,产生这样的位图,并传回自定义视图。但是,配置更改可能导致自定义视图重新创建。因此,我需要确保我的AsyncTask能有正确的看法时参考 onPostExecute
。
假设你使用的AsyncTask
只为绘图相关的操作(否则你真的应该重新审视你的逻辑 - 作为意见建议),您可以创建的AsyncTask
在自定义直接查看
类:
类MyView的扩展视图{ 私人MyAsyncTask currentTask = NULL; // 查看详情 @覆盖
公共无效onAttachedToWindow(){
currentTask =新MyAsyncTask(本);
currentTask.execute();
} @覆盖
公共无效onDetachedFromWindow(){
super.onDetachedFromWindow();
如果(currentTask!= NULL){
currentTask.cancel(真);
currentTask = NULL;
}
} 静态类MyAsyncTask扩展的AsyncTask<无效,无效的,位图> { 私人的WeakReference<&MyView的GT; viewRef; MyAsyncTask(MyView的视图){
viewRef =新的WeakReference<>(视图);
} //后台任务落实 @覆盖
公共无效onPostExecute(位图位图){
MyView的观点= viewRef.get();
如果(查看== NULL){
返回;
} //你现在可以安全地更新你的观点 - 我们是在UI线程
} }}
这是如何实现安全会是什么样子。它也有一些缺点和重要的部分:
- 在任何时候你的
的AsyncTask
应该持有强引用查看
(这就是为什么类被声明为静态
并持有的WeakReference
到查看
) - 当您从
的AsyncTask
不感兴趣,结果了 - 取消 - 这实现将扔掉可能有用的结果,从取消
的AsyncTask
。如果是这样的问题 - 我建议删除的AsyncTask
从查看
完全和寻找其他的解决方案(单独执行人
或HandlerThread
)。
还有 onPostExecute
的AsyncTask
将被从启动它的同一弯针线所谓的(在你的情况这是主线程,因此它不会,如果你从活动
或查看
,或任何其他地方启动它没关系,这一切都取决于这将是多么难以管理的任务)。
It is quite common to spawn a time consuming computation thread. Later, we require to update Activity
or Fragment
with computation result.
All the while, I'm following the below guidelines. It works well for me till now.
AsyncTask needs to onPostExecute UI Fragment
- Use
setRetainInstance(true)
UI-less fragment. - Use
setTargetFragment
andgetTargetFragment
technique - Please refer to http://stackoverflow.com/a/12303649/72437
AsyncTask needs to onPostExecute UI Activity
- Use
setRetainInstance(true)
UI-less fragment. - Use
onAttach
andonDetach
to store reference toActivity
. Google seems doesn't encourage usinggetActivity
. http://developer.android.com/guide/components/fragments.html - Please refer to http://stackoverflow.com/a/16305029/72437
However, how about case for a class derived from View
? I plan to launch AsyncTask
from the custom View
. However, how can I onPostExecute
back to the View
?
The reason I'm asking so is, in my custom view, certain touch event will trigger it to redraw itself with a new bitmap. Generating the new bitmap is time consuming. Hence, I plan to launch a AsyncTask, to generate such bitmap, and pass back to custom View. However, configuration change might cause custom View to be recreated. Hence, I need to ensure my AsyncTask can have correct View reference during onPostExecute
.
Assuming that you're using AsyncTask
only for drawing-related operations (otherwise you should really revisit your logic - as comments suggest), you can create AsyncTask
directly in your custom View
class:
class MyView extends View {
private MyAsyncTask currentTask = null;
// View details
@Override
public void onAttachedToWindow() {
currentTask = new MyAsyncTask(this);
currentTask.execute();
}
@Override
public void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (currentTask != null) {
currentTask.cancel(true);
currentTask = null;
}
}
static class MyAsyncTask extends AsyncTask<Void, Void, Bitmap> {
private WeakReference<MyView> viewRef;
MyAsyncTask(MyView view) {
viewRef = new WeakReference<>(view);
}
// background task implementation
@Override
public void onPostExecute(Bitmap bitmap) {
MyView view = viewRef.get();
if (view == null) {
return;
}
// you now can safely update your view - we're on UI thread
}
}
}
That's how safe implementation would look like. It has some disadvantages and important parts:
- At no point your
AsyncTask
should hold strong reference toView
(that's why class is declared asstatic
and holdsWeakReference
toView
) - When you're not interested in result from
AsyncTask
anymore - cancel it - This implementation will just throw away possibly useful result from cancelled
AsyncTask
. If that's the issue - I would suggest to removeAsyncTask
fromView
completely and search for others solutions (separateExecutor
orHandlerThread
).
Also onPostExecute
of AsyncTask
will be called from the same looper thread which launched it (in your case that's main thread, so it does not matter if you start it from Activity
or View
, or wherever else, it all depends on how hard it would be to manage those tasks).
这篇关于从自定义视图启动AsyncTask的最佳实践的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!