概要
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 {
}
})
}