在嵌套片段之间传递数据

时间:2013-12-25 18:37:06

标签: android android-fragments

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

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

  • 选择片段(包含GridView
  • 信息片段(ViewPager5-6 child fragments
    • childFragment1
    • childFragment2
    • childFragment3
    • ...

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

SelectFrag扩展片段:

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扩展片段:

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

<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能够一直到达子片段。我在考虑将InfoCom的MyCommunicator实现并将数据传递给子Fragments,但是不会为不可见的childFragments抛出NullPointerException。

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

感谢您的帮助!

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

2 个答案:

答案 0 :(得分:6)

我认为你面临着另一个问题。

您需要创建以下组件:

  1. 要在片段中实现的界面。
  2. 实现该接口的侦听器列表。
  3. 添加/删除该列表中的项目。
  4. 最终通知听众发生的事情。
  5. 我将概述一个超简化版本。

    <强>接口: 这很简单:

    public interface DataChangeListener {
        void onDataChanged();
    }
    

    听众列表:这也很容易......在您的控制器/活动/单身人士或您需要执行操作并通知听众的任何地方......

    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);
            }
    
    }
    

    到目前为止,您在恢复时进行注册,并在不再可见时删除。

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

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

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

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

    这种模式适用于任何事情,这是一种很简单的方法,可以通知您UI已经检索到新数据,必须通知适配器等等。

    使用类似的东西重新思考你的问题,事情会容易得多。

答案 1 :(得分:1)

现在找到解决方案。而不是与子片段通信。每次在GridView中选择一个项目时,我都会重新验证ViewPager(在infoFrag中调用changeObj)。 我想我应该早点使用不同的关键字来找到解决方案! :/ Replacing a fragment from ViewPager android