LoginSignup
1
0

Android+RetrofitでHTTP通信するアプリの作り方(その4)

Posted at

UIの仮組みとViewModelの導入

前回の記事でHiltを活用できるようになりました。

それではここからアプリを組み上げていきましょう。

目次

今回の作業内容

  1. ViewModelを導入する
  2. UIを追加する
  3. 通信状態に応じてUIを更新する機構を追加する

ViewModelを追加する

少々ネタバレですが、通信機能とUI更新機能を全部MainActivityに書き込むと、MainActivityの可読性が著しく落ちます。

なので、必要最小限のものはMainActivityに残しますが、必要最小限ではない事柄は全部ViewModelへ移します。

ViewModelの定義

まず、プロジェクトエクスプローラー上の任意のディレクトリを右クリック → New → Kotlin File/Classとたどり、JsonPlaceHolderViewModelクラスを追加します。

JsonPlaceHolderViewModel.kt
class JsonPlaceHolderViewModel  {}

これを、Hiltの管理下にあるViewModelだという定義に書き換えます。

JsonPlaceHolderViewModel.kt
@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ステートを生成できます。

  1. 通信に成功したらPost型のListを引数とするSuccess、
  2. 通信中ならLoading
  3. 通信にエラーが起きたらError

通信状態に応じてUIを更新する機構を追加する

MutaleState

さきほど定義した3つの状態を広報するMutableStateをViewModelに定義します。

JsonPlaceHolderViewModel.kt
@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が差し代わるようになりました。

  1. 通信中はLoading
  2. 通信に成功したらSuccess, size is 100
  3. エラー時はError(機内モードで通信するとエラーを発生させることができます)

リポジトリ

https://github.com/aburagirio/retrofitExample.git

ブランチpart4をcheck outしてください。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0