introduce
It's just a personal study note. If there's something wrong, please leave a message
Learn some basic knowledge first
@Binds
Declare that Person is provided by Student
public class Person {
@Inject Person(){}
}
// Student
public class Student extends Person {
@Inject Student(){}
}
@Module
public abstract class MainModule {
@Binds
public abstract Person bindMainTarger(Student student);
}
@IntoSet @IntoMap @IntoXXXX
The article here is very detailed, so I won't rewrite it any more
https://blog.csdn.net/io_field/article/details/71170727
Let's first introduce how to design MVVM when it is not dagger2
If you don't know how to use databinding, the following video is recommended
Android Data Binding practice - Beginner Level
https://www.imooc.com/learn/719
Android Data Binding practice - Advanced
https://www.imooc.com/learn/720
Let's put it simply
override fun onCreate(savedInstanceState: Bundle?) {
val binding = DataBindingUtil.setContentView<ActivityMainBinding>(this,R.layout.activity_main)
binding.vm = ViewModelProviders.of(this, viewModelFactory).get(MainViewModel::class.java)
binding.vm.start()
}
But in most cases, we customize ViewModelProvider.Factory, and then create
To build viewmodels with different parameters
Custom Factory
public class ViewModelFactory extends ViewModelProvider.NewInstanceFactory {
private ViewModelFactory(Application application, TasksRepository repository) {
mApplication = application;
mTasksRepository = repository;
}
@Override
public <T extends ViewModel> T create(Class<T> modelClass) {
if (modelClass.isAssignableFrom(MainViewModel.class)) {
//noinspection unchecked
return (T) new MainViewModel(mApplication, mTasksRepository);
}
throw new IllegalArgumentException("Unknown ViewModel class: " + modelClass.getName());
}
}
The above part has made it clear that there are some complicated problems in building dagger2, and the following is the introduction of dagger2. You will see why so many people like dagger2
dagger2 actual MVVM
Refer to Google:
https://github.com/googlesamples
ViewModel related
// dagger2 custom key
@MustBeDocumented
@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
@MapKey
internal annotation class ViewModelKey(val value: KClass<out ViewModel>)
ViewModelFactory
class ViewModelFactory @Inject constructor(
private val creators: Map<Class<out ViewModel>, @JvmSuppressWildcards Provider<ViewModel>>)
: ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>): T {
var creator: Provider<ViewModel>? = creators[modelClass]
if (creator == null) {
for ((key, value) in creators) {
if (modelClass.isAssignableFrom(key)) {
creator = value
break
}
}
}
if (creator == null) throw IllegalArgumentException("unknown model class " + modelClass)
try {
return creator.get() as T
} catch (e: Exception) {
throw RuntimeException(e)
}
}
}
ViewModel
class WelcomeViewModel @Inject constructor(application: Application) : AndroidViewModel(application) {
// Self defined function
fun start(){
// ...
}
}
scope statement
@Scope
@Retention(RUNTIME)
annotation class ActivityScope
@Scope
@Retention(RetentionPolicy.RUNTIME)
annotation class FragmentScope
module
Overall situation
@Module
internal object AppModule {
@Singleton
@Provides
@JvmStatic
fun getHttpService(): IOfficialApi {
# Here is my custom library. You can change it to normal retrofit
return RetrofitClient.Builder(
IOfficialApi::class.java,
true,
IConstantPool.sCommonUrl,
headers = { HashMap() }
).create()
}
}
Corresponding activity
@Module
internal abstract class WelcomeViewModelModule
@Binds
@IntoMap
@ViewModelKey(WelcomeViewModel::class)
abstract fun bindMainViewModel(viewModel: WelcomeViewModel): ViewModel
}
AllActivitiesModule
@Module
internal abstract class AllActivitiesModule {
@Binds
abstract fun bindViewModelFactory(factory: ViewModelFactory): ViewModelProvider.Factory
@ActivityScope
@ContributesAndroidInjector(modules = [WelcomeViewModelModule::class])
abstract fun contributeWelcomeActivitytInjector(): WelcomeActivity
}
Let's talk about it alone
Contributesaandroidinjector actually simplifies the following code
Let's look at the compiled kapt file
public abstract class AllActivitiesModule_ContributeWelcomeActivitytInjector {
private AllActivitiesModule_ContributeWelcomeActivitytInjector() {}
@Binds
@IntoMap
@ActivityKey(WelcomeActivity.class)
abstract AndroidInjector.Factory<? extends Activity> bindAndroidInjectorFactory(
WelcomeActivitySubcomponent.Builder builder);
@Subcomponent(modules = WelcomeViewModelModule.class)
@ActivityScope
public interface WelcomeActivitySubcomponent extends AndroidInjector<WelcomeActivity> {
@Subcomponent.Builder
abstract class Builder extends AndroidInjector.Builder<WelcomeActivity> {}
}
}
component
@Singleton
@Component(
modules = [
AndroidInjectionModule::class,
AndroidSupportInjectionModule::class,
// Globalmodule
AppModule::class,
// each activity Corresponding design
AllActivitiesModule::class
]
)
interface AppComponent {
@Component.Builder
interface Builder {
@BindsInstance
fun application(application: Application): Builder
fun build(): AppComponent
}
fun inject(app: App)
}
Use
Please build the code above first
App
public class App extends Application implements HasActivityInjector {
@Inject
DispatchingAndroidInjector<Activity> dispatchingAndroidInjector;
@Override
public void onCreate() {
super.onCreate();
DaggerAppComponent.builder()
.application(this)
.build()
.inject(this);
// ARouter
ARouter.init(this);
}
@Override
public AndroidInjector<Activity> activityInjector() {
return dispatchingAndroidInjector;
}
}
BaseActivity
abstract class BaseActivity<in T : ViewDataBinding, vm : ViewModel>(
// custom layout
private val layoutResID: Int)
:AppCompatActivity(){
// mvvm
private lateinit var binding: T
@Inject
lateinit var viewModelFactory: ViewModelProvider.Factory
override fun onCreate(savedInstanceState: Bundle?) {
// injection
AndroidInjection.inject(this)
// create
super.onCreate(savedInstanceState)
// Initializing Binding
binding = DataBindingUtil.setContentView(this, layoutResID)
// binding
val vm = ViewModelProviders.of(this, viewModelFactory).get(getViewModelClass())
// DataBinding
init(binding, vm)
}
/** MVVM */
abstract fun getViewModelClass(): Class<vm>
abstract fun init(binding: T, vm: vm)
}
WelcomeActivity
class WelcomeActivity : BaseActivity<ActivityWelcomeBinding,WelcomeViewModel>(
R.layout.activity_welcome
) {
override fun getViewModelClass() = WelcomeViewModel::class.java
override fun init(binding: ActivityWelcomeBinding, vm: WelcomeViewModel) {
binding.viewModel = vm
vm.start()
}
}
Is dagger2 very easy to use? It's comfortable~~