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

时间:2017-02-17 16:20:21

标签: android android-fragments android-viewpager singleton

我在ViewPager中有5个片段用于逐步填充业务对象的几个字段,在每个步骤中将设置其中一些字段。我已经阅读了许多关于片段之间的通信的文章,但是我感觉不像其他人喜欢的方式,所以在考虑如何在我的情况下这样做之后,最后我开始考虑使用单件模型对象,所有片段都可以轻松访问到它的领域并按照特定的步骤填写它们。

由于我是android新手,我想听听专家关于使用单例而不是在已实现的接口之类的片段之间传递数据(看起来它太复杂且难以维护)。任何建议都会有所帮助。

7 个答案:

答案 0 :(得分:6)

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

  1. 根据定义,单例将您的应用程序限制为主业务对象的单个实例。如果您(或设计师或您老板的老板的老板)决定一次拥有多个ViewPage,那么无论如何您都必须改变您的架构。
  2. “Android思维方式”是指您的用户可能会将您的应用置于后台,并在返回应用之前使用其他应用。如果系统决定在后台终止您的应用程序,那么您的单例内存对象将被销毁,您的用户将失去所有进度。正确的Android保存方式是将状态保存在活动或片段中,在onSaveInstanceState()中正确保存,然后在onCreate()中恢复。
  3. ViewPager中的所有片段都可以通过调用getActivity()来获取对父Activity的引用。或者,如果您的ViewPager在片段内,则所有片段都可以通过调用getParentFragment()来访问父片段。然后,您可以将结果转换为适当的类(或更好的接口),并进行方法调用以来回传递数据。在父Activity / Fragment中跟踪您的业务数据。这样,您就不需要全局单例

    例如,

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

答案 1 :(得分:6)

虽然单身方法似乎很容易实现并且理解它不是达到所需要的最佳方式。一个原因是你的模型对象或你称之为业务对象的东西生活在你的活动的上下文之外,这可能会造成难以发现的错误。例如。如果系统创建了多个活动类实例,并且两者都保持对您的单例的引用。看看你如何失去对象的踪迹?

我会做的是

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

    Bundle args = new Bundle(); args.putParcable("businessObject", yourBusinessObjectThatIsParcable); yourFragment.setArguments(args);

    否则:     yourFragment.getArguments().putParcelable("businessObject", yourBusinessObjectThatIsParcable);

  4. 在您的片段中,也许在onCreateView方法中获取您的模型对象,如MyParcableObject mpo = (MyParcableObject)getArguments().getParcelable("businessObject"),并使用它设置您想要的任何数据。

  5. 当您在按钮上单击或在onPause方法上完成对象的编辑时,更新了片段的参数getArguments().putParcelable("businessObject", mpo);

  6. 在您的上一页或最后一个片段中,您可以将对象传递给您的活动,here是如何操作的

  7. 即使它看起来很麻烦,但是你需要习惯作为Android开发人员。当模型实现parcelable时,您可以获得更多控制权。

    执行所需操作的另一种方法是通过Delegation Pattern,但它主要用于回调,即使您也可以传递对象。

答案 2 :(得分:2)

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

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

  3. 我更喜欢第一种选择,因为你不想在应用程序类中混淆包含来自不同活动和片段的所有数据。 我希望我能提供帮助:)。

答案 3 :(得分:1)

您有结帐EventBus吗?

我不确定这是否是最佳方法,特别是当您的问题过于宽泛时,只有5个碎片会很酷。

希望有所帮助

答案 4 :(得分:0)

我认为在您的MainActivity中有一个ViewPager,而FragmentOne将是视图寻呼机内的一个片段。这里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");
        }
    }
    ...
}

首先加载片段时,从MainActivity调用update方法。您可以执行此操作覆盖getItemPosition中的PagerAdapter方法,如下所示:

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

答案 5 :(得分:0)

在选择任何选项之前,请记住,用户可以导航或打开任何其他应用,以免丢失数据。

您可以使用onSaveInstanceState,但它会以某种方式难以维护(正如您所说的Android新手)。您可以使用

使用单身人士
  • 数据库 - 当您想要存储多个记录时使用,但您必须创建数据库getter / setter或使用任何ORM,如RushOrm等。
  • SharefPreference(最好) - 如果您想使用单个值。

在这两种情况下,您都将创建一个单例对象并在片段中访问其属性。

答案 6 :(得分:-1)

使您的对象可以使用,然后使用bundle将其传递给其他片段。即bundle.putParcelable(obj)parcelable是非常有效和快速的。

它应该激励你

http://www.developerphil.com/parcelable-vs-serializable/