-
Notifications
You must be signed in to change notification settings - Fork 0
Cook book
codeerow edited this page Jul 17, 2019
·
23 revisions
Okay, this is what we need for this essential recipe:
- Model
- ViewModel
- View
- Dagger/Koin
- Model is our business logic. We should make an use case for interacting with it:
/* Use case for fetching string from network/database/... */
class FetchStringUseCase(private val api: StringAPI //imagine such weird API) : UseCase() {
fun execute(request: FetchStringRequest) : Single<String> {
return api.fetch(request)
}
- Create ViewModel and provide your just created use case:
/* ViewModel for interacting with business logic */
class FetchViewModel @Inject(private val fetchStringUseCase: FetchStringUseCase): MvvmViewModel<Unit> {
val string = MutableLiveData<String>().apply { value = "" }
fun fetchString() {
fetchStringUseCase.execute(FetchRequest()) .doOnSuccess(string::postValue)
.subscribeByViewModel()
}
}
- And the last, add a view:
class FetchFragment : MvvmFragment() {
override val viewModel by viewModel<AViewModel>()
/* Lifecycle */
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_a, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel.string.observe(this, Observer { tvString.text = it })
RxView.clicks(btnFetchData)
.subscribeByView { viewModel.fetchData() }
}
}
- After MVVM created you can add as much salt as you want.
First of all setup MVVM from the first recipe. Next we need:
- Use case state
- ViewModel state
- One overriding on view
- Smoke a joint or drink some Vodka.
- UseCase has its own state out of box. Add some state changing for your use case:
class FetchStringUseCase(private val api: StringAPI): UseCase() {
fun fetchString(request: FetchStringRequest) : Single<String> {
return api.fetchString(request)
.doOnSubscribe {state.accept(State.Processing()) }}
.doOnError { state.accept(State.Failure(listOf(it))) }
.doOnSuccess { state.accept(State.Success()) }
}
- Bind use case state with your ViewModel state. Yeah, each ViewModel has state that represents a view state. By the way, states for use case and view model are the same sealed classes with New, Processing, Failure and Success states.
class FetchViewModel ...
init {
// When there is at least one use case with
// failure state -> ViewModel state is Failure,
// if no failures but there is at least one processing use case -> ViewModel state is Processing,
// else -> ViewModel state is Success
state.bindsWith(fetchStringUseCase.state)
}
...
- Handle view state on the view. You can observe the whole view state by overriding render or grannualy observe state for use cases:
class FetchFragment ...
override fun onViewCreated(...) {
// Observe use case states for animate something. (e.g. button for fetching string)
viewModel.fetchStringUseCase.state
doOnNext(::renderFetchingString)
subscribeByView()
}
override fun render(viewState: State) {
when(viewState) {
is New -> renderInitialView()
is Success -> renderSuccessView()
is Processing -> renderProcessingView()
is Failure -> renderFailureView(viewState.failures)
}
}
// fun renderInitialView()
// fun renderFetchingString()
// ...
}
Pandora have out of box navigation based on Android Architecture Component. But it makes navigation more customizable. We need:
- Navigation graph
- AacFragment or AacActivity (navigation holder)
- Some fragments (screens we will navigate through)
- Some view models for fragments And it's all!
- Create MainActivity and extend it from AacActivity. It means that your activity turns into navigation holder and can handle common navigation command like StartActivity and FinishActivity and special Aac Command:
- AacGoForward
- AacGoBackward Navigation command might come from ViewModel or be applying from fragment/activity. I use BaseAacActivity for injecting viewmodels factory.
class MainActivity : BaseAacActivity() {
override val settings = AacSettings(start)
}
- Core concepts
- ViewModel
- View
- UseCase
- State
- Navigation
- Using out of box navigation
- Custom navigation
- UI Configuration
- Using out of box UI configurations (Toolbar, BottomNavigation)
- Custom UI Provider/ UI Configuration
- MVVM relationship, Interact with Business logic, ViewState handling