使用新的架构组件ViewModel在片段之间共享数据 [英] Sharing data between fragments using new architecture component ViewModel

本文介绍了使用新的架构组件ViewModel在片段之间共享数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在上一个Google IO上,Google发布了一些新的Arch组件的预览,其中一个是ViewModel.

On Last Google IO, Google released a preview of some new arch components, one of which, ViewModel.

文档中google显示了一种可能的用法对于此组件:

In the docs google shows one of the possible uses for this component:

一个活动中的两个或多个片段通常需要 互相交流.这绝不是小事,因为这两个片段 需要定义一些接口描述,并且所有者活动必须 将两者捆绑在一起.而且,两个片段都必须处理案件 另一个片段尚未创建或不可见的地方.

It is very common that two or more fragments in an activity need to communicate with each other. This is never trivial as both fragments need to define some interface description, and the owner activity must bind the two together. Moreover, both fragments must handle the case where the other fragment is not yet created or not visible.

可以使用ViewModel对象解决此常见的痛点. 想象一个主细节片段的常见情况,我们有一个 用户从列表中选择一个项目和另一个项目的片段 显示所选项目内容的片段.

This common pain point can be addressed by using ViewModel objects. Imagine a common case of master-detail fragments, where we have a fragment in which the user selects an item from a list and another fragment that displays the contents of the selected item.

这些片段可以使用其活动范围共享ViewModel 处理这种沟通.

These fragments can share a ViewModel using their activity scope to handle this communication.

并显示一个实现示例:

public class SharedViewModel extends ViewModel {
    private final MutableLiveData<Item> selected = new MutableLiveData<Item>();

    public void select(Item item) {
        selected.setValue(item);
    }

    public LiveData<Item> getSelected() {
        return selected;
    }
}

public class MasterFragment extends Fragment {
    private SharedViewModel model;
    public void onActivityCreated() {
        model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
        itemSelector.setOnClickListener(item -> {
            model.select(item);
        });
    }
}

public class DetailFragment extends LifecycleFragment {
    public void onActivityCreated() {
        SharedViewModel model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
        model.getSelected().observe(this, { item ->
           // update UI
        });
    }
}

我很可能不需要那些用于片段的接口通过活动进行通信.

I was quite excited about the possibility of not needing those interfaces used for fragments to communicate through the activity.

但是Google的示例并未确切显示我将如何从master调用细节片段.

But Google's example does not show exactly how would I call the detail fragment from master.

我仍然必须使用界面由活动实现,它将调用fragmentManager.replace(...),还是有另一种方法可以使用新的体系结构?

I'd still have to use an interface that will be implemented by the activity, which will call fragmentManager.replace(...), or there is another way to do that using the new architecture?

推荐答案

于6/12/2017更新,

Android官方提供了一个简单而精确的示例,以说明ViewModel如何在Master-Detail模板上工作,您应该先看一下它.

Android Official provide a simple, precise example to example how the ViewModel works on Master-Detail template, you should take a look on it first.Share data between fragments

作为@CommonWare和@Quang Nguyen的方法,Yitit的目的不是从主打到细节,而是更好地使用中间人模式.但是,如果要进行一些片段事务,则应在活动中完成.那时,ViewModel类应该作为Activity中的静态类,并且可能包含一些丑陋的回调来回调活动以进行片段事务.

As @CommonWare, @Quang Nguyen methioned, it is not the purpose for Yigit to make the call from master to detail but be better to use the Middle man pattern. But if you want to make some fragment transaction, it should be done in the activity. At that moment, the ViewModel class should be as static class in Activity and may contain some Ugly Callback to call back the activity to make the fragment transaction.

我试图实现这一点,并为此做一个简单的项目.您可以看一下.大多数代码都引用自Google IO 2017以及该结构. https://github.com/charlesng/SampleAppArch

I have tried to implement this and make a simple project about this. You can take a look it. Most of the code is referenced from Google IO 2017, also the structure. https://github.com/charlesng/SampleAppArch

我不使用Master Detail Fragment来实现该组件,而是使用旧的(ViewPager中的片段之间的通信.)逻辑应相同.

