【问题标题】:Executing lifecycle method of backstack fragment problem in android在android中执行backstack片段问题的生命周期方法
【发布时间】:2019-01-24 11:36:20
【问题描述】:

我有一个包含两个片段的活动,并希望在使用后退按钮从第二个片段返回时执行第一个片段。我在将第一个片段导航到第二个片段时使用add()。这是我的场景和代码sn-p:

第一个片段:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {

        // Inflate the layout for this fragment
        View view = inflater.inflate(R.layout.one_fragment, container, false);    

        final Button button = (Button) view.findViewById(R.id.buttonChange);
        button.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                buttonClicked(v);
            }
        });

        return view;
    }

    public void buttonClicked(View view) {
        FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
        fragmentTransaction.add(R.id.fragment_Container, new TwoFragment());
        fragmentTransaction.addToBackStack("sdfsf");
        fragmentTransaction.commit();

}

移动到第二个片段,这里是代码:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {

        View view = inflater.inflate(R.layout.two_fragment, container, false);
        return view;
}

问题是,当我从第一个片段导航到第二个片段,然后使用后退按钮再次返回第一个片段时,第一个片段生命周期方法没有执行。如果我使用replace() 而不是使用add(),那么生命周期方法正在正确执行。我知道 add()replace() 之间的区别,但我想使用 add() 并且还希望在使用返回按钮返回第一个片段时有导航回调来处理一些逻辑。

也试过下面的代码:

fragmentManager.addOnBackStackChangedListener(
        new FragmentManager.OnBackStackChangedListener() {
                public void onBackStackChanged() {
                        Log.e(TAG, "onBackStackChanged: ");
                        // Update your UI here.
                }
});

但它也多次调用并产生异常。

我该如何处理?当我从第二个片段返回时,专门处理第一个片段中的一些逻辑。

【问题讨论】:

  • addOnBackStackChangedListener 应该可以正常工作,可能您设置了多个侦听器而不是一个?
  • 对我来说,当我从第一个片段导航到第二个片段时,它的调用以及当我回到第一个片段时,它再次调用。大教堂,每次后台更改时都会调用它。
  • 没错,只要使用getBackStackEntryAt取顶部条目名称,调用getName()即可。根据名字就可以知道当前是什么fragment。

标签: android android-fragments android-lifecycle


【解决方案1】:

我能想到的最简单的方法是在您完成第二个片段后设置结果,这实际上是通过其 onActivityResult 方法告诉第一个片段“恢复”。

当您创建 Fragment B 的实例时,调用 #setTargetFragment() 并传入 Fragment A 作为您的目标 Fragment。然后当 Fragment B 完成并返回 Fragment A 时,在它退出之前,您将通过调用为 Fragment A 设置它的结果:

getTargetFragment().onActivityResult(getTargetRequestCode(), RESULT_FRAGMENT_B_FINISHED,null)
///// horizontal scroll padding

请注意,RESULT_FRAGMENT_B_FINISHED 将是您在某处定义的一些静态整数,例如

public static final int RESULT_FRAGMENT_B_FINISHED = 123123;

现在在 Fragment A 中,您需要做的就是覆盖 onActivityResult 并检查请求代码是否与 setTargetFragment 中的请求代码整数匹配,并且结果代码也与 RESULT_FRAGMENT_B_FINISHED 匹配,如果是这样,您可以运行本应从 onResume 触发的代码()。

#getTargetFragment()

#onActivityResult()

#getTargetRequestCode()

【讨论】:

  • 当我使用fragmentTransaction.add(R.id.fragment_Container, new TwoFragment()); 将片段 A 导航到片段 B 时,即使我从后台堆栈返回片段 A,我的片段 A 生命周期方法也没有改变。那么,我该如何执行这些方法。
  • 您无法使用 fragmentTransaction#add() 获取生命周期事件。这是因为从技术上讲,您可以在单个活动上显示多个片段。 Android 不知道它是全屏还是部分屏幕。调用 add 时,您是在告诉 android 我正在显示这两个片段。如果你使用 fragmentTransaction#replace() 你会得到那些生命周期事件,因为你告诉 android 我正在删除片段 a 并添加片段 b。
  • 我知道使用 replace() 可以修复它,但我不会每次在 A 和 B 之间切换时创建和销毁片段 A。
  • 不久前我遇到了类似的问题。我决定让 Fragment a 在后台继续聆听并更新它的视图。性能没有任何损失,用户可以返回代表最新数据的 UI。
  • 如果 Fragment A 在 Fragment B 上造成中断,例如它显示一个对话框或在事件期间切换到 Fragment C,您可以让它检查它之前是否在 backstack 中的顶部 Fragment让它继续。
【解决方案2】:

我建议您使用 SharedViewModel,而不是在两个片段之间传递数据。

这个想法是第一个片段观察一些数据的变化,第二个片段编辑这些数据。

例子:

共享视图模型

public class SharedViewModel extends ViewModel {

  private final MutableLiveData<Item> selected = new 
  MutableLiveData<Item>();

  public void select(Item item) {
      selected.setValue(item);
  }

  public LiveData<Item> getSelected() {
      return selected;
  }
}

第一个片段

public class FirstFragment extends Fragment {

  public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      SharedViewModel model = 
      ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
      model.getSelected().observe(this, { item ->
         // Update the UI.
      });
  }
}

第二个片段

public class SecondFragment extends Fragment {

  public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      SharedViewModel model = 
      ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
      model.select(new Item("value 1","value 2");
  }
}

您可以从这里开始阅读有关 ViewModel、LiveData 和架构组件的信息:https://developer.android.com/topic/libraries/architecture/viewmodel#java

此答案假设您要根据某些数据更改执行某些逻辑。如果不是这样,您可以解释您要执行什么样的逻辑,我将编辑我的答案。

【讨论】:

  • 感谢您的回答,但实际上我想在片段从后台堆栈中看到时跟踪我的片段。它与逻辑无关,主要是视图跟踪需求。
猜你喜欢
  • 2020-07-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多