Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
### Реализуйте ApplicationComponent
Это корень нашего дерева компонентов. Инициализируется в классе App, прокидывает в граф через Component Dependencies/Subcomponents ниже по графу следующие сущности:
Это корень нашего дерева компонентов. Инициализируется в классе App, прокидывает
в граф через Component Dependencies/Subcomponents ниже по графу следующие сущности:
- Context(Application) до FragmentProducerComponent и FragmentReceiverComponent.
Проброс Context в граф реализуйте через BindsInstance + ComponentFactory

### Реализуйте MainActivityComponent
Инициализируется в MainActivity. Прокидывает следующие сущности:
- Context(Activity). Проброс в граф реализуйте через BindsInstance + ComponentFactory
- Ваша реализация обсервера(Coroutine Channel/StateFlow/Subject либо другую реализацию обсервера). Он понадобится нам чтобы отправлять евенты из одного фрагмента и принимать их в другом, в обоих фрагментах должен быть один и тот же инстанс обсервера.
- Ваша реализация обсервера(Coroutine Channel/StateFlow/Subject либо другую реализацию обсервера).
Он понадобится нам чтобы отправлять евенты из одного фрагмента и принимать их в другом, в обоих фрагментах должен быть один и тот же инстанс обсервера.

### Реализуйте FragmentReceiverComponent/FragmentProducerComponent
Коммуникацию между Producer и Receiver осуществите через канал/StateFlow/Subject либо другую реализацию обсервера которая уже есть в графе. ViewModelProducer должна отправлять эвенты, ViewModelReceiver должна получать эвенты. Обсерверы должны прокидываться в конструкторы вьюмоделей и существовать в единственном экземпляре в Activity.
Коммуникацию между Producer и Receiver осуществите через канал/StateFlow/Subject либо другую реализацию обсервера которая уже есть в графе.
ViewModelProducer должна отправлять эвенты, ViewModelReceiver должна получать эвенты.
Обсерверы должны прокидываться в конструкторы вьюмоделей и существовать в единственном экземпляре в Activity.
Флоу отправки эвента выглядит следующим образом:
Клик на кнопку button в FragmentProducer -> вызов метода вьюмодели -> проброс евента в обсервер -> евент ловится на стороне ViewModelReceiver -> евент передается FragmentReceiver и вызывается функция ru.otus.daggerhomework.FragmentReceiver#populateColor
Клик на кнопку button в FragmentProducer -> вызов метода вьюмодели -> проброс евента в обсервер ->
евент ловится на стороне ViewModelReceiver -> евент передается FragmentReceiver
и вызывается функция ru.otus.daggerhomework.FragmentReceiver#populateColor
9 changes: 9 additions & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,21 @@ android {
}
}

ext {
dagger_version = '2.38.1'
}

dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.core:core-ktx:1.6.0'
implementation 'androidx.appcompat:appcompat:1.3.1'
implementation 'com.google.android.material:material:1.4.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.0'

implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.1'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.0'
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'

implementation 'com.google.dagger:dagger:2.38.1'
kapt 'com.google.dagger:dagger-compiler:2.38.1'
}
1 change: 1 addition & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:name=".App"
android:theme="@style/Theme.DaggerHomework">
<activity android:name=".MainActivity">
<intent-filter>
Expand Down
15 changes: 14 additions & 1 deletion app/src/main/java/ru/otus/daggerhomework/App.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,18 @@ package ru.otus.daggerhomework

import android.app.Application

