Android ViewPager中多个片段之间的通信对象

Android ViewPager中多个片段之间的通信对象,android,android-fragments,android-viewpager,singleton,Android,Android Fragments,Android Viewpager,Singleton,我在ViewPager中有5个片段,用于一步一步地用几个字段填充业务对象,在每个步骤中都会设置一些字段。我读过很多关于片段间通信的文章,但我对其他人喜欢的方式感到不舒服,所以在考虑了我应该如何在我的案例中做到这一点之后,最后我开始考虑使用singleton模型对象,所有片段都可以轻松访问其字段,并在特定步骤中填充它们 由于我是android新手,我想听听专家们关于使用singleton而不是在片段之间传递数据的意见,比如实现的接口(它看起来很复杂,很难维护)。任何建议都会有帮助。我想在您的主要活

我在
ViewPager
中有5个片段,用于一步一步地用几个字段填充业务对象,在每个步骤中都会设置一些字段。我读过很多关于片段间通信的文章,但我对其他人喜欢的方式感到不舒服,所以在考虑了我应该如何在我的案例中做到这一点之后,最后我开始考虑使用singleton模型对象,所有片段都可以轻松访问其字段,并在特定步骤中填充它们


由于我是android新手,我想听听专家们关于使用singleton而不是在片段之间传递数据的意见,比如实现的接口(它看起来很复杂,很难维护)。任何建议都会有帮助。

我想在您的主要活动中有一个
ViewPager
,而
FragmentOne
将是ViewPager中的一个片段。这里,MainActivity正在与FragmentOne通信以刷新其适配器。希望是明确的

在MainActivity中添加此界面:

public interface Updateable {
    public void update();
}
在需要更新的片段中实现此接口,并在
update
方法中编写代码以通知适配器:

public class FragmentOne extends Fragment implements MainActivity.Updateable {
    ...
    @Override
    public void update() {
        // YOUR CODE TO UPDATE HERE, FOR EXAMPLE, HERE I'M UPDATING THE ADAPTER
        if ( adapter != null ) {
            adapter.notifyDataSetChanged();
        } else {
            Log.d("LOG_TAG", "null");
        }
    }
    ...
}
当片段第一次加载时,从main活动调用
update
方法。您可以覆盖
PagerAdapter
中的
getItemPosition
方法来执行此操作,如下所示:

@Override
public int getItemPosition(Object object) {    
    if ( object != null && object instanceof FragmentOne ) {
        FragmentOne f = (FragmentOne) object;

        f.update();
    }
    return super.getItemPosition(object);
}
最后,必须调用viewPager适配器的notifyDataSetChanged()。这将强制viewpager的适配器调用getItemPosition方法

mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
        int previousState;
        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

        }

        @Override
        public void onPageSelected(int position) {

        }

        @Override
        public void onPageScrollStateChanged(int state) {

            if (previousState == ViewPager.SCROLL_STATE_SETTLING && state == ViewPager.SCROLL_STATE_IDLE) {

                if ( viewPagerAdapter.getItem(viewpager.getCurrentItem()) instanceof Pictures ) {
                    Log.d("LOG_TAG", "New Position=" + viewpager.getCurrentItem());

                    viewPagerAdapter.notifyDataSetChanged();
                }

            }
            previousState = state;
        }
    });

我不推荐全球单身人士。主要原因有两个:

  • 根据定义,单例将应用程序限制为主业务对象的单个实例。如果你(或设计师,或你老板的老板的老板)决定一次拥有多个这样的viewpager,你将不得不改变你的架构
  • “安卓思维方式”是希望你的用户可以将你的应用程序放在后台,并在返回到你的应用程序之前使用其他应用程序。如果系统决定在后台杀死你的应用程序,那么你的单例内存对象将被销毁,你的用户将失去所有的进程。Android保存状态的正确方法是将状态保存在活动或片段中,适当地保存在
    onSaveInstanceState()
    中,然后在
    onCreate()
    中恢复状态
  • ViewPager中的所有片段都可以通过调用
    getActivity()
    获得对父活动的引用。或者,如果ViewPager位于片段中,则所有片段都可以通过调用
    getParentFragment()
    访问父片段。然后,您可以将结果强制转换到适当的类(或者更好的接口),并进行方法调用以来回传递数据。跟踪父活动/片段中的业务数据。这样,您就不需要一个全局单例

    比如说,

    public class MyParentFragment extends Fragment {
    
      private String mPageOneData;
      private int mPageTwoData;
      private List<Date> mPageThreeData;
    
      public void setPageOneData(String data) {
        mPageOneData = data;
      }
    
      ...
    }
    
    public class PageOneFragment extends Fragment {
    
      private void sendDataToParent(String data) {
        Fragment f = getParentFragment();
        if (f != null && f instanceof MyParentFragment) {
          MyParentFragment parent = (MyParentFragment) f;
          f.setPageOneData(data);
        }
      }
    
    }
    
    公共类MyParentFragment扩展了片段{
    私有字符串mPageOneData;
    私有数据;
    私人名单mPageThreeData;
    public void setPageOneData(字符串数据){
    mPageOneData=数据;
    }
    ...
    }
    公共类PageOneFragment扩展了该片段{
    私有void sendDataToParent(字符串数据){
    片段f=getParentFragment();
    如果(f!=null&&f MyParentFragment的instanceof){
    MyParentFragment父项=(MyParentFragment)f;
    f、 setPageOneData(数据);
    }
    }
    }
    
    在选择任何选项之前,请记住用户可以导航或打开任何其他应用程序,这样您就丢失了数据

    您可以在SaveInstanceState上使用
    onSaveInstanceState
    ,但它在某种程度上难以维护(正如您所说,您是android新手)。您可以使用

    • 数据库-当您希望存储和维护多个记录,但必须创建数据库getter/setter或使用任何ORM(如RushOrm等)时使用
    • 共享fpreference
      (最好)-如果要使用单个值
    在这两种情况下,您都将创建一个单例对象并在片段中访问其属性

  • 您可以将数据保存在活动的onSaveInstanceState()事件中,以防进程进入后台。 您可以使用Bundle和getExtras()在onCreate()事件中恢复数据

  • 您可以将数据保存在应用程序类中,并且数据仍然存在,以防您的进程进入后台

  • 我更喜欢第一个选项,因为您不希望在应用程序类中使用来自不同活动和片段的所有数据造成混乱。 我希望我能帮忙:)

    您结账了吗

    我不确定这是否是最好的方法,特别是当你的问题太宽泛时,但是只有5个片段就很酷了


    希望它能有所帮助,而单例方法似乎很容易实现和理解,它并不是实现您所需的最佳方法。一个原因是,您的模型对象或您称之为业务对象的对象存在于活动的上下文之外,这可能会产生难以发现的bug。例如,当系统创建了多个activity类实例,并且两个实例都引用了您的singleton时。看看你是如何失去对物体的跟踪的

    我要做的是

  • 让我的模型对象实现你一开始会讨厌它,但一旦你习惯了它,它就会成为你模型最好的朋友
  • 由于您的模型是可打包的,现在您可以轻松地在片段、活动之间传递它,甚至可以将它保存在共享首选项中在片段或活动之间传递
    parcelable
    时,这里需要注意的一点很重要,它就像传递值一样,即每次创建新实例时。
  • 设置片段的参数,或者如果片段已经实例化,则获取参数并添加模型。以下是一个例子: 如果片段尚未激活:

    Bundle