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
10 changes: 7 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,13 @@
### Реализуйте 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
4 changes: 4 additions & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ android {
kotlinOptions {
jvmTarget = '1.8'
}
namespace 'ru.otus.daggerhomework'
}

dependencies {
Expand All @@ -40,4 +41,7 @@ dependencies {
implementation 'androidx.constraintlayout:constraintlayout:2.1.0'
implementation 'com.google.dagger:dagger:2.42'
kapt 'com.google.dagger:dagger-compiler:2.42'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.3'
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.5.0'
}
6 changes: 3 additions & 3 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="ru.otus.daggerhomework">
xmlns:android="http://schemas.android.com/apk/res/android">

<application
android:allowBackup="true"
android:name=".App"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.DaggerHomework">
<activity android:name=".MainActivity">
<activity android:name=".MainActivity" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

Expand Down
4 changes: 4 additions & 0 deletions app/src/main/java/ru/otus/daggerhomework/App.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,8 @@ package ru.otus.daggerhomework
import android.app.Application

class App :Application() {

val component by lazy {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Убрать либо заменить на несинхронизированный

DaggerApplicationComponent.factory().create(applicationContext)
}
}
7 changes: 7 additions & 0 deletions app/src/main/java/ru/otus/daggerhomework/AppScope.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package ru.otus.daggerhomework

import javax.inject.Scope

@Scope
@Retention(AnnotationRetention.RUNTIME)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Можно убрать

annotation class AppScope()
27 changes: 27 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,31 @@
package ru.otus.daggerhomework

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

@AppScope
@Component(modules = [ViewModelModule::class])
interface ApplicationComponent {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Нужно добавить ActivityComponent


fun inject(activity: MainActivity)


fun provideMyViewModel(): MyViewModel


fun provideColorGenerator(): ColorGenerator


fun provideContext(): Context

@Component.Factory
interface AppComponentFactory {

fun create(
@BindsInstance context: Context
): ApplicationComponent
}
}
5 changes: 3 additions & 2 deletions app/src/main/java/ru/otus/daggerhomework/ColorGenerator.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@ import android.graphics.Color
import androidx.annotation.ColorInt
import androidx.annotation.ColorRes
import java.util.*
import javax.inject.Inject

interface ColorGenerator {
interface ColorGenerator{

@ColorInt
fun generateColor(): Int
}

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

override fun generateColor(): Int {
val rnd = Random()
Expand Down
15 changes: 14 additions & 1 deletion app/src/main/java/ru/otus/daggerhomework/FragmentProducer.kt
Original file line number Diff line number Diff line change
@@ -1,14 +1,27 @@
package ru.otus.daggerhomework

import android.content.Context
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import androidx.fragment.app.Fragment
import javax.inject.Inject

class FragmentProducer : Fragment() {

private val subcomponent by lazy {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Удалить

FragmentProducerComponent.getFragmentProducerComponent((requireContext() as App).component)
}

@Inject
lateinit var viewModelProducer: ViewModelProducer

override fun onAttach(context: Context) {
super.onAttach(context)
subcomponent.inject(this)
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
Expand All @@ -20,7 +33,7 @@ class FragmentProducer : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
view.findViewById<Button>(R.id.button).setOnClickListener {
//отправить результат через livedata в другой фрагмент
viewModelProducer.generateColor()
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package ru.otus.daggerhomework

import android.content.Context
import dagger.BindsInstance
import dagger.Component
import dagger.Subcomponent

@MyScope
@Component(dependencies = [ApplicationComponent::class])
interface FragmentProducerComponent {

fun inject(fragment: FragmentProducer)

companion object{
fun getFragmentProducerComponent(applicationComponent: ApplicationComponent): FragmentProducerComponent {
return DaggerFragmentProducerComponent.builder().applicationComponent(applicationComponent).build()
}
}
}
17 changes: 17 additions & 0 deletions app/src/main/java/ru/otus/daggerhomework/FragmentReceiver.kt
Original file line number Diff line number Diff line change
@@ -1,17 +1,31 @@
package ru.otus.daggerhomework

import android.content.Context
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 javax.inject.Inject

class FragmentReceiver : Fragment() {

private lateinit var frame: View

private val subcomponent by lazy {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Нужно убрать

FragmentReceiverComponent.getFragmentReceiverComponent((requireContext() as App).component)
}

@Inject
lateinit var мiewModelReceiver: ViewModelReceiver

override fun onAttach(context: Context) {
super.onAttach(context)
subcomponent.inject(this)
}

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
Expand All @@ -23,6 +37,9 @@ class FragmentReceiver : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
frame = view.findViewById(R.id.frame)
мiewModelReceiver.colorLiveData.observe(viewLifecycleOwner){
populateColor(it)
}
}

fun populateColor(@ColorInt color: Int) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package ru.otus.daggerhomework


import dagger.Component

@MyScope
@Component(dependencies = [ApplicationComponent::class])
interface FragmentReceiverComponent {

fun inject(fragment: FragmentReceiver)

companion object{
fun getFragmentReceiverComponent(applicationComponent: ApplicationComponent): FragmentReceiverComponent {
return DaggerFragmentReceiverComponent.builder().applicationComponent(applicationComponent).build()
}
}
}
14 changes: 14 additions & 0 deletions app/src/main/java/ru/otus/daggerhomework/MainActivity.kt
Original file line number Diff line number Diff line change
@@ -1,12 +1,26 @@
package ru.otus.daggerhomework

import android.annotation.SuppressLint
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.FrameLayout
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import javax.inject.Inject

class MainActivity : AppCompatActivity() {

private val component by lazy {
(application as App).component
}

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

component.inject(this)

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

import javax.inject.Scope

@Scope
@Retention(AnnotationRetention.RUNTIME)
annotation class MyScope()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Лучше переименовать

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

import androidx.lifecycle.*
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.launch
import javax.inject.Inject
import javax.inject.Singleton

class MyViewModel @Inject constructor() : ViewModel() {

private val _catsStateFlow = MutableStateFlow<Int>(-1)
val catsStateFlow: StateFlow<Int> = _catsStateFlow

fun sendEvent(color: Int){
viewModelScope.launch(){
_catsStateFlow.value = color
}
}
}

class MyViewModelFactory @Inject constructor() :
ViewModelProvider.NewInstanceFactory() {
override fun <T : ViewModel> create(modelClass: Class<T>): T =
MyViewModel() as T
}
20 changes: 20 additions & 0 deletions app/src/main/java/ru/otus/daggerhomework/ViewModelModule.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package ru.otus.daggerhomework

import androidx.lifecycle.ViewModel
import dagger.Binds
import dagger.Module
import javax.inject.Singleton

@Module
interface ViewModelModule {


@AppScope
@Binds
fun bindMyViewModel(impl: MyViewModel): ViewModel


@Binds
fun bindColorGenerator(impl: ColorGeneratorImpl): ColorGenerator

}
9 changes: 7 additions & 2 deletions app/src/main/java/ru/otus/daggerhomework/ViewModelProducer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,19 @@ package ru.otus.daggerhomework
import android.content.Context
import android.widget.Toast
import androidx.fragment.app.FragmentActivity
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.flow
import javax.inject.Inject

class ViewModelProducer(
class ViewModelProducer @Inject constructor(
private val colorGenerator: ColorGenerator,
private val context: Context
private val context: Context,
private val myViewModel: MyViewModel
) {

fun generateColor() {
if (context !is FragmentActivity) throw RuntimeException("Здесь нужен контекст активити")
Toast.makeText(context, "Color sent", Toast.LENGTH_LONG).show()
myViewModel.sendEvent(colorGenerator.generateColor())
}
}
17 changes: 14 additions & 3 deletions app/src/main/java/ru/otus/daggerhomework/ViewModelReceiver.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,24 @@ package ru.otus.daggerhomework
import android.app.Application
import android.content.Context
import android.widget.Toast
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import kotlinx.coroutines.flow.collectLatest
import javax.inject.Inject

class ViewModelReceiver(
private val context: Context
class ViewModelReceiver @Inject constructor(
private val context: Context,
private val myViewModel: MyViewModel
) {

fun observeColors() {
private val _colorLiveData = MutableLiveData<Int>()
var colorLiveData:LiveData<Int> = _colorLiveData

suspend fun observeColors() {
if (context !is Application) throw RuntimeException("Здесь нужен контекст апликейшена")
Toast.makeText(context, "Color received", Toast.LENGTH_LONG).show()
myViewModel.catsStateFlow.collectLatest {
_colorLiveData.value = it
}
}
}
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ buildscript {
google()
}
dependencies {
classpath "com.android.tools.build:gradle:7.0.4"
classpath 'com.android.tools.build:gradle:8.1.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
Expand Down
Loading