gpt4 book ai didi

java - fragment 创建和检索并发

转载 作者:行者123 更新时间:2023-11-30 00:15:11 25 4
gpt4 key购买 nike

我目前在弄清楚如何防止涉及 fragment 的并发问题时遇到了问题。

为了在 Activity 重新创建(配置更改等)之间存储多条数据,我使用了一个保留的 fragment (没有 View )。

public class ListRetainFragment extends Fragment {
private static final String TAG = "ListRetainFragment";

public ListRetainFragment() {}

public static ListRetainFragment findOrCreateRetainFragment(FragmentManager fm) {
ListRetainFragment fragment = (ListRetainFragment) fm.findFragmentByTag(TAG);
if (fragment == null) {
fragment = new ListRetainFragment();
fm.beginTransaction().add(fragment, TAG).commit();
Log.e("FRAGMENT_INIT", "New retain fragment created with reference: "+fragment.toString());
}
else{
Log.e("FRAGMENT_INIT", "Existing fragment found with reference: "+fragment.toString());
}
return fragment;
}

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}

//Storage code omitted.....
}

然后在想要在其中存储一些数据的 fragment 的 onCreate 中检索该 fragment 。

@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
listRetainFragment = ListRetainFragment.findOrCreateRetainFragment(getFragmentManager());
}

对于这个例子,我们将这些 fragment 称为 Fragment1Fragment2,它们都由同一个 fragment 管理器管理,因此可以访问同一个 ListRetainFragment 通过 findOrCreateRetainFragment 方法。在大多数情况下,这工作正常。 fragment 被保留,数据也随之正确地保留下来。

按预期工作时查看 logcat:

D/FRAGMENT_INIT: New retain fragment created with reference: ListRetainFragment{671e2da ListRetainFragment} //Fragment 1 is the first one trying to retrieve a retain fragment. A new instance is created and added to the fragment manager.
D/FRAGMENT_INIT: Existing fragment found with reference: ListRetainFragment{671e2da ListRetainFragment} //Fragment 2 is the second one trying to retrieve a retain fragment. The originally created fragment is found and returned
//ACTIVITY + FRAGMENT1 + FRAGMENT2 ARE RECREATED (Ex. when changing device orientation)
D/FRAGMENT_INIT: Existing fragment found with reference: ListRetainFragment{671e2da ListRetainFragment} //After recreation Fragment1 finds the orignal fragment and uses it to retrieve/store persistent data
D/FRAGMENT_INIT: Existing fragment found with reference: ListRetainFragment{671e2da ListRetainFragment} //After recreation Fragment2 finds the orignal fragment and uses it to retrieve/store persistent data

但是,在某些设备配置中,Fragment1 和 Fragment2 是 2-fragment ViewPager 的一部分,因此会相继创建。

这种情况会导致以下问题:

D/FRAGMENT_INIT: New retain fragment created with reference: ListRetainFragment{214bdd7 ListRetainFragment}
D/FRAGMENT_INIT: New retain fragment created with reference: ListRetainFragment{887e4db ListRetainFragment}
//ACTIVITY + FRAGMENT1 + FRAGMENT2 ARE RECREATED (Ex. when changing device orientation)
D/FRAGMENT_INIT: Existing fragment found with reference: ListRetainFragment{887e4db ListRetainFragment}
D/FRAGMENT_INIT: Existing fragment found with reference: ListRetainFragment{887e4db ListRetainFragment}

由于 Fragment1 和 Fragment2 是由 ViewPager 相继创建的,由 Fragment1 (214bdd7) 创建的保留 fragment 在 Fragment2 尝试检索时尚未正确添加到 FragmentManager它。因此,创建了一个新 fragment (887e4db),它覆盖了 Fragment1 创建的 fragment 。

Activity 重建后,最初由 Fragment1 (214bdd7) 检索和引用的 fragment 与其数据一起丢失,因为重新创建的 Fragment1 现在正在检索由 Fragment2 (887e4db) 创建的保留 fragment 。

有没有办法确保在我尝试检索前一个 fragment 提交之前完成?我已经尝试过 commitNow()executePendingTransactions() 方法,但它们会导致 java.lang.IllegalStateException: FragmentManager is already executing transactions 异常。

最佳答案

我认为解决问题的唯一方法是重新考虑每个 UI fragment 如何获取对保留 fragment 的引用。与其让每个 UI fragment 尝试从 FragmentManager 中检索保留的 fragment ,我认为你应该让你的 activity 这样做,然后让你的 fragment 从你的 Activity 。

问题的根源在于 FragmentTransaction.commit() 是异步的。因此,FragmentManager 不是“我的保留 fragment 是否已创建?”这个问题的可靠答案来源。相反,您应该让您的 Activity 成为有关保留 fragment 的真实来源。

public class MainActivity extends AppCompatActivity {

private RetainedFragment retainedFragment;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

if (savedInstanceState != null) {
retainedFragment = (RetainedFragment) getSupportFragmentManager().findFragmentByTag(RetainedFragment.TAG);
}
else {
retainedFragment = new RetainedFragment();

getSupportFragmentManager()
.beginTransaction()
.add(retainedFragment, RetainedFragment.TAG)
.commit();
}
}

public RetainedFragment getRetainedFragment() {
return retainedFragment;
}
}

通过利用 savedInstanceState 参数创建和检索您的保留 fragment 保证您只会创建一个保留 fragment 的实例:当 Activity 第一次启动时,它会创建一个新的并且将它添加到 FragmentManager 中,当您的 Activity 在旋转后重新创建时,它知道 FragmentManager 已经有了它的一个实例,所以它只是使用它。

您的 UI fragment 现在可以像这样访问保留的 fragment :

public class UiFragment extends Fragment {

private RetainedFragment retainedFragment;

@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
MainActivity main = (MainActivity) getActivity();
retainedFragment = main.getRetainedFragment();
}
}

关于java - fragment 创建和检索并发,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47402085/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com