Android Architecture ComponentsのViewModelとHolderFragmentとActivity-Fragment間通信と。
Android Architecture ComponentsのViewModel周りの実装を読んでいくとふーんってなったのでActivity-Fragment間通信やれそうだしやってみたらいけたなーそりゃそうだねみたいな話
Android Architecture ComponentsのViewModelとViewModelProviders
Android Architecture ComponentsのViewModelは次のような抽象クラスである。なーんにもない。
public abstract class ViewModel { @SuppressWarnings("WeakerAccess") protected void onCleared() { } }
もう一つApplicationを安全に保持したAndroidViewModelがある。
public class AndroidViewModel extends ViewModel { private Application mApplication; public AndroidViewModel(Application application) { mApplication = application; } public <T extends Application> T getApplication() { return (T) mApplication; } }
ViewModelかAndroidViewModelを継承した上で、ViewModelProvidersを通してインスタンスを作る。
val viewModel = ViewModelProviders.of(this).get(MainViewModel::class.java)
ViewModelProvidersにはFactoryをセットできる。
val viewModel = ViewModelProviders.of(this, factory).get(MainViewModel::class.java)
デフォルトではDefaultFactoryが使われる。DefaultFactoryではAndroidViewModelかそれ以外かを判定してインスタンスを作ってる。 立て込んだViewModelを作るときはFactoryを実装することになる。
ViewModelとHolderFragment
抽象クラスであるViewModelはなーんにもしてないからわざわざインスタンスを作るためにViewModelProvidersを通す意味がわからないと思うが、 Configuration ChangeでのActivity再生成に備えてViewModelProvidersはガンバってViewModelの保持機能を備えている。
内部を追っかけるとActivityやFragmentをkeyとしてViewModelを保持するViewModelStoresというクラスが見つかる。
public static ViewModelProvider of(@NonNull FragmentActivity activity) { initializeFactoryIfNeeded(activity.getApplication()); return new ViewModelProvider(ViewModelStores.of(activity), sDefaultFactory); }
ViewModelStoresはさらにholderFragmentFor関数でHolderFragmentというFragmentを取り出している。
public static ViewModelStore of(FragmentActivity activity) { return holderFragmentFor(activity).getViewModelStore(); }
HolderFragmentはふつーのFragmentである。メンバにViewModelStoreを持っている。
で、コンストラクタでsetRetainInstance(true)
してる。
public class HolderFragment extends Fragment { private ViewModelStore mViewModelStore = new ViewModelStore(); public HolderFragment() { setRetainInstance(true); } // ... }
ViewModelStoreはHashMapでViewModelを保持している。
public class ViewModelStore { private final HashMap<String, ViewModel> mMap = new HashMap<>(); // ... }
ようするにUIなしFragmentじゃねーの
Activity-Fragment間通信
ActivityをkeyにViewModelインスタンスを取り出せるので、Activity-Fragment間で通信ができる。
たとえば2タブで子Fragmentからunread countをもらってタブに出すやつとか。 次のように更新の通知を受けたい値をLiveDataで用意する。
class MainViewModel : ViewModel() { val left: MutableLiveData<Int> = MutableLiveData() val right: MutableLiveData<Int> = MutableLiveData() }
で、こういう感じでobserveしておいて、
// MainActivity val viewModel = ViewModelProviders.of(this).get(MainViewModel::class.java) viewModel.left.observe(this, Observer { tab.count.text = it.toString() })
Fragment側で取り出して、更新すると
// Fragment val viewModel = ViewModelProviders.of(activity).get(MainViewModel::class.java) viewModel.left.value = 10
シュッ
Source Code
詳細はソースを見てください。
GitHub - sys1yagi/aac-viewmodel-with
雑感
へーって思った