目标是从Fragment
获取信息,以便托管Activity
可以显示该信息。我们举一个简单的例子,假设当Fragment
更改时,我们希望在Fragment
的操作栏中显示Activity
的标题。
这是我过去的做法:
Activity
@Override
protected void onCreate( @Nullable Bundle savedInstanceState )
{
super.onCreate( savedInstanceState );
getSupportFragmentManager().addOnBackStackChangedListener( this );
}
@Override
public void onBackStackChanged( )
{
BaseFragment fragment = mNavigationManager.getCurrentFragment( );
if( fragment != null && fragment instanceof ActionBarProvider )
mActionBarTitle.setText( ( ( ActionBarProvider ) fragment ).getTitle( ) );
}
ActionBarProvider
public interface ActionBarProvider
{
String getTitle( );
}
片段
// implements ActionBarProvider
@Override
protected String getTitle( )
{
return "Hello world";
}
以下是我对MVVM的看法:
活动
@Override
protected void onCreate( @Nullable Bundle savedInstanceState )
{
super.onCreate( savedInstanceState );
mViewModel = ViewModelProviders.of( this, mViewModelFactory ).get( MainViewModel.class );
mViewModel.getTitle( ).observe( this, s -> mActionBarTitle.setText( s ) );
}
MainViewModel
private MutableLiveData< String > mTitle = new MutableLiveData<>( );
public MutableLiveData< String > getTitle( )
{
return mTitle;
}
public void setTitle( String title )
{
mTitle.postValue( title );
}
片段
@Override
public void onActivityCreated( @Nullable Bundle savedInstanceState )
{
super.onActivityCreated( savedInstanceState );
MainViewModel viewModel = ViewModelProviders
.of( getActivity( ), mViewModelFactory )
.get( MainViewModel.class );
viewModel.setTitle( "hello world" );
}
MVVM看起来更干净,但它假设Fragment
知道它的主要Activity
ViewModel:
MainViewModel viewModel = ViewModelProviders
.of( getActivity( ), mViewModelFactory )
.get( MainViewModel.class );
因此,如果您将Fragment
移至另一个Activity
,那么这项工作就无法完成。
我应该保持旧的方式吗?或者你们有其他方式使用MVVM进行这种通信吗?
THX!
答案 0 :(得分:5)
使用ViewModel是一条黄金法则。除了* .arch软件包之外,导入中以Android软件包开头的所有内容都是错误的。
你没有在你的行动中设置标题,因为它与片段绑定。
在片段中的getActivity().setTitle()
/ onStart
方法中使用onResume
。
ViewModels绑定到片段OR或主机活动。更改活动也会在ViewModel中调用onCleared()
。您无法使用ViewModel在多个活动之间共享数据。
创建共享数据的接口不是MVVM。它是MVP,应该避免使用MVVM和Google's AAC。
由于多个活动可能是您的片段的主机,因此您永远不应直接访问该活动。最好在片段中使用if (getActivity() != null) { getActivity().setTitle(...) }
。
顺便说一下,如果你不修改getter / setter,你也应该使用public final LiveData
并避免使用getter和setter。您的LiveData
实例不会发生变化,但数据会发生变化。方法final
就好了。
public final LiveData<String> mTitle = new MutableLiveData<String>();
如果您不想附加数据,还应该考虑使用setValue()
来设置数据。
因此,如果您将片段移动到另一个活动,这将无法正常工作。我应该保持旧的方式吗?或者你们有其他方式使用MVVM进行这种通信吗?
ViewModel只能在片段和托管活动之间共享,但它不能使用多个活动共享。