于 2017 年 6 月 12 日更新,
Android 官方提供了一个简单、准确的例子来说明 ViewModel 如何在 Master-Detail 模板上工作,你应该先看看它。在片段之间共享数据
正如@CommonWare、@Quang Nguyen 所说,Yigit 的目的不是从大师到细节的调用,而是更好地使用中间人模式。但是如果你想做一些片段事务,应该在活动中完成。此时,ViewModel 类应该是 Activity 中的静态类,并且可能包含一些 Ugly Callback 来回调 Activity 以进行 Fragment 事务。
我试图实现这一点并为此做了一个简单的项目。你可以看看它。大部分代码引用自 Google IO 2017,结构也是如此。
https://github.com/charlesng/SampleAppArch
我不使用Master Detail Fragment来实现组件,而是旧的(ViewPager中的fragment之间的通信。)逻辑应该是一样的。
但我发现使用这些组件很重要
- 您想在中间人中发送和接收的内容,它们应该只在 View Model 中发送和接收
- 在片段类中修改似乎并没有太多。因为它只是将实现从“接口回调”更改为“监听和响应 ViewModel”
- 视图模型初始化似乎很重要,并且可能在活动中被调用。
- 使用 MutableLiveData 使源仅在活动中同步。
1.寻呼机活动
public class PagerActivity extends AppCompatActivity {
/**
* 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 = new ViewModelProvider(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(它应该有一个更好的名字而不是这个)
public class PagerAgentViewModel extends ViewModel {
private final SavedStateHandle state;
private final MutableLiveData<String> messageContainerA;
private final MutableLiveData<String> messageContainerB;
public PagerAgentViewModel(SavedStateHandle state) {
this.state = state;
messageContainerA = state.getLiveData("Default Message");
messageContainerB = state.getLiveData("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.空白片段A
public class BlankFragmentA extends Fragment {
private PagerAgentViewModel viewModel;
public BlankFragmentA() {
// Required empty public constructor
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
viewModel = new ViewModelProvider(getActivity()).get(PagerAgentViewModel.class);
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) {
viewModel.sendMessageToB("Hello B");
}
});
//setup the listener for the fragment A
viewModel.getMessageContainerA().observe(getViewLifecycleOwner(), 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);
return view;
}
}
4.空白片段B
public class BlankFragmentB extends Fragment {
public BlankFragmentB() {
// Required empty public constructor
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
viewModel = new ViewModelProvider(getActivity()).get(PagerAgentViewModel.class);
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) {
viewModel.sendMessageToA("Hello A");
}
});
//setup the listener for the fragment B
viewModel.getMessageContainerB().observe(getViewLifecycleOwner(), 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);
return view;
}
}