Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
12 changes: 7 additions & 5 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="ru.otus.daggerhomework">
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="otus.homework.dagger">

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

Expand Down
23 changes: 23 additions & 0 deletions app/src/main/java/otus/homework/dagger/App.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package otus.homework.dagger

import android.app.Application
import otus.homework.dagger.di.*
import otus.homework.dagger.di.AppModule

class App : Application() {

override fun onCreate() {
super.onCreate()
appComponent = DaggerAppComponent.builder().appModule(AppModule(this)).build()
activityComponent = DaggerActivityComponent.factory().create(appComponent)
fragmentReceverComponent = DaggerFragmentReceiverComponent.factory().create(activityComponent)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Зачем тебе эти компоненты на уровне апликейшена? это чревато утечками памяти, тк в этих комопнентах лежит ссылка на фрагменты. Создавай их прямо в активити/фрагментах

fragmentProducerComponent = DaggerFragmentProducerComponent.factory().create(activityComponent)
}

companion object {
lateinit var appComponent: AppComponent
lateinit var activityComponent: ActivityComponent
lateinit var fragmentReceverComponent: FragmentReceiverComponent
lateinit var fragmentProducerComponent: FragmentProducerComponent
}
}
7 changes: 7 additions & 0 deletions app/src/main/java/otus/homework/dagger/ColorFlow.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package otus.homework.dagger

import androidx.lifecycle.MutableLiveData

