Posted at

ViewModel について


概要

ViewModel が導入される前は、Activity や Fragment に通信処理や色々な処理を実装していました。

別クラスに分離して、処理を分けたとしてもUIに情報を通知するためにコールバックをひたすら実装することが多かったです。

ViewModel が導入され、UIと切り離して実装でき、通知も LiveData を使うことで楽に実装出来るようになったので、サンプルを記載したいと思います。


ViewModel 導入前

例えば、AsyncTask で、UIと重い処理をクラスで分けた場合、下記のような実装するかと思います。

UIで、CallBackを受け取って、UI操作をします。

public class MainTask extends AsyncTask<Void, Void, Long> {

private Callback callback;
public MainTask(CallBack callBack) {
this.callback = callBack;
}

@Override
protected Long doInBackground(Void... params) {
// 重い処理
if (ok) {
return 0L;
} else {
return -1L;
}
}

@Override
protected void onPostExecute(Long result) {
if (result == 0) {
callback.onComplete();
} else {
callback.onError();
}
}

public interface CallBackTask {
public void onComplete();

public void onError();
}
}


ViewModel 導入後

LiveData を postValue することで、UI に通知することが可能です。

導入前と比較するため同様な記載をしていますが、MutableLiveData<Long> として、値を渡せますので、resultの結果を渡せばいいことになります。そのため、本来なら onError は不要かと思います。

public class MainViewModel extends ViewModel {

private final MutableLiveData<Long> onComplete = new MutableLiveData<>();
private final MutableLiveData<Long> onError = new MutableLiveData<>();

public MainViewModel() {
new MainTask().execute();
}

public LiveData<Long> getComplete() {
return onComplete;
}

public LiveData<Long> getError() {
return onError;
}

private class MainTask extends AsyncTask<Void, Void, Long> {

@Override
protected Long doInBackground(Void... params) {
// 重い処理
if (true) {
return 0L;
} else {
return -1L;
}
}

@Override
protected void onPostExecute(Long result) {
if (result == 0) {
onComplete.postValue(result);
} else {
onError.postValue(result);
}
}
}
}

UI側は、observe することで、変化があるたびに onChanged が呼ばれますので、それに適したUIを操作するだけになります。

    @Override

public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mViewModel = ViewModelProviders.of(this).get(MainViewModel.class);
mViewModel.getComplete().observe(this, new Observer<Long>() {
@Override
public void onChanged(Long result) {
// UI操作
}
});
mViewModel.getError().observe(this, new Observer<Long>() {
@Override
public void onChanged(Long result) {
// UI操作
}
});
}

今までは、必要なコールバックを interface で定義して、都度渡す必要がありましたが、ViewModel 側でUIに通知したい場合は、postValue する。

UI側は、observe で変化が合った場合にUIを操作するだけになります。


おまけ

ここまで対応すると、もう kotlin で実装した方がすごく楽になります。皆さんも kotlin を使っていきましょう。

    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.1'

implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.1'

class MainViewModel : ViewModel(), CoroutineScope {

override val coroutineContext: CoroutineContext
get() = Dispatchers.Main + job

private val job = Job()

val data = MutableLiveData<Long>()

fun getData() {
launch {
// 重い処理
if (true) {
data.postValue(0)
} else {
data.postValue(-1)
}
}
}
}

    override fun onActivityCreated(savedInstanceState: Bundle?) {

super.onActivityCreated(savedInstanceState)
viewModel = ViewModelProviders.of(this).get(MainViewModel::class.java)
viewModel.data.observe(this, Observer {
// UI操作
if (it == 0L) {

} else {

}
})
}