我一直在使用这种模式。这是一个非常人为的AsyncTask +进度指示器示例:
new AsyncTask<Void, Void, Void>() {
WeakReference<MyFragment> weakFragment = new WeakReference<MyFragment>(MyFragment.this);
@Override
protected void onPreExecute() {
Fragment fragment = weakFragment.get();
if(fragment != null) fragment.getView().findViewById(R.id.progress).setVisibility(View.VISIBLE);
}
@Override
protected Document doInBackground(Void... params) {
Fragment fragment = weakFragment.get();
if(fragment == null) return null;
// Do something ...
}
@Override
protected void onPostExecute() {
Fragment fragment = weakFragment.get();
if(fragment != null) fragment.getView().findViewById(R.id.progress).setVisibility(View.GONE);
}
}.execute();
对于方向更改它可以正常工作,但是当我从后台堆栈中弹出片段时,我注意到片段是非null而fragment.getView()为null。这显然会导致崩溃。你们用什么方法?我似乎无法在线找到完美的解决方案。重要提示,这是一个片段,我在onActivityCreated(...)上对该片段调用setRetainInstance(true);
。
答案 0 :(得分:4)
AsyncTask
是一个异步任务,这意味着您通常不知道它何时完成以及何时调用onPostExecute()
。我想你的问题就在这里。当您旋转设备时,您的asynctask尚未完成,您的片段视图将被销毁并再次快速重新创建,而asynctask仍在工作线程上,当它完成其工作时,您的片段有一个视图并且getView
&# 39; s返回值不是null
。但是如果轮换时间很长,您将获得null
,因为AsyncTask
已完成,但您的片段没有任何视图。现在这个场景恰好发生在你的backstack上当你将你的片段推到backstack时,它的视图被销毁(look at the picture)但是片段本身不是(片段从backstack返回到布局)。现在,您的AsyncTask
完成并调用了fragment
getView
方法,并且没有任何view
,因此您将获得NPE
。
我的解决方案:
首先,您应该使用WeakReference<ProgressBar>
而不是WeakReference<MyFragment>
并在onPostExecute()
中检查它是否为空,如果它为null则不执行任何操作,因为如果不是,则默认值不可见null call setVisibility(View.GONE)
。
更新
这个片段还活着,但视图已经被释放了。这是 可能的?
是的,只需从链接中查看图2。片段处于活动状态时(绿色框)the fragment added to back stack
片段转到onPause
,onStop
onDestroyView 。然后当片段从后面的堆栈弹出时,它会直接到onCreateView
带有此文本的箭头链接:the fragment returns to the layout from backstack
。
为了确认我的回答,您可以在AsyncTask
内创建SystemClock.sleep(30000)
并致电doInbackground
。现在你可以将你的片段推入到backstack并从backstack弹出它,没有异常,因为asynctask还没有完成,当它调用onPostExecute()
时你的片段已经有了一个视图。
您可以看到的另一件好事是setRetainInstance
这只能用于不在后栈中的片段。
因此,当您将片段推入后堆时,可能完全销毁,可能在弹出时获得新的片段引用。但是当您使用setRetainInstance(true);
进行配置更改时,您的片段会在“活动重新创建”中保留,这意味着它是相同的片段而onCreate
不是调用。这是一件非常非常重要的事情,因为如果您使用AsyncTask
方法启动onCreate
,当您将片段推入后台并弹出后,可能一个新的片段,这意味着onCreate
方法运行,另一个AsyncTask
被触发。这意味着您无法控制呼叫AsyncTask
的数量,因此请注意
内存泄漏!