Android:防止片段在替换另一个片段时变成"active"

Android: Prevent fragment from becoming "active" while replacing another

我有以下调用:

context.getSupportFragmentManager().popBackStack(tag.name(), 1);
context.getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, fragment, tag.name()).addToBackStack(tag.name()).commit();

...而我之前打开的后台堆栈上至少有 2 个其他片段。当执行这两个命令并且最新的片段已从后台堆栈中弹出时,在很短的时间内,在弹出的片段被给定片段替换之前,该片段之前的片段将处于活动状态。这就是问题所在,因为此片段从服务器获取数据并显示进度对话框。有时这会导致竞争条件和奇怪的行为。

如何防止 "non-active" 片段在替换另一个片段时变为活动状态?

这里是对这种情况的简短解释: MainActivity -> 打开 Fragment1 -> 打开 Fragment2a -> 打开 EditActivity -> 在 "save action" 之后,Fragment2a 将被弹出,并在 MainActivity 的 fragment_container 中添加一个新的 Fragment2b。虽然发生这种情况,但 Fragment1 正在做一些事情,但它不能这样做。我想阻止 Fragment1 执行任何任务。它应该以某种方式留在后台并且 "sleep".

检查

if(getActivity() == null || !isAdded){
    return; //don't do your code that touches UI if it is not active.
}

但是如果您不打算等待完成,请确保您的 onPause 删除了您的忙碌指示器,否则您将造成 window 内存泄漏。

使用观察者模式怎么样?您创建一个接口,该接口具有将片段设置为繁忙启动或执行某些逻辑的方法。

所有片段都实现了这个接口,你创建了一个包含这些接口的列表 Activity。例如,如果片段已注册,请添加此片段以列出或使用注销方法将其删除。

可以调用

(MyActivity)getActivity.register(this);注册片段。或者,如果您希望将除此片段之外的其他片段设置为繁忙 (MyActivity)getActivity.setActive(this),并且在 MyActivity 中,您可以将此方法声明为

,则可以调用活动片段中的方法
public void setActive(IStateController fragment) {
    for(IStateController f: listOfSubscribers) {
        if(f == fragment) {
            // This fragment called the method and should active
            // other fragments can be set to busy or waiting state   
        }
    }
}

我真的不能说它是否适合你,但可以通过这种方式在彼此不知情的情况下与片段进行交互,或者你可以查看 EventBus library

我不确定我是不是误用了片段管理器的概念导致了这种情况的发生,或者片段管理器的概念是否完全是废话(就像 Android 中的很多),但我解决了这个问题使用一些解决方法。当我开始或替换一个新片段时,我会立即在应用程序上下文中存储一个 ID。当片段开始时,它会检查它是否具有正确的 ID。如果不是,我 return 一个空视图并且不会创建片段。支票如下所示:

@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState)
{
    return FragmentCreationHelper.createFragmentView(inflater, container, TAG, getFragmentId(), R.layout.fragment_mycoolview);
}

帮手class...

public class FragmentCreationHelper
{
    public static View createFragmentView(LayoutInflater inflater, ViewGroup container, String loggingTag, FragmentTag fragmentId, int template)
    {
        Log.d(loggingTag, "onCreateView()");
        if (MyContext.getNextVisibleFragment() == null || fragmentId.equals(MyContext.getNextVisibleFragment()))
        {
            Log.d(loggingTag, "inflating view...");
            return inflater.inflate(template, container, false);
        }
        else
        {
            Log.d(loggingTag, "Skipping view inflation. Fragment should not be displayed.");
            return null;
        }
    }
}