class ColorFlow {
var colorObserver = MutableLiveData<Int>()
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
package ru.otus.daggerhomework
package otus.homework.dagger

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

interface ColorGenerator {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,25 +1,32 @@
package ru.otus.daggerhomework
package otus.homework.dagger

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 androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.get
import javax.inject.Inject

class FragmentProducer : Fragment() {

@Inject lateinit var viewModel: ViewModelProducer

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

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

import android.os.Bundle
import android.view.LayoutInflater
Expand All @@ -7,16 +7,25 @@ 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() {

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


override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
App.activityComponent.injectInto(this)
viewModel.observer.colorObserver.observe(this) {
populateColor(it)
viewModel.observeColors()
}
return inflater.inflate(R.layout.fragment_b, container, true)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
package ru.otus.daggerhomework
package otus.homework.dagger

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

class MainActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
App.appComponent.injectInto(this)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Опять же, если у тебя компонент создается в Application и по смыслу и по названию относиться к Application, то его инжектить можно только в Application, если тебе нужны его сущности то выстраивай иерархию

Toast.makeText(App.appComponent.context, "context.toString()", Toast.LENGTH_LONG).show()
}
}
18 changes: 18 additions & 0 deletions app/src/main/java/otus/homework/dagger/MyViewModelFactory.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package otus.homework.dagger

import android.content.Context
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider

class MyViewModelFactory constructor(private val context: Context) : ViewModelProvider.Factory {

override fun <T : ViewModel> create(modelClass: Class<T>): T {
return if (modelClass.isAssignableFrom(ViewModelProducer::class.java)) {
ViewModelProducer(context = context, colorGenerator = ColorGeneratorImpl()) as T
} else if (modelClass.isAssignableFrom(ViewModelReceiver::class.java)) {
ViewModelReceiver(context) as T
} else {
throw IllegalArgumentException("ViewModel Not Found")
}
}
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
package ru.otus.daggerhomework
package otus.homework.dagger

import android.content.Context
import android.widget.Toast
import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.ViewModel
import java.lang.RuntimeException
import javax.inject.Inject

class ViewModelProducer(
private val colorGenerator: ColorGenerator,
private val context: Context
) {
) : ViewModel() {
@Inject
lateinit var observer: ColorFlow

fun generateColor() {
if (context !is FragmentActivity) throw RuntimeException("Здесь нужен контекст активити")
Toast.makeText(context, "Color sent", Toast.LENGTH_LONG).show()
observer.colorObserver.value = colorGenerator.generateColor()
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
package ru.otus.daggerhomework
package otus.homework.dagger

import android.app.Application
import android.content.Context
import android.widget.Toast
import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.ViewModel
import java.lang.RuntimeException
import javax.inject.Inject

class ViewModelReceiver(
private val context: Context
) {
) : ViewModel() {
@Inject
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

А почему здесь инжект в поле? Инжекти в конструктор и ВМ создавай через фабрику, это предпочтительный способ, к тому же я не совсем понял как у тебя вообще код компилируется если здесь нет мембер инжектора

lateinit var observer: ColorFlow

fun observeColors() {
if (context !is Application) throw RuntimeException("Здесь нужен контекст апликейшена")
Expand Down
34 changes: 34 additions & 0 deletions app/src/main/java/otus/homework/dagger/di/ActivityComponent.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package otus.homework.dagger.di

import android.content.Context
import dagger.Component
import dagger.Module
import dagger.Provides
import otus.homework.dagger.ColorFlow
import otus.homework.dagger.FragmentProducer
import otus.homework.dagger.FragmentReceiver
import javax.inject.Scope

@ActivityScope
@Component(dependencies = [AppComponent::class], modules = [ActivityModule::class])
interface ActivityComponent {
var context: Context

fun injectInto(producer: FragmentProducer)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Зачем эти методы? Если у тебя компонент на активити то писать мембер инжектор методы на фрагмент это бед практис. Если тебе во фрагменте нужна какая то сущность, которая предоставляется ActivityComponent и его модулями, то для этого как раз и используются сабкомпоненты app -> activity -> fragment

fun injectInto(receiver: FragmentReceiver)

@Component.Factory
interface Factory {
fun create(appComponent: AppComponent): ActivityComponent
}
}

@Module
class ActivityModule {
@get:Provides
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Этот модуль можно убрать. Добавь инжект аннотацию над ColorFlow

@ActivityScope
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Скоуп здесь не нужен

var observer = ColorFlow()
}

@Scope
annotation class ActivityScope
26 changes: 26 additions & 0 deletions app/src/main/java/otus/homework/dagger/di/ApplicationComponent.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package otus.homework.dagger.di

import android.content.Context
import dagger.Component
import dagger.Module
import dagger.Provides
import otus.homework.dagger.App
import otus.homework.dagger.MainActivity
import javax.inject.Singleton

@Singleton
@Component(modules = [AppModule::class])
interface AppComponent {
var context: Context

fun injectInto(activity: MainActivity)
}

@Module
internal class AppModule(var app: App) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Вместо конструктора модуля нужны использовать BindsInstance

@Singleton
@Provides
fun provideContext(): Context {
return app.applicationContext
}
}
59 changes: 59 additions & 0 deletions app/src/main/java/otus/homework/dagger/di/FragmentComponents.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package otus.homework.dagger.di

import android.content.Context
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.ViewModelStoreOwner
import dagger.Component
import dagger.Module
import dagger.Provides
import otus.homework.dagger.MyViewModelFactory
import otus.homework.dagger.ViewModelProducer
import otus.homework.dagger.ViewModelReceiver
import javax.inject.Scope

@FragmentScope
@Component(dependencies = [ActivityComponent::class], modules = [FragmentReceiverModule::class])
interface FragmentReceiverComponent {
var context: Context
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Зачем эта проперти? Выглядит как какая-то смесь между сабкомпонентами и компонент депенденсис. Если ты выбрал сабкомпоненты то эти провижен методы/проперти не нужны

var vmReceiver: ViewModelReceiver
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

И эта


@Component.Factory
interface Factory {
fun create(activityComponent: ActivityComponent): FragmentReceiverComponent
}
}

@Module
class FragmentReceiverModule(var context: Context) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Не используй конструктор модуля, это bad practice тк ты не можешь использовать статические Provides методы и модуль теперь содержит стейт.


@Provides
@FragmentScope
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

То же самое про скоуп

fun provideVMReceiver(owner: ViewModelStoreOwner) : ViewModelReceiver {
return ViewModelProvider(owner, MyViewModelFactory(context))[ViewModelReceiver::class.java]
}
}

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

var context: Context
var vmProducer: ViewModelProducer
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Аналогичные вопросы. Эти проперти не нужны


@Component.Factory
interface Factory {
fun create(activityComponent: ActivityComponent): FragmentProducerComponent
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

А зачем ему в аргументах ActivityComponent если у тебя FragmentProducerComponent должен быть сабкомпонентом у ActivityComponent? в ActivityComponent должен появится провижен метод который отдает FragmentProducerComponent.Factory

}
}
@Module
class FragmentProducerModule(var context: Context) {

@Provides
@FragmentScope
fun provideVMReceiver(owner: ViewModelStoreOwner) : ViewModelProducer {
return ViewModelProvider(owner, MyViewModelFactory(context))[ViewModelProducer::class.java]
}
}

@Scope
annotation class FragmentScope
6 changes: 0 additions & 6 deletions app/src/main/java/ru/otus/daggerhomework/App.kt

This file was deleted.

This file was deleted.

11 changes: 5 additions & 6 deletions app/src/main/res/drawable-v24/ic_launcher_foreground.xml
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportHeight="108"
android:viewportWidth="108"
android:width="108dp">
android:viewportHeight="108">
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
<aapt:attr name="android:fillColor">
<gradient
Expand All @@ -26,6 +25,6 @@
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
android:strokeColor="#00000000"
android:strokeWidth="1" />
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>
Loading