feature TI-194: [Android] DI

This commit is contained in:
Evgeny Dubravin 2024-03-29 22:36:19 +07:00
parent c2ea821791
commit a81a66bdb9
10 changed files with 124 additions and 15 deletions

View File

@ -11,12 +11,12 @@
android:label="@string/common_app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="false"
tools:ignore="GoogleAppIndexingWarning">
tools:ignore="GoogleAppIndexingWarning"
android:theme="@style/AppTheme">
<activity
android:name="ru.touchin.template.SingleActivity"
android:name=".feature.SingleActivity"
android:screenOrientation="portrait"
android:theme="@style/AppTheme"
android:windowSoftInputMode="adjustResize"
android:exported="true">
<intent-filter>

View File

@ -1,5 +0,0 @@
package ru.touchin.template
import androidx.appcompat.app.AppCompatActivity
class SingleActivity : AppCompatActivity()

View File

@ -1,12 +1,17 @@
package ru.touchin.template.base.activity
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.ViewModel
import ru.touchin.template.di.SharedComponent
import ru.touchin.template.di.getSharedModule
class BaseActivity : AppCompatActivity() {
abstract class BaseActivity<T : ViewModel> : AppCompatActivity() {
protected val viewModel: T by lazy { createViewModelLazy().value }
protected val viewModelFactory by lazy { getSharedComponent().viewModelFactory() }
abstract fun createViewModelLazy(): Lazy<T>
protected fun getSharedComponent(): SharedComponent = getSharedModule()
}

View File

@ -1,12 +1,15 @@
package ru.touchin.template.base.fragment
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModel
import ru.touchin.template.di.SharedComponent
import ru.touchin.template.di.getSharedModule
class BaseFragment : Fragment() {
abstract class BaseFragment<T : ViewModel> : Fragment() {
protected val viewModelFactory by lazy { getSharedComponent().viewModelFactory() }
protected abstract fun createViewModelLazy(): Lazy<T>
protected fun getSharedComponent(): SharedComponent = getSharedModule()
}

View File

@ -2,9 +2,11 @@ package ru.touchin.template.di
import dagger.Module
import ru.touchin.template.di.viewmodel.ViewModelFactory
import ru.touchin.template.feature.second.SecondViewModel
interface SharedComponent {
fun viewModelFactory(): ViewModelFactory
fun secondScreenViewModelFactory(): SecondViewModel.Factory
}
@Module

View File

@ -5,9 +5,10 @@ import androidx.lifecycle.ViewModelProvider
import dagger.Binds
import dagger.Module
import dagger.multibindings.IntoMap
import ru.touchin.template.SingleViewModel
import ru.touchin.template.di.viewmodel.ViewModelFactory
import ru.touchin.template.di.viewmodel.ViewModelKey
import ru.touchin.template.feature.SingleViewModel
import ru.touchin.template.feature.first.FirstViewModel
@Module
interface ViewModelModule {
@ -19,4 +20,10 @@ interface ViewModelModule {
@IntoMap
@ViewModelKey(SingleViewModel::class)
fun bindsSingleViewModel(viewModel: SingleViewModel): ViewModel
@Binds
@IntoMap
@ViewModelKey(FirstViewModel::class)
fun bindsFirstViewModel(viewModel: FirstViewModel): ViewModel
}

View File

@ -1,7 +1,13 @@
package ru.touchin.template.di.viewmodel
import android.os.Bundle
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.lifecycle.AbstractSavedStateViewModelFactory
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.savedstate.SavedStateRegistryOwner
import javax.inject.Inject
import javax.inject.Provider
@ -14,4 +20,25 @@ class ViewModelFactory @Inject constructor(
val viewModel = viewModels[modelClass]?.get()
return viewModel as T
}
}
inline fun <reified VM : ViewModel> Fragment.assistedViewModel(
crossinline creator: (SavedStateHandle) -> VM,
): Lazy<VM> = viewModels { createAbstractSavedStateViewModelFactory(arguments, creator) }
inline fun <reified T : ViewModel> SavedStateRegistryOwner.createAbstractSavedStateViewModelFactory(
arguments: Bundle? = Bundle(),
crossinline creator: (SavedStateHandle) -> T,
): ViewModelProvider.Factory {
return object : AbstractSavedStateViewModelFactory(
owner = this@createAbstractSavedStateViewModelFactory,
defaultArgs = arguments,
) {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(
key: String,
modelClass: Class<T>,
handle: SavedStateHandle,
): T = creator(handle) as T
}
}

View File

@ -1,6 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.fragment.app.FragmentContainerView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/fragment_container"
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent" />
android:layout_height="match_parent"
android:background="@color/biometric_error_color">
<FrameLayout
android:id="@+id/activityScreensContainer"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="40dp"
android:background="@color/colorPrimary"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintVertical_chainStyle="packed"
app:layout_constraintBottom_toTopOf="@+id/button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintVertical_chainStyle="packed"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintVertical_chainStyle="packed"
app:layout_constraintBottom_toTopOf="@+id/button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintVertical_chainStyle="packed"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView" />
</androidx.constraintlayout.widget.ConstraintLayout>