UIの仮組みとViewModelの導入
前回の記事でHiltを活用できるようになりました。
それではここからアプリを組み上げていきましょう。
目次
今回の作業内容
- ViewModelを導入する
- UIを追加する
- 通信状態に応じてUIを更新する機構を追加する
ViewModelを追加する
少々ネタバレですが、通信機能とUI更新機能を全部MainActivityに書き込むと、MainActivityの可読性が著しく落ちます。
なので、必要最小限のものはMainActivityに残しますが、必要最小限ではない事柄は全部ViewModelへ移します。
ViewModelの定義
まず、プロジェクトエクスプローラー上の任意のディレクトリを右クリック → New → Kotlin File/Class
とたどり、JsonPlaceHolderViewModel
クラスを追加します。
class JsonPlaceHolderViewModel {}
これを、Hiltの管理下にあるViewModelだという定義に書き換えます。
@HiltViewModel
class JsonPlaceHolderViewModel @Inject constructor() : ViewModel (){}
このViewModelに通信の実行と実行結果としてのUIステート生成を委ねます。
UIを追加する
とりあえず仮組みのUIとして、ロード中、ロート完了、エラーの3状態を表示できるUIを追加したいと思います。
Sealed Interface
通信の状態が3つあるとして、それをUIステートに割り当てる場合はSealed Interface
が使えます。
sealed interface JsonPlaceHolderUIState{
data object Success(val posts: List<Post>): JsonPlaceHolderUIState
data object Error: JsonPlaceHolderUIState
data object Loading: JsonPlaceHolderUIState
}
このSealed Interfae
により、以下のようなUIステートを生成できます。
- 通信に成功したら
Post
型のListを引数とするSuccess、 - 通信中ならLoading
- 通信にエラーが起きたらError
通信状態に応じてUIを更新する機構を追加する
MutaleState
さきほど定義した3つの状態を広報するMutableStateをViewModelに定義します。
@HiltViewModel
class JsonPlaceHolderViewModel @Inject constructor() : ViewModel (){
...
var jsonPlaceHolderUIState: JsonPlaceHolderUIState by mutableStateOf(JsonPlaceHolderUIState.Loading)
...
}
Stateのhoist
先ほど定義した3状態に応じて表示を差し替える機構を追加します。
@Composable
fun JsonPlaceHolderUI(
jsonPlaceHolderUIState: JsonPlaceHolderUIState,
modifier: Modifier = Modifier
){
/**
* jsonPlaceHolderUIStateの状態に応じて表示を差し替える
*/
when (jsonPlaceHolderUIState){
JsonPlaceHolderUIState.Error -> {
Text(text = "Error", modifier = modifier)
}
JsonPlaceHolderUIState.Loading -> {
Text(text = "Loading", modifier = modifier)
}
is JsonPlaceHolderUIState.Success -> {
val p = jsonPlaceHolderUIState.posts
Text(text = "Success, size is " + p.size, modifier = modifier)
}
}
}
やっていることは単純で、状態を受け取ってwhenでTextを差し替えるだけです。
MainActivity
ViewModel内のMutableStateを読み取って、Composableな関数へ渡します。
このような仕組みをState Hoist
と呼びます。
https://developer.android.com/jetpack/compose/state#state-hoisting
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
...
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
,,,
private val jsonPlaceHolderViewModel: JsonPlaceHolderViewModel by viewModels()
...
setContent {
RetrofitTheme {
// A surface container using the 'background' color from the theme
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
JsonPlaceHolderUI(
jsonPlaceHolderUIState = jsonPlaceHolderViewModel.jsonPlaceHolderUIState
)
}
}
}
...
}
...
}
State Hoistの仕組みを取り入れることで、PreviewやTestが書きやすくなります。
できあがり
できました。
通信状態に応じてUIが差し代わるようになりました。
- 通信中は
Loading
- 通信に成功したら
Success, size is 100
- エラー時は
Error
(機内モードで通信するとエラーを発生させることができます)
リポジトリ
https://github.com/aburagirio/retrofitExample.git
ブランチpart4
をcheck outしてください。