如何在调用popBackStack()后将所选项从ListFragment传递给之前的Fragment?

时间:2015-01-27 10:34:28

标签: android android-fragments android-listfragment

我准备了一个非常简单的测试用例,其中包含1个活动和2个片段,用于我的问题:

screenshot

最初,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执行所有重要工作"它显示2个片段中的1个,并将用户数据保存在共享首选项中。

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

我正在寻找一种正确的方法,没有任何黑客攻击(例如片段不应该触及共享偏好)。

更新:我已经尝试过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时,它不起作用。

5 个答案:

答案 0 :(得分:1)

当发生这种情况时,你的第一个片段是否仍保留在内存中?我这么认为。这意味着您可以使用SharedPreferences.OnSharedPreferenceChangeListener。只需让MyMainFragment实现该接口,然后使用registerOnSharedPreferenceChangeListener监视更改。不过,不要忘记取消注册!

更好的想法可能是将您的活动注册为侦听器,并在再次显示时将其传递给MyMainFragment。

答案 1 :(得分:1)

为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()可能还需要一些额外的检查,并为TextView设置适当的值。

答案 2 :(得分:1)

首先,您可以在UI线程内使用SharedPrefences,即内部片段。这种常见的误解从只有commit()方法的时间开始生根。现在,我们apply()使用缓存数据进行异步工作和get*()

其次,在没有使用SDK的情况下解决问题的最简单方法是在第二个片段中通知Activity选择项目(例如,在片段中:((MainActivity)getActivity()).setSelectedItem(itemId);)并获取此值第一个片段的onResume()(例如,((MainActivity)getActivity()).getSelectedItem();)。当然,如果没有选择任何内容,你应该检查这个值为null。

答案 3 :(得分:1)

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

有几种方法可以做到这一点(听后面的堆栈等),但我最常用的是:

声明一个后退键监听器接口:

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将在按下后退键时调用它。 这使您可以选择将值传递回活动。

答案 4 :(得分:1)

解决方案是使用setTargetFragment / getTargetFragment方法。用这种方法 您可以在没有Activity和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();

} 
相关问题