¡Oye! Mi nombre es Vitaly Sulimov, soy desarrollador de Android en Wheely y hoy me gustaría hablarles sobre la arquitectura de las aplicaciones móviles. A saber, cómo en la empresa aplicamos la arquitectura Redux a nuestras dos aplicaciones y qué resultó de ella.
Descargo de responsabilidad n. ° 1
Android- 2016- , MVC, MVP, Moxy Arello Mobile, Clean Architecture Redux. — . , , . , , , . — Android-.
?
Redux, , :
1. View
View — , -, , , — (, , , , Pull To Refresh, ..)
2. , - /
, .
— , runtime, , , .
3.
, , . , / ..
4.
, , , - . , , : , .
Redux, !
Redux Android-, , , Android.
Redux . , Store, , , - , , - . , , Redux.
State
, Redux. () .
Store
Store (State) , Middleware Reducer.
API , (Action), .
Action
, , Store. ( ). .
Reducer
, (Action). , , () ( , , , ..).
, Reducer Copy-on-write , .
Middleware
Middleware , (Action) , , Reducer.
Middleware , - .
Redux Android?
. Android (Action), , , Activity, View, BroadcastReceiver - Action , ( ).
Talk is cheap. Show me the code.
, , Redux , . Counter, , . . .
?
Android Studio Redux Kotlin.
Redux, Android. , , , !
#2
, Rx, Coroutines, - , , . KISS, , .
, Redux? , Copy-on-write. , Kotlin - data class.
ApplicationState.kt
data class ApplicationState(
val counter: Int = 0
)
, , .
Action Redux. Action . Middleware Reducer, sealed class’, , . .
CounterAction.kt
sealed class CounterAction : Action {
object Increment : CounterAction()
object Reset : CounterAction()
}
Reducer
, Reducer<S>, S - , .. ApplicationState. - - reduce. , .
CounterReducer.kt
object CounterReducer : Reducer<ApplicationState> {
override fun reduce(action: Action, state: ApplicationState): ApplicationState =
when (action) {
is CounterAction.Increment ->
state.copy(counter = state.counter.inc())
is CounterAction.Reset ->
state.copy(counter = 0)
else ->
state
}
}
Store
, Store.
Store . - AbstractStore<S> . Middleware Reducer.
ApplicationStore.kt
class ApplicationStore(
initialState: ApplicationState,
middlewares: List<Middleware<ApplicationState>>,
reducers: List<Reducer<ApplicationState>>
) : AbstractStore<ApplicationState>(initialState, middlewares, reducers)
ApplicationStore, Middleware Reducer. Store, ApplicationState - AppComponent Store .
AppComponent.kt
object AppComponent {
val store = ApplicationStore(
initialState = ApplicationState(),
middlewares = emptyList(),
reducers = listOf(CounterReducer)
)
}
, , .
ReduxFunctions.kt
fun dispatch(action: Action) =
AppComponent.store.dispatch(action)
fun subscribe(subscription: Subscription<ApplicationState>) =
AppComponent.store.subscribe(subscription)
fun unsubscribe(subscription: Subscription<ApplicationState>) =
AppComponent.store.unsubscribe(subscription)
, , , , reducer, , . , . , reducer’a, , store . , UI!
Android-. (Single Activity / Multiple Activities / Fragments?), , - Activity View. Activity View, .
CounterView.kt
class CounterView(
context: Context
) : FrameLayout(context) {
private val counterSubscription = SubStateSubscription<ApplicationState, Int>(
transform = { it.counter },
onStateChange = { state: Int, _: Boolean -> handleCounterStateChange(state) }
)
private lateinit var counterTextView: TextView
private lateinit var floatingActionButton: FloatingActionButton
init {
inflate(context, R.layout.view_counter, this)
findViewsById()
setOnClickListeners()
}
private fun findViewsById() {
counterTextView = findViewById(R.id.counterTextView)
floatingActionButton = findViewById(R.id.floatingActionButton)
}
private fun setOnClickListeners() {
floatingActionButton.setOnClickListener { dispatch(CounterAction.Increment) }
}
override fun onAttachedToWindow() {
super.onAttachedToWindow()
subscribeToStateChanges()
}
private fun subscribeToStateChanges() {
subscribe(counterSubscription)
}
override fun onDetachedFromWindow() {
unsubscribeFromStateChanges()
super.onDetachedFromWindow()
}
private fun unsubscribeFromStateChanges() {
unsubscribe(counterSubscription)
}
private fun handleCounterStateChange(state: Int) {
counterTextView.text = state.toString()
}
}
, . SubStateSubscription, , , - , , Rx, map(), - .
, lateinit var View.
. XML-, Floating Action Button. dispatch CounterAction.Increment, .
OnViewAttached / Detached from window.
, , . , TextView.
CounterView.kt
... counterTextView.text = state.toString() ...
! .
, , View , counter ApplicationState, , by design, Application View , … , , , ( “”). ? .
, Redux Android
, Android Redux. . AppCompatActivity, AppCompatActivity : Activity ActivityLifecycleAction ( ) . - AppCompatActivity Store, . .
MainActivity.kt
class MainActivity : AppCompatActivity<ApplicationState>() {
private lateinit var contentViewGroup: ViewGroup
override fun getStore(): Store<ApplicationState> =
AppComponent.store
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
findViewsById()
addCounterView()
}
private fun findViewsById() {
contentViewGroup = findViewById(R.id.contentViewGroup)
}
private fun addCounterView() {
contentViewGroup.addView(CounterView(context = this))
}
}
Middleware
- MIddleware. , : Activity (onDestroy) isFInishing == true - .
isFinishing , true, , , false - , .
, , . , Middleware<S>, S - handleAction().
ActivityLifecycleMiddleware.kt
object ActivityLifecycleMiddleware : Middleware<ApplicationState> {
override fun handleAction(
action: Action,
state: ApplicationState,
next: Next<ApplicationState>
): Action {
val newAction = when (action) {
is ActivityLifecycleAction.OnDestroy ->
handleActivityOnDestroy(action)
else ->
action
}
return next(newAction, state)
}
private fun handleActivityOnDestroy(action: ActivityLifecycleAction.OnDestroy): Action =
if (action.isFinishing) CounterAction.Reset else action
}
, . ActivityLifecycleAction.OnDestroy Reducer, Middleware, , . , isFinishing == true, Reducer CounterAction.Reset, , false - , , , . middleware AppComponent-.
AppComponent.kt
store = ApplicationStore( initialState = ApplicationState(), middlewares = listOf(ActivityLifecycleMiddleware), reducers = listOf(CounterReducer) )
!
Redux. , , — . , JavaScript. , , , . . - - Action. - Middleware, - Reducer. View , .
, , Counter, Middleware Reducer , . Redux- — “”, Android ( ), API OpenWeatherMap. .
https://gitlab.com/v.sulimov/android-redux-kotlin
https://gitlab.com/v.sulimov/android-redux-demo
https://gitlab.com/v.sulimov/android-openweather-kotlin
, Redux Android, . , , , , Redux , , . , - .
, , .
, . Wheely.