产生耗时的计算线程是很常见的。稍后,我们需要使用计算结果更新Activity
或Fragment
。
我一直遵循以下准则。到目前为止,它对我很有用。
setRetainInstance(true)
无UI片段。setTargetFragment
和getTargetFragment
技术setRetainInstance(true)
无UI片段。onAttach
和onDetach
存储对Activity
的引用。谷歌似乎不鼓励使用getActivity
。 http://developer.android.com/guide/components/fragments.html 但是,从View
派生的类的情况怎么样?我计划从自定义AsyncTask
启动View
。但是,我怎样才能onPostExecute
回到View
?
我问的原因是,在我的自定义视图中,某些触摸事件会触发它使用新的位图重绘自身。生成新位图非常耗时。因此,我计划启动AsyncTask,生成这样的位图,然后传回自定义View。但是,配置更改可能会导致重新创建自定义View。因此,我需要确保我的AsyncTask在onPostExecute
期间可以有正确的View引用。
答案 0 :(得分:3)
假设您仅使用AsyncTask
进行与绘图相关的操作(否则您应该重新审视您的逻辑 - 正如评论所示),您可以直接在自定义{{AsyncTask
中创建View
1}} 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
}
}
}
这是如何安全实施的样子。它有一些缺点和重要的部分:
AsyncTask
在任何时候都不应该强烈引用View
(这就是为什么将类声明为static
并将WeakReference
保持为View
的原因})AsyncTask
的结果不感兴趣时 - 取消它AsyncTask
可能有用的结果。如果这是问题所在 - 我建议您完全从AsyncTask
删除View
并搜索其他解决方案(单独Executor
或HandlerThread
)。同样的onPostExecute
AsyncTask
将从启动它的同一个looper线程中调用(在你的情况下是主线程,所以如果从{{{}开始它并不重要1}}或Activity
,或者其他任何地方,一切都取决于管理这些任务的难度。)
答案 1 :(得分:0)
我会向您提供一个大致的想法,即您可以在任何需要的地方继续申请(包括Thread
或ThreadExecutor
(而不是仅仅依赖AsyncTask);
您可以直接使用库来处理events
,其中事件在公共“总线”中调度,任何想要的类都可以注册到总线并收听这些事件:
为此,我会将你引用给Otto,它很好用且功能非常强大:http://square.github.io/otto/
或者您可以使用LocalBroadcastManager
https://developer.android.com/reference/android/support/v4/content/LocalBroadcastManager.html自行实现,如下所示:
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(context)
&lt;那是为了得到它。
onEventComplete:(发生在您的主题或AsyncTask上
Intent i = new Intent("DOWNLOAD_COMPLETE");
// ps. feel free to attach extras to the intent, in order to pass data back to your activity/fragment/view
lbm.sendBroadcast(i);
然后在您的活动/片段/视图中创建一个接收器
BroadcastReceiver receiver = new BroadcastReceiver(){
@Override
public void onReceive (Context context, Intent intent){
// feel free to read the extras from the intent with data here and update your view
}
};
<强> onStartListening:强>
lbm.registerReceiver(receiver, new IntentFilter("DOWNLOAD_COMPLETE"));
<强> onStopListening:强>
lbm.unregisterReceiver(receiver);
然后你必须在onStart
/ onStop
或onResume
/ onPause
或onAttachedToWindow
/ {{期间开始和停止聆听1}}(对于观点)