如何从ListFragment通过所选项目到以前的片段调用popBackStack后()?(How

2019-10-21 17:26发布

我已经准备了一个非常简单的测试用例1个活性2个片段对我的问题:

  • MainActivity.java (存储选择的项目中共享偏好)
  • MyMainFragment.java (显示一个文本视图和“选择”按钮)
  • MyListFragment.java (显示项目列表)

最初MainActivity显示MyMainFragment。

当用户触摸“选择项...”按钮,MainActivity显示MyListFragment有:

public void selectedButtonClicked() {
    SharedPreferences prefs = getSharedPreferences(PREFS, 0);
    int index = prefs.getInt(INDEX, -1);
    Fragment fragment = MyListFragment.newInstance(index);
    getFragmentManager().beginTransaction()
        .addToBackStack(null)
        .replace(R.id.root, fragment, LIST)
        .commit();
}

用户触摸,MainActivity存储所选择的项目的位置在共享偏好列表中的项目中的一个,并调用后popBackStack()再次显示MyMainFragment:

public void itemSelected(int index) {
    SharedPreferences prefs = getSharedPreferences(PREFS, 0);
    Editor editor = prefs.edit();
    editor.putInt(INDEX, index);
    editor.commit();
    getFragmentManager().popBackStack();
    // How to show the index in mSelectedTextView?
}

即在我的应用程序在MainActivity完成所有的“繁重的工作”:它会显示1 2的片段,并保持在共享偏好的用户数据。

我的问题是:如何在显示所选项目(在上面的截图“项目07”) mSelectedTextView的MyMainFragment的?

我正在寻找一种方式来做到这一点正确,没有任何黑客(例如片段应不能触及共享偏好)。

更新:我已经尝试通过corsair992的建议(感谢!)

public void itemSelected(int index) {
    SharedPreferences prefs = getSharedPreferences(PREFS, 0);
    Editor editor = prefs.edit();
    editor.putInt(INDEX, index);
    editor.commit();
    getFragmentManager().popBackStackImmediate();
    MyMainFragment f = (MyMainFragment) getFragmentManager().findFragmentById(R.id.root);
    // call a method in MyMainFragment to update mSelectedTextView
    f.setText("Selected index: " + index);
}

但它仅适用,当用户在触摸MyListFragment的项目。 但是,它没有工作,当用户返回触摸返回按钮MyMainFragment。

Answer 1:

在我看来,你已经有了一个合理的第一部分答案(由corsair992建议 - 从选择的项目传递值),第二部分是你如何处理返回键。

有这样做(听回栈等),但我用最fequently就是其中的几种方法:

声明一个返回键监听器接口:

public interface BackKeyListener {
   boolean onBackPressed();
}

在主要活动添加以下内容:

import BackKeyListener;
void onBackKeyPressed() {
   boolean backKeyHandled = false;
   Fragment activeFragment = getActiveFragment();
   if (activeFragment instanceof BackKeyListener) {
      backKeyHandled = ((BackKeyListener) activeFragment).onBackKeyPressed();
   }
   if (!handled) {
      // If should process back key normally, pass to super..
      super.onBackKeyPressed();
   }
}

Fragment getActiveFragment() {
   // I'm assuming you place all your fragments here, if not..
   // alter to suit
   return getFragmentManager().findFragmentById(R.id.root);
}

在MyListFragment添加以下内容:

import BackKeyListener;

class MyListFragment extends Fragment(orsomething) implements BackKeyListener

public boolean onBackPressed() {
  // User pressed back, select default item..
  ((MainActivity) getActivity()).itemSelected(selectedItem);

  // In this case, prevent normal back processing or
  // you might get a double backstack pop.
  return true;
}

使用的片段的界面让你“不小心”的活性片段是什么。 如果它实现了BackKeyListener,按下返回键时,在MainActivity将调用它。 这给你传递一个值回活动的选项。



Answer 2:

是您的第一个片段仍然保存在内存中,当发生这种情况? 我认为如此。 这意味着你可以使用一个SharedPreferences.OnSharedPreferenceChangeListener 。 只是要MyMainFragment实现接口,然后使用registerOnSharedPreferenceChangeListener监视更改。 不要忘了注销,但!

一个更好的想法可能是注册您的活动作为听众,并使其通过这些数据来MyMainFragment当它再次显示它。



Answer 3:

首先,你可以使用SharedPrefences UI线程内,即内部片段。 这个通常的误解扎根从时间时,只有commit()方法。 现在,我们已经apply()以异步方式运行,并get*()使用缓存的数据。

其次,要解决你的问题,而不SDK杂耍最简单的方法,将是你的第二个片段来通知项目选择的活动(例如,您的片段内: ((MainActivity)getActivity()).setSelectedItem(itemId); )并获得该值在你的第一个片段的onResume()例如, ((MainActivity)getActivity()).getSelectedItem(); )。 当然,你应该检查在被选择的情况下没有什么空此值。



Answer 4:

分配标签MyMainFragment,假定这将是MY_MAIN_FRAGMENT_TAG。 此代码添加到您的itemSelected方法:

Fragment myMainFragment = getFragmentManger.findFragmentByTag("MY_MAIN_FRAGMENT_TAG");
if (null != myMainFragment) {
    Bundle args = new Bundle();
    myMainFragment.getArguments().putInt("selectedItem", index);
    getFragmentManager().popBackStack();
}

然后在你的MyMainFragment覆盖onViewStateRestored()方法:

@Override
public void onViewStateRestored(@Nullable Bundle savedInstanceState) {
    super.onViewStateRestored(savedInstanceState);
    mSelectedTextView.setText(String.valueOf(getArguments.getInt("selectedItem")));
}

也许你会需要一些额外的检查,如果null != getArguments()并设置apropriate价值为TextView



Answer 5:

一种解决方案是使用setTargetFragment / getTargetFragment方法。 通过这种方法,您可以使用只是你没有碎片的活动和SharedPreferences帮助。 在你MyMainFragment,当用户点击按钮“选择项...”你可以用你的回调selectedButtonClicked()为:

public void selectedButtonClicked() {

Fragment fragment = MyListFragment.newInstance(index);

//Set the TargetFragment

fragment.setTargetFragment(MyMainFragment.this, MyListFragment.REQUESTCODE)

    getFragmentManager().beginTransaction()
    .addToBackStack(null)
    .replace(R.id.root, fragment, LIST)
    .commit();
 }

你必须定义MainFragment回调onActivityResult:

public void onActivityResult(int requestCode, int resultCode, Intent data){

    if(requestCode == MyListFragment.REQUESTCODE){
         f.setText("Selected index: " + intent.getInt("INDEX");
    }
}

在MyListFragment一旦用户选择一个项目,你可以调用你的回调itemSelected()

public void itemSelected(int index) {

Intent i = new Intent();    
i.putExtraInt("INDEX",index);
getTargetFragment.onActivityResult(MyListFragment.REQUESTCODE,Context.Result_OK,i);
    getFragmentManager().popBackStackImmediate();

} 


文章来源: How to pass selected item from ListFragment to previous Fragment after calling popBackStack()?