Android依赖注入– Dagger 2
在本教程中,我们将在android应用程序中讨论并实现依赖注入(DI)。
对于过去(可能在Spring)使用过DI的那些人,可以跳过以下部分来介绍Android Dependency Injection。
什么是Android依赖注入?
您不是自己创建对象,而是让别人为您创建对象。
让我们分析一下以上语句的含义。
想象以下情况:我们有一个Activity,并且希望将一些数据保存在SharedPreferences中。
在没有DI的情况下执行此操作将导致我们实例化,保存,从SharedPreferences中检索数据,所有这些都在Activity的样板代码内。
下图或者多或者少地描绘了某种东西。
没有DI
上面的方法可能会导致一些严重的问题,尤其是当您的代码库增大时。
您将遇到单元测试问题,太多样板代码,难以修改的当前代码库(有太多实例需要关注)(共享实例,作用域实例)。
其中Android Dependency Injection Pattern可以大大增强您的代码。
如依赖项中所述和下图所示,不是让每次在我们的Activity中实例化SharedPreferences,而是让它从另一个类中注入。
因此,我们的活动取决于SharedPreferences。
因此,SharedPreferences充当我们Activity的依赖项。
SharedPreferences从外部注入到我们的Activity中,而不是实例化。
为什么要使用Android依赖注入?
如果您是的老板,您希望自己做所有事情还是委派任务?
您是否愿意聘请新手,而不是已经知道任务的专家?
在理想情况下,以上两个问题的答案应该是后一种选择。
这就是依赖注入如此重要的原因。
与其每次在我们的活动中实例化SharedPreferences,数据库和网络库,我们都希望在其他地方创建它们的实例,并在需要时将它们注入到我们的活动中。
这些依赖关系通常在我们的类中使用构造函数,我们将很快看到。
什么是Dagger2?
Dagger库由Square的开发人员在2012年创建。
Dagger1用于创建类的实例并通过Reflections注入依赖项。
Dagger 2在第一个版本的基础上进行了改进,并与Google的开发人员团队合作,引入了一个更快,更完善的版本,而没有使用Reflections。
Dagger 2是一个编译时android依赖项注入框架,并使用Java Specification Request(JSR)330并使用注释处理器。
以下是Dagger 2中使用的基本注释:
@Module:此类用于构造最终将作为依赖项提供的对象的类。
@Provides:用于Module类中将返回对象的方法上。
@Inject:用于构造函数,字段或者方法,表示已请求依赖项。
@Component:Module类未直接向请求它的类提供依赖项。
为此,使用了一个Component接口,它充当@Module和@Inject之间的桥梁。@Singleton:这表明将仅创建依赖项对象的单个实例。
不用担心上面的东西会打扰您。
现在,我们将开发一个使用Dagger并提供SharedPreferences作为我们Activity中的依赖项的应用程序。
Android依赖注入示例项目
我们的应用程序将包含一个单一活动,其中我们将保存并从EditTexts中检索数据到SharedPreferences中。
首先,在build.gradle文件中添加以下依赖项。
compile 'com.google.dagger:dagger:2.10' annotationProcessor 'com.google.dagger:dagger-compiler:2.10'
让我们分析一下如何使用Dagger和上述注释在我们的应用程序中引入依赖注入的功能。
要在另一个类中实例化SharedPreferences实例,我们需要传递当前上下文。
组件完成将东西传递给Module类的工作,并将依赖项注入到我们的Activity中。
Android Dagger 2代码
首先让我们看一下" activity_main.xml"布局。
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:app="https://schemas.android.com/apk/res-auto"
xmlns:tools="https://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.theitroad.dagger2.MainActivity">
<EditText
android:id="@+id/inUsername"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:hint="Username"
<EditText
android:id="@+id/inNumber"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/inUsername"
android:layout_margin="8dp"
android:inputType="number"
android:hint="Number"
<Button
android:id="@+id/btnSave"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="SAVE"
android:layout_below="@+id/inNumber"
android:layout_toLeftOf="@+id/btnGet"
android:layout_toStartOf="@+id/btnGet"
android:layout_marginRight="8dp"
android:layout_marginEnd="8dp"
<Button
android:id="@+id/btnGet"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="GET"
android:layout_below="@+id/inNumber"
android:layout_alignRight="@+id/inNumber"
android:layout_alignEnd="@+id/inNumber"
</RelativeLayout>
下面给出了SharedPrefModule.java类的代码。
package com.theitroad.dagger2;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;
@Module
public class SharedPrefModule {
private Context context;
public SharedPrefModule(Context context) {
this.context = context;
}
@Singleton
@Provides
public Context provideContext() {
return context;
}
@Singleton
@Provides
public SharedPreferences provideSharedPreferences(Context context) {
return PreferenceManager.getDefaultSharedPreferences(context);
}
}
上下文是在构造函数中设置的。
返回依赖对象的方法通常以provider开头,因此命名为" provideSharedPreferences()"。
下面给出了MyComponent.java接口的代码。
package com.theitroad.dagger2;
import javax.inject.Singleton;
import dagger.Component;
@Singleton
@Component(modules = {SharedPrefModule.class})
public interface MyComponent {
void inject(MainActivity activity);
}
在@Component批注中提到了所有模块。
允许请求模块声明的依赖项的活动,服务或者片段(使用@Inject)应在此接口中使用单独的inject()方法进行声明。
下面给出了MainActivity.java类的代码:
package com.theitroad.dagger2;
import android.content.SharedPreferences;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import javax.inject.Inject;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
EditText inUsername, inNumber;
Button btnSave, btnGet;
private MyComponent myComponent;
@Inject
SharedPreferences sharedPreferences;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initViews();
myComponent = DaggerMyComponent.builder().sharedPrefModule(new SharedPrefModule(this)).build();
myComponent.inject(this);
}
private void initViews() {
btnGet = findViewById(R.id.btnGet);
btnSave = findViewById(R.id.btnSave);
inUsername = findViewById(R.id.inUsername);
inNumber = findViewById(R.id.inNumber);
btnSave.setOnClickListener(this);
btnGet.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btnGet:
inUsername.setText(sharedPreferences.getString("username", "default"));
inNumber.setText(sharedPreferences.getString("number", "12345"));
break;
case R.id.btnSave:
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString("username", inUsername.getText().toString().trim());
editor.putString("number", inNumber.getText().toString().trim());
editor.apply();
break;
}
}
}
将Dagger绑定到我们的应用程序中的代码是:
myComponent = DaggerMyComponent.builder().sharedPrefModule(new SharedPrefModule(this)).build();
" Dagger"关键字位于组件类名称的前面。
如果组件类名称为AppComponent,则结果为DaggerAppComponent。
将模块类名称转换为驼峰格式,并通过传递上下文在模块内部对其进行初始化(最终,SharedPreferences要求使用它进行初始化!)。
在此阶段,Dagger可以生成文件,因此您需要重建项目以使其能够执行其工作("构建">"重建项目")。
在此之后可以使用SharedPreferences依赖项对象:myComponent.inject(this)。
我们可以对SharedPreferences进行操作,而无需在Activity中对其进行初始化。
我们可以对Retrofit适配器等做同样的事情,以使我们的代码更简单,更易于使用/测试。
上述应用程序的输出如下:
代替@Singleton,我们也可以定义不同的范围,例如@ PerApp,@ PerActivity,以使实例创建的数量分别取决于Application/Activity的生存期。

