Skip to content
This repository has been archived by the owner on Feb 20, 2024. It is now read-only.

Add support Activity/Fragment/ViewModel on feature module injection #5

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
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
24 changes: 14 additions & 10 deletions app/build.gradle
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
apply plugin: 'com.android.application'

apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'

android {
compileSdkVersion 28
defaultConfig {
Expand Down Expand Up @@ -51,18 +51,22 @@ dependencies {
api "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"

api 'androidx.appcompat:appcompat:1.0.2'
implementation 'androidx.core:core-ktx:1.0.1'
api 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.core:core-ktx:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'

implementation "com.google.android.play:core:1.4.1"
api 'com.google.android.play:core:1.3.5'
api "androidx.lifecycle:lifecycle-extensions:2.1.0"

daggerApi 'com.google.dagger:dagger:2.16'
api 'com.google.dagger:dagger-android-support:2.16'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.2.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'

kapt 'com.google.dagger:dagger-compiler:2.16'
api 'com.jakewharton.timber:timber:4.7.1'

implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0-alpha04'
androidTestImplementation 'androidx.test:rules:1.2.0-alpha04'
api 'com.google.dagger:dagger:2.23.2'
kapt 'com.google.dagger:dagger-compiler:2.23.2'
api 'com.google.dagger:dagger-android:2.23.2'
api 'com.google.dagger:dagger-android-support:2.23.2'
kapt 'com.google.dagger:dagger-android-processor:2.23.2'
}
Empty file.
18 changes: 14 additions & 4 deletions app/src/dagger/java/com/google/android/samples/dynamiccodeloading/MyApplication.kt
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,26 @@
*/
package com.google.android.samples.dynamiccodeloading

import androidx.annotation.MainThread
import com.google.android.play.core.splitcompat.SplitCompatApplication
import com.google.android.play.core.splitcompat.SplitCompat
import com.google.android.samples.dynamiccodeloading.di.BaseComponent
import com.google.android.samples.dynamiccodeloading.di.DaggerBaseComponent
import dagger.android.AndroidInjector
import dagger.android.DaggerApplication

class MyApplication : DaggerApplication() {
override fun applicationInjector(): AndroidInjector<out DaggerApplication> {
return baseComponent
}

override fun onCreate() {
super.onCreate()
SplitCompat.install(this)
baseComponent.inject(this)
}

class MyApplication : SplitCompatApplication() {
val baseComponent: BaseComponent by lazy {
DaggerBaseComponent.builder()
.application(this)
.logger(MainLogger)
.build()
}
}
16 changes: 9 additions & 7 deletions app/src/dagger/java/com/google/android/samples/dynamiccodeloading/di/BaseDagger.kt
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -19,28 +19,26 @@ package com.google.android.samples.dynamiccodeloading.di
import android.app.Application
import android.content.Context
import android.util.Log
import com.google.android.samples.dynamiccodeloading.Logger
import com.google.android.samples.dynamiccodeloading.StorageFeature
import com.google.android.samples.dynamiccodeloading.TAG
import com.google.android.samples.dynamiccodeloading.*
import dagger.BindsInstance
import dagger.Component
import dagger.Module
import dagger.Provides
import dagger.android.AndroidInjectionModule
import dagger.android.AndroidInjector

const val PROVIDER_CLASS = "com.google.android.samples.storage.StorageFeatureImpl\$Provider"

@Component(modules = [BaseModule::class])
interface BaseComponent : StorageFeature.Dependencies {
@Component(modules = [AndroidInjectionModule::class, BaseModule::class, BaseViewModelModule::class])
interface BaseComponent : StorageFeature.Dependencies, AndroidInjector<MyApplication> {

fun storageFeature(): StorageFeature?

@Component.Builder
interface Builder {
@BindsInstance fun application(application: Application): Builder
@BindsInstance fun logger(logger: Logger): Builder
fun build(): BaseComponent
}

}

@Module
Expand Down Expand Up @@ -72,4 +70,8 @@ object BaseModule {
@Provides
@JvmStatic
fun appContextProvider(application: Application): Context = application

@Provides
@JvmStatic
fun loggerProvider(): Logger = MainLogger
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.google.android.samples.dynamiccodeloading.di

import androidx.lifecycle.ViewModelProvider
import dagger.Binds
import dagger.Module

@Module
abstract class BaseViewModelModule {
@Binds
abstract fun bindViewModelFactory(factory: ViewModelFactory): ViewModelProvider.Factory
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.google.android.samples.dynamiccodeloading.di

import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import javax.inject.Inject
import javax.inject.Provider

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

override fun <T : ViewModel> create(modelClass: Class<T>): T {
var creator = creators[modelClass]
if (creator == null) {
for ((key, value) in creators) {
if (modelClass.isAssignableFrom(key)) {
creator = value
break
}
}
}
if (creator == null) {
throw IllegalAccessException("unknown model class $modelClass")
}

@Suppress("UNCHECKED_CAST")
return creator.get() as T
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.google.android.samples.dynamiccodeloading.di.annotation

import androidx.lifecycle.ViewModel
import dagger.MapKey
import kotlin.reflect.KClass

@MustBeDocumented
@Target(
AnnotationTarget.FUNCTION,
AnnotationTarget.PROPERTY_GETTER,
AnnotationTarget.PROPERTY_SETTER
)
@Retention(AnnotationRetention.RUNTIME)
@MapKey
annotation class ViewModelKey(val value: KClass<out ViewModel>)
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,16 @@
*/
package com.google.android.samples.dynamiccodeloading

import android.content.Intent
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import android.widget.Button
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders
import java.lang.Exception

/**
* The single, main activity of this sample.
Expand All @@ -39,6 +43,25 @@ class MainActivity : AppCompatActivity() {

private lateinit var viewModel: MainViewModel

override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.menu_main, menu)
return super.onCreateOptionsMenu(menu)
}

override fun onOptionsItemSelected(item: MenuItem?): Boolean {
when (item?.itemId) {
R.id.storage_activity -> {
try {
val intent = Intent(this, Class.forName("com.google.android.samples.storage.StorageActivity"))
startActivity(intent)
} catch (exception: Exception) {
exception.printStackTrace()
}
}
}
return super.onOptionsItemSelected(item)
}

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
Expand Down
9 changes: 9 additions & 0 deletions app/src/main/res/menu/menu_main.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">

<item
android:id="@+id/storage_activity"
app:showAsAction="always"
android:title="Storage Activity" />
</menu>
13 changes: 11 additions & 2 deletions storage/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,15 @@ android {

dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'

implementation project(':app')
kapt 'com.google.dagger:dagger-compiler:2.16'
}
kapt 'com.android.tools.build.jetifier:jetifier-core:1.0.0-beta07'
annotationProcessor 'com.android.tools.build.jetifier:jetifier-core:1.0.0-beta07'

kapt 'com.google.dagger:dagger-compiler:2.23.2'
kapt 'com.google.dagger:dagger-android-processor:2.23.2'

implementation 'androidx.appcompat:appcompat:1.1.0'
implementation "androidx.lifecycle:lifecycle-extensions:2.1.0"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.google.android.samples.storage

import androidx.lifecycle.ViewModel
import com.google.android.samples.dynamiccodeloading.di.BaseViewModelModule
import com.google.android.samples.dynamiccodeloading.di.annotation.ViewModelKey
import dagger.Binds
import dagger.Module
import dagger.android.ContributesAndroidInjector
import dagger.multibindings.IntoMap

@Module(includes = [BaseViewModelModule::class])
abstract class ActivityModule {
@ContributesAndroidInjector(modules = [ActivityViewModelModule::class])
abstract fun contributeStorageActivity(): StorageActivity

@Module
abstract class ActivityViewModelModule {
@Binds
@IntoMap
@ViewModelKey(StorageViewModel::class)
abstract fun bindStorageViewModel(viewModel: StorageViewModel): ViewModel
}
}
13 changes: 12 additions & 1 deletion storage/src/dagger/java/com/google/android/samples/storage/StorageFeatureImpl.kt
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package com.google.android.samples.storage

import android.content.SharedPreferences
import com.google.android.samples.dynamiccodeloading.Logger
import com.google.android.samples.dynamiccodeloading.MyApplication
import com.google.android.samples.dynamiccodeloading.StorageFeature
import com.google.android.samples.storage.di.DaggerStorageComponent
import javax.inject.Inject
Expand Down Expand Up @@ -47,7 +48,17 @@ class StorageFeatureImpl @Inject constructor(
*/
companion object Provider : StorageFeature.Provider {
override fun get(dependencies: StorageFeature.Dependencies): StorageFeature {
return DaggerStorageComponent.builder().dependencies(dependencies).build().storageFeature()
val component = DaggerStorageComponent.builder()
.dependencies(dependencies)
.build()

when (dependencies.getContext()) {
is MyApplication -> {
component.inject(dependencies.getContext() as MyApplication)
}
}

return component.storageFeature()
}
}
}
9 changes: 7 additions & 2 deletions storage/src/dagger/java/com/google/android/samples/storage/di/StorageDagger.kt
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,24 @@ package com.google.android.samples.storage.di

import android.content.Context
import android.preference.PreferenceManager
import com.google.android.samples.dynamiccodeloading.MyApplication
import com.google.android.samples.dynamiccodeloading.StorageFeature
import com.google.android.samples.dynamiccodeloading.di.BaseViewModelModule
import com.google.android.samples.storage.ActivityModule
import com.google.android.samples.storage.StorageFeatureImpl
import dagger.Component
import dagger.Module
import dagger.Provides
import dagger.android.AndroidInjectionModule
import dagger.android.AndroidInjector
import javax.inject.Singleton

@Singleton
@Component(
modules = [StorageModule::class],
modules = [AndroidInjectionModule::class, StorageModule::class, BaseViewModelModule::class, ActivityModule::class],
dependencies = [StorageFeature.Dependencies::class] // needs dependencies passed in to create component
)
interface StorageComponent {
interface StorageComponent : AndroidInjector<MyApplication> {
fun storageFeature(): StorageFeature
}

Expand Down
3 changes: 3 additions & 0 deletions storage/src/main/AndroidManifest.xml
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,8 @@
dist:title="@string/title_storage">
<dist:fusing dist:include="true"/>
</dist:module>
<application>
<activity android:name=".StorageActivity" />
</application>
</manifest>

Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.google.android.samples.storage

import android.os.Bundle
import android.widget.TextView
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.ViewModelProviders
import dagger.android.support.DaggerAppCompatActivity
import javax.inject.Inject

class StorageActivity : DaggerAppCompatActivity() {

@Inject
lateinit var viewModelFactory: ViewModelProvider.Factory

private val viewModel by lazy {
ViewModelProviders.of(this, viewModelFactory).get(StorageViewModel::class.java)
}

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

viewModel.counter.observe(this, Observer {
findViewById<TextView>(R.id.counter).text = "$it"
})
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.google.android.samples.storage

import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import com.google.android.samples.dynamiccodeloading.StorageFeature
import javax.inject.Inject

class StorageViewModel @Inject constructor(
private val storageFeature: StorageFeature
) : ViewModel() {
val counter = MutableLiveData<Int>(storageFeature.loadCounter())
}
Loading