Dan*_*son 8 android android-configchanges android-fragments fragmentmanager
我的问题涉及托管三个支持片段的活动.一个是正常的程序片段(让我们称之为家庭片段).一个是在设备定向时添加在主片段顶部的肖像片段,一个是"无头"的,以便无论配置如何变化都能继续执行异步任务.很简单,我正在研究这个很好的例子.
public class HeadlessCustomerDetailFetchFragment extends Fragment{
private RequestCustomerDetails mRequest;
private AsyncFetchCustomerDetails mAsyncFetchCustomerDetails;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
mRequest = (RequestCustomerDetails)getActivity();
}
public void startFetching(String scannedBarcode) {
if(mAsyncFetchCustomerDetails != null && mAsyncFetchCustomerDetails.getStatus() == AsyncTask.Status.RUNNING) return;
if(mAsyncFetchCustomerDetails == null || mAsyncFetchCustomerDetails.getStatus() == AsyncTask.Status.FINISHED)
mAsyncFetchCustomerDetails = new AsyncFetchCustomerDetails(getActivity(), mRequest, mPartner, scannedBarcode);
}
public void stopFetching() {
if(mAsyncFetchCustomerDetails != null && mAsyncFetchCustomerDetails.getStatus() != AsyncTask.Status.RUNNING) return;
mAsyncFetchCustomerDetails.cancel(true);
}
Run Code Online (Sandbox Code Playgroud)
}
在我的活动的onCreate()中,我根据需要创建并添加无头片段.
mHeadlessCustomerDetailFetchFragment = (HeadlessCustomerDetailFetchFragment)getSupportFragmentManager()
.findFragmentByTag(HeadlessCustomerDetailFetchFragment.class.getSimpleName());
if(mHeadlessCustomerDetailFetchFragment == null) {
mHeadlessCustomerDetailFetchFragment = HeadlessCustomerDetailFetchFragment.instantiate(this, HeadlessCustomerDetailFetchFragment.class.getName());
getSupportFragmentManager().beginTransaction()
.add(mHeadlessCustomerDetailFetchFragment, mHeadlessCustomerDetailFetchFragment.getClass().getSimpleName())
.commit();
getSupportFragmentManager().executePendingTransactions();
id = null;
}
Run Code Online (Sandbox Code Playgroud)
然后,在方向更改为纵向时添加的肖像片段的onCreateView()中启动6秒延迟(用于测试)之后,我启动异步任务(通过我的startFetching()函数).在活动的onCreate()中检测到方向更改:
if (savedInstanceState == null) {
// Do some initial stuff for the home fragment
}
else {
getSupportFragmentManager().popBackStackImmediate(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
//Launch portrait fragment
FragmentLauncher.launchPortraitFragment(this);
}
Run Code Online (Sandbox Code Playgroud)
任务完成后,我返回活动并尝试更新活动肖像片段的UI,但片段管理器找不到它,findFragmentByTag()返回null.
要明确:
也许保留一个片段会积极地杀死其他未保留的片段或其他类似的片段?
小智 4
问题的根源在于如何维护对无头片段内活动的引用。
\n从提供的代码中不清楚如何在 AsyncTask 完成后更新 UI,让我们假设您mRequest从第一个代码片段中使用。当您需要新的 AsyncTask 时,您可以将其交给mRequest构造函数,并在 AsyncTask 完成后使用此引用。
\n如果在创建 Activity 和更新 UI 之间没有屏幕旋转,那就没关系。这是因为您使用了对仍处于活动状态的活动的引用。
\n旋转屏幕是不行的。每次轮换后您都会有新的活动。但是,当您在第一次调用 Activity\xe2\x80\x99s 中创建无头片段时, mRequest 仅分配一次onCreate()。因此它包含对旋转后不活动的第一个活动实例的引用。在您的情况下,轮换后有 2 个活动实例:第一个 - 由 mRequest 引用,第二个 - 可见且处于活动状态。您可以通过记录以下活动的引用来确认这一点onCreate:Log.i(TAG, "onCreate: this=" + this);和内部 Activity\xe2\x80\x99s 方法,该方法在异步任务后更新 UI:Log.i(TAG, "updating UI: this=" + this);
\n此外,第一个活动处于“销毁”状态。所有片段都将从该活动中分离出来,并且未保留的片段将被销毁。这就是为什么findFragmentByTag返回 null 的原因。
\n如果无头片段未设置为保留自身,则 Activity\xe2\x80\x99sonCreate()会在每次调用中重新创建它。因此mRequest,始终引用最后创建的活动以及所有片段。在这种情况下findFragmentByTag返回不为空。
\n为了避免这个问题,我建议:
private WeakReference<RequestCustomerDetails> mRequest;HeadlessCustomerDetailFetchFragment更新此引用。public void updateResultProcessor(RequestCustomerDetails requestCustomerDetails) {\n mRequest = new WeakReference(requestCustomerDetails);\n// Update ui if there is stored result of AsyncTask (see p.4b)\n}mRequest.get()没有完成null则更新 UI。mRequest.get()则将null结果存储在无头片段内并在 p.2 中使用它。| 归档时间: |
|
| 查看次数: |
507 次 |
| 最近记录: |