在嵌套片段之间传递数据 [英] Passing data between nested Fragments

查看:70
本文介绍了在嵌套片段之间传递数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在一个项目中,我必须在片段之间传递数据.所有数据都是从我的DatabaseHandler class(SQLiteOpenHelper)提供的.我正在手工撰写这篇文章,因此,请忽略语法错误(如果有的话).

I am working on a project where I have to pass data between fragments. All the data is provided from my DatabaseHandler class (SQLiteOpenHelper). I'm writing this post by hand, so ignore syntax errors, if any.

这是我的Activity的样子(包含SelectionFragment和InfoFragment):

Here's what my Activity looks like(contains SelectionFragment and InfoFragment):

  • 选择片段(包含GridView)
  • 信息片段(带有大约5-6 child fragmentsViewPager)
    • childFragment1
    • childFragment2
    • childFragment3
    • ...
    • Selection Fragment (contains a GridView)
    • Info Fragment (ViewPager with about 5-6 child fragments)
      • childFragment1
      • childFragment2
      • childFragment3
      • ...

      这是我到目前为止所做的:

      SelectFrag扩展片段:

      Here's what I've done so far:

      SelectFrag extends Fragment :

      MyCommunicator communicator;
      GridView myGrid;
      
      onItemSelected(... int position, ...) {
          communicator.respond("The id i get from getTag()..");
      }
      public void setCommunicator(MyCommunicator communicator) {
          this.communicator = communicator;
      }
      
      public interface MyCommunicator {
          public void respond(String id);
      }
      



      活动扩展FragmentActivity实现SelectFrag.MyCommunicator:

      FragmentManager manager;
      SelectFrag selectFrag;
      InfoFrag infoFrag;
      
      onCreate() {
          manager = getSupportFragmentManager();
          selectFrag = (SelectFrag) manager.findFragmentById(...);
          selectFrag.setCommunicator(this);
      }
      
      @Override
      public void respond(String id) {
          DatabaseHandler db = new DatabaseHandler(this);
          try {
              CustomObject obj = db.getObj(id);
          } finally {
              db.close();
          }
          infoFrag = (InfoFrag) manager.findFragmentById(...);
          if(obj != null)
              infoFrag.changeObj(id)
          setTitle(obj.getName();
      }
      


      InfoFrag扩展了Fragment:

      ViewPager pager;
      Context context;
      MyObj obj;
      
      public void changeObj(String id) {
          DatabaseHandler db = new DatabaseHandler(context);
          this.obj = db.getObj(id);
          db.close();
      }
      
      protect class MyPagerAdapter extends FragmentPagerAdapter{
          public Fragment getItem(int i) {
              Fragment frag = null;
              switch(i) {
                  case 0:
                      frag = new ChildFrag1();
                  break;
                  case 1:
                      frag = new ChildFrag2();
                  break;
                  ... Goes to case 6 for now.
              }
              return frag;
          }
      }
      

      以下是我的布局:

      select_frag.xml

      select_frag.xml

      <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
          xmlns:tools="http://schemas.android.com/tools"
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          tools:context=".SelectFrag" >
      
          <GridView
              android:id="@+id/selectGridView"
              android:layout_width="fill_parent"
              android:layout_height="fill_parent"
              android:columnWidth="56dp"
              android:background="#dd5500"
              android:horizontalSpacing="5dp"
              android:numColumns="auto_fit"
              android:paddingLeft="10dp"
              android:paddingRight="2dp"
              android:paddingTop="3dp"
              android:stretchMode="columnWidth"
              android:verticalSpacing="5dp" >
          </GridView>
      
      </RelativeLayout>
      

      main_activity.xml:

      <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
          xmlns:tools="http://schemas.android.com/tools"
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          tools:context=".MyActivity"
          android:orientation="vertical" >
      
          <fragment
              android:id="@+id/selectFragment"
              android:name="my.package.SelectFragment"
              android:layout_width="wrap_content"
              android:layout_height="0dp"
              android:layout_weight="3" />
      
          <fragment
              android:id="@+id/infoFragment"
              android:name="my.package.InfoFragment"
              android:layout_width="wrap_content"
              android:layout_height="0dp"
              android:layout_weight="7" />
      
      </LinearLayout>
      

      info_fragment.xml:

      <android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
          xmlns:tools="http://schemas.android.com/tools"
          android:id="@+id/myPager"
          android:layout_width="match_parent"
          android:layout_height="match_parent" >
      
          <android.support.v4.view.PagerTitleStrip
              android:id="@+id/my_pager_title_strip"
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:layout_gravity="top"
              android:background="#33b5e5"
              android:paddingBottom="4dp"
              android:paddingTop="4dp"
              android:textColor="#fff" />
      
      </android.support.v4.view.ViewPager>
      

      该应用当前将信息从selectFrag传递到Activity,然后将其传输到infoFrag.我希望此ID一直到达子片段.我正在考虑也许将MyCommunicator实施到InfoFrag并将数据传递给子Fragment,但这不会为不可见的childFragment抛出NullPointerException.

      The app currently passes info from selectFrag to Activity, which transfers it to infoFrag. I would like for this ID to reach All the way to the child Fragments. I was thinking of maybe implementing the MyCommunicator to InfoFrag and passing the data to children Fragments, but wouldn't that throw a NullPointerException for the childFragments that are not visible.

      * 注意:* selectFrag和InfoFrag在活动"中始终可见.在selectFrag的GridView中选择新项目时,InfoFrag必须刷新.

      *Note: * The selectFrag and InfoFrag are always visible in the Activity. InfoFrag has to refresh when a new item is selected in selectFrag's GridView.

      感谢您的帮助!


      我尝试使用通信界面",但每次都会迷路:(大声笑.有人可以给我简单的方法吗?我所有的childFragments都能从selectFrag实现通讯器吗?如果是,那是正确的方法吗?我认为InfoFragment应该实现接口并将数据传递给它的'children',但是我不知道该怎么做并刷新我正在想做的另一件事是将lastItemClicked存储在sharedPreferences中,然后从我的数据库访问Object.我真的很困惑:/再次感谢!


      I've tried using the "communication interface", but I get lost every time :( lol.. Can someone plz give me a brief way to do this? Can all my childrenFragments implement the communicator from selectFrag? If yes, is that the right way to do it? I think InfoFragment should implement the interface and pass the data to its' children. But I don't know how to do that and refresh the children. Another thing I was thinking of doing was storing lastItemClicked in sharedPreferences and then accessing the Object from my db. I'm really confused :/ Thanks once again!

      推荐答案

      我认为您面临的是另一个问题.

      I think you are facing a different problem.

      您需要创建以下组件:

      1. 要在片段中实现的接口.
      2. 实现该接口的侦听器列表.
      3. 添加/删除该列表中的项目.
      4. 最终将发生的事情通知给听众.

      我将概述一个超级简化版.

      I'll outline a super simplified version.

      接口: 这很简单:

      public interface DataChangeListener {
          void onDataChanged();
      }
      

      侦听器列表:这也很容易……在您的Controllers/Activities/Singletons或您需要执行操作并通知侦听器的任何地方……

      List Of Listeners: This is easy too… in your Controllers/Activities/Singletons or anywhere you need to perform actions and notify listeners…

      protected List<DataChangeListener> mListeners = new ArrayList<DataChangeListener>();
          public void addDataChangeListener(DataChangeListener listener) {
              if (listener != null && !mListeners.contains(listener)) {
                  mListeners.add(listener);
              }
          }
          public void removeDataChangeListener(DataChangeListener listener) {
              if (listener != null) {
                  mListeners.remove(listener);
              }
          }
      

      然后是您的片段…(例如)

      public class YourFragment extends Fragment implements DataChangeListener {
      
      private SomeControllerForExample mController;
      
          @Override
          public void onPause() {
              super.onPause();
              mController.removeDataChangeListener(this);
          }
          @Override
          public void onResume() {
              super.onResume();
              mController.addDataChangeListener(this);
              }
      
      }
      

      到目前为止,您可以在恢复后注册,而在不再可见时将其删除.

      So far, you register when you are resumed and remove when you're no longer visible.

      您还需要实现该方法...

      You also need to implement the method…

      @Override
      public void onDataSetChanged() {
              // DO WHATEVER YOU NEED TO DO
      }
      

      最后,在您的控制器中有一个notify方法(具有列表的那个)

      And finally, have a notify method in your controller (the same one which had the list)

      private void notifyListeners(){
          for (DataChangeListener listener : mListeners) {
              if (listener != null) {
                   listener.onDataSetChanged();
              }
          }
      }
      

      此模式适用于任何事物,这是一种非常好用的简单方法,可以让UI通知您已检索到新数据,必须通知适配器等.

      This pattern applies to anything, it's a nice and simple way to have your UI notified that you have retrieved new data, that an adapter must be notified, etc.

      使用这样的方式重新考虑您的问题,事情会容易得多.

      Rethink your problem using something like this and things will be a lot easier.

      这篇关于在嵌套片段之间传递数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