I do not use Master Detail Fragment to implement the component, but the old one ( communication between fragment in ViewPager.) The logic should be the same.

但是我发现使用这些组件很重要

But I found something is important using these components

  1. 您想要在中间人中发送和接收的内容,应该仅在View Model中发送和接收它们
  2. 在fragment类中的修改似乎不太多.由于它仅将实现从接口回调"更改为侦听并响应ViewModel"
  3. View Model初始化似乎很重要,并且很可能在活动中被调用.
  4. 使用MutableLiveData使源仅在活动中同步.

1.Pager活动

public class PagerActivity extends LifecycleActivity {
    /**
     * The pager widget, which handles animation and allows swiping horizontally to access previous
     * and next wizard steps.
     */
    private ViewPager mPager;
    private PagerAgentViewModel pagerAgentViewModel;
    /**
     * The pager adapter, which provides the pages to the view pager widget.
     */
    private PagerAdapter mPagerAdapter;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_pager);
        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        });
        mPager = (ViewPager) findViewById(R.id.pager);
        mPagerAdapter = new ScreenSlidePagerAdapter(getSupportFragmentManager());
        mPager.setAdapter(mPagerAdapter);
        pagerAgentViewModel = ViewModelProviders.of(this).get(PagerAgentViewModel.class);
        pagerAgentViewModel.init();
    }

    /**
     * A simple pager adapter that represents 5 ScreenSlidePageFragment objects, in
     * sequence.
     */
    private class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter {
       ...Pager Implementation
    }

}

2.PagerAgentViewModel (应该用一个更好的名称代替它)

2.PagerAgentViewModel (It deserved a better name rather than this)

public class PagerAgentViewModel extends ViewModel {
    private MutableLiveData<String> messageContainerA;
    private MutableLiveData<String> messageContainerB;

    public void init()
    {
        messageContainerA = new MutableLiveData<>();
        messageContainerA.setValue("Default Message");
        messageContainerB = new MutableLiveData<>();
        messageContainerB.setValue("Default Message");
    }

    public void sendMessageToB(String msg)
    {
        messageContainerB.setValue(msg);
    }
    public void sendMessageToA(String msg)
    {
        messageContainerA.setValue(msg);

    }
    public LiveData<String> getMessageContainerA() {
        return messageContainerA;
    }

    public LiveData<String> getMessageContainerB() {
        return messageContainerB;
    }
}

3.BlankFragmentA

public class BlankFragmentA extends LifecycleFragment {

    public BlankFragmentA() {
        // Required empty public constructor
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        //setup the listener for the fragment A
        ViewModelProviders.of(getActivity()).get(PagerAgentViewModel.class).getMessageContainerA().observe(this, new Observer<String>() {
            @Override
            public void onChanged(@Nullable String msg) {
                textView.setText(msg);
            }
        });

    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View view = inflater.inflate(R.layout.fragment_blank_a, container, false);
        textView = (TextView) view.findViewById(R.id.fragment_textA);
        // set the onclick listener
        Button button = (Button) view.findViewById(R.id.btnA);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                ViewModelProviders.of(getActivity()).get(PagerAgentViewModel.class).sendMessageToB("Hello B");
            }
        });
        return view;
    }

}

4.BlankFragmentB

public class BlankFragmentB extends LifecycleFragment {

    public BlankFragmentB() {
        // Required empty public constructor
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        //setup the listener for the fragment B
        ViewModelProviders.of(getActivity()).get(PagerAgentViewModel.class).getMessageContainerB().observe(this, new Observer<String>() {
            @Override
            public void onChanged(@Nullable String msg) {
                textView.setText(msg);

            }
        });
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View view = inflater.inflate(R.layout.fragment_blank_b, container, false);
        textView = (TextView) view.findViewById(R.id.fragment_textB);
        //set the on click listener
        Button button = (Button) view.findViewById(R.id.btnB);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                ViewModelProviders.of(getActivity()).get(PagerAgentViewModel.class).sendMessageToA("Hello A");

            }
        });
        return view;
    }

}

这篇关于使用新的架构组件ViewModel在片段之间共享数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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