class App :Application() {
class App : Application() {

private var _appComponent: ApplicationComponent? = null

val appComponent: ApplicationComponent
get() = _appComponent ?: DaggerApplicationComponent
.factory()
.create(this)
.also { _appComponent = it }

override fun onCreate() {
super.onCreate()
appComponent
}
}
19 changes: 19 additions & 0 deletions app/src/main/java/ru/otus/daggerhomework/ApplicationComponent.kt
Original file line number Diff line number Diff line change
@@ -1,4 +1,23 @@
package ru.otus.daggerhomework

import android.content.Context
import dagger.BindsInstance
import dagger.Component
import javax.inject.Qualifier
import javax.inject.Singleton

@Qualifier
annotation class ApplicationContext

@Singleton
@Component
interface ApplicationComponent {

@ApplicationContext
fun provideAppContext(): Context

@Component.Factory
interface Factory {
fun create(@BindsInstance @ApplicationContext applicationContext: Context): ApplicationComponent
}
}
4 changes: 2 additions & 2 deletions app/src/main/java/ru/otus/daggerhomework/ColorGenerator.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@ package ru.otus.daggerhomework

import android.graphics.Color
import androidx.annotation.ColorInt
import androidx.annotation.ColorRes
import java.util.*
import javax.inject.Inject

interface ColorGenerator {

@ColorInt
fun generateColor(): Int
}

class ColorGeneratorImpl : ColorGenerator {
class ColorGeneratorImpl @Inject constructor() : ColorGenerator {

override fun generateColor(): Int {
val rnd = Random()
Expand Down
18 changes: 17 additions & 1 deletion app/src/main/java/ru/otus/daggerhomework/FragmentProducer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,37 @@ import android.view.View
import android.view.ViewGroup
import android.widget.Button
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import javax.inject.Inject

class FragmentProducer : Fragment() {

@Inject
lateinit var viewModelFactory: ViewModelFactory
lateinit var viewModel: ViewModelProducer

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
DaggerFragmentProducerComponent.builder()
.mainActivityComponent((requireActivity() as MainActivity).activityComponent)
.build()
.inject(this)
viewModel = ViewModelProvider(this, viewModelFactory)[ViewModelProducer::class.java]
}

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_a, container, true)
return inflater.inflate(R.layout.fragment_a, container, false)
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
view.findViewById<Button>(R.id.button).setOnClickListener {
//отправить результат через livedata в другой фрагмент
viewModel.generateColor()
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package ru.otus.daggerhomework

import dagger.Component
import javax.inject.Scope

@Scope
annotation class FragmentScope

@FragmentScope
@Component(dependencies = [MainActivityComponent::class], modules = [FragmentProducerModule::class])
interface FragmentProducerComponent {

fun inject(fragment: FragmentProducer)

}
18 changes: 18 additions & 0 deletions app/src/main/java/ru/otus/daggerhomework/FragmentProducerModule.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package ru.otus.daggerhomework

import androidx.lifecycle.ViewModel
import dagger.Binds
import dagger.Module
import dagger.multibindings.IntoMap

@Module
interface FragmentProducerModule {

@Binds
@IntoMap
@ViewModelKey(ViewModelProducer::class)
fun producerViewModel(viewModel: ViewModelProducer): ViewModel

@Binds
fun bindsColorGenerator(generator: ColorGeneratorImpl): ColorGenerator
}
20 changes: 17 additions & 3 deletions app/src/main/java/ru/otus/daggerhomework/FragmentReceiver.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,42 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import androidx.annotation.ColorInt
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import javax.inject.Inject

class FragmentReceiver : Fragment() {

@Inject
lateinit var viewModelFactory: ViewModelFactory
lateinit var viewModel: ViewModelReceiver
private lateinit var frame: View

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
DaggerFragmentReceiverComponent.builder()
.mainActivityComponent((requireActivity() as MainActivity).activityComponent)
.build()
.inject(this)
viewModel = ViewModelProvider(this, viewModelFactory)[ViewModelReceiver::class.java]
}

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_b, container, true)
return inflater.inflate(R.layout.fragment_b, container, false)
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
frame = view.findViewById(R.id.frame)
viewModel.observeColors { populateColor(it) }
}

fun populateColor(@ColorInt color: Int) {
private fun populateColor(@ColorInt color: Int) {
frame.setBackgroundColor(color)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package ru.otus.daggerhomework

import dagger.Component

@FragmentScope
@Component(dependencies = [MainActivityComponent::class], modules = [FragmentReceiverModule::class])
interface FragmentReceiverComponent {

fun inject(fragment: FragmentReceiver)

}
15 changes: 15 additions & 0 deletions app/src/main/java/ru/otus/daggerhomework/FragmentReceiverModule.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package ru.otus.daggerhomework

import androidx.lifecycle.ViewModel
import dagger.Binds
import dagger.Module
import dagger.multibindings.IntoMap

@Module
interface FragmentReceiverModule {

@Binds
@IntoMap
@ViewModelKey(ViewModelReceiver::class)
fun receiverViewModel(viewModel: ViewModelReceiver): ViewModel
}
19 changes: 18 additions & 1 deletion app/src/main/java/ru/otus/daggerhomework/MainActivity.kt
Original file line number Diff line number Diff line change
@@ -1,11 +1,28 @@
package ru.otus.daggerhomework

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {

private var _activityComponent: MainActivityComponent? = null

val activityComponent: MainActivityComponent
get() = _activityComponent ?: DaggerMainActivityComponent
.factory()
.create(this, (application as App).appComponent)
.also { _activityComponent = it }

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

activityComponent

supportFragmentManager
.beginTransaction()
.add(R.id.main_activity, FragmentReceiver())
.add(R.id.main_activity, FragmentProducer())
.commit()
}
}
30 changes: 30 additions & 0 deletions app/src/main/java/ru/otus/daggerhomework/MainActivityComponent.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package ru.otus.daggerhomework

import android.content.Context
import dagger.BindsInstance
import dagger.Component
import kotlinx.coroutines.flow.MutableStateFlow
import javax.inject.Scope

@Scope
annotation class ActivityScope

@ActivityScope
@Component(dependencies = [ApplicationComponent::class], modules = [MainActivityModule::class])
interface MainActivityComponent {

@ApplicationContext
fun provideAppContext(): Context

fun provideActivityContext(): Context

fun provideStateFlow(): MutableStateFlow<Int>

@Component.Factory
interface Factory {
fun create(
@BindsInstance activityContext: Context,
applicationComponent: ApplicationComponent
): MainActivityComponent
}
}
15 changes: 15 additions & 0 deletions app/src/main/java/ru/otus/daggerhomework/MainActivityModule.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package ru.otus.daggerhomework

import dagger.Module
import dagger.Provides
import kotlinx.coroutines.flow.MutableStateFlow

@Module
class MainActivityModule {

@ActivityScope
@Provides
fun stateObserver(): MutableStateFlow<Int> {
return MutableStateFlow(0)
}
}
23 changes: 23 additions & 0 deletions app/src/main/java/ru/otus/daggerhomework/ViewModelFactory.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package ru.otus.daggerhomework

import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import dagger.MapKey
import javax.inject.Inject
import javax.inject.Provider
import kotlin.reflect.KClass

@FragmentScope
class ViewModelFactory @Inject constructor(
private val viewModels: MutableMap<Class<out ViewModel>,
@JvmSuppressWildcards Provider<ViewModel>>
) : ViewModelProvider.Factory {

override fun <T : ViewModel> create(modelClass: Class<T>): T =
viewModels[modelClass]?.get() as T
}

@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER)
@kotlin.annotation.Retention(AnnotationRetention.RUNTIME)
@MapKey
internal annotation class ViewModelKey(val value: KClass<out ViewModel>)
Loading