Dagger2介绍
为什么我们需要注解依赖注入?
Dependency Injection(注解依赖)是在IOC(Inversion of cnontrol)的基础上实现的,一个类的依赖需要从外部进行获取。换句话说一个类不能直接实例化另一个类,需要从配置文件中获取实例化的类的对象。
如果一个类使用new操作符来实例化另外一个类,那么这两个类直接就产生依赖关系,被称为Hard dependency。
依赖注入的优点
- 增加类的可复用性,可以独立于其他类进行测试;
Dagger2
Dagger2使用注解的方式来构建依赖图,在工程构建的过程中,使用Javax inject包生成依赖,在程序运行之前就可以就可以对代码中的错误进行检测。
注入模式
- 构造函数注入:以传递参数的方式;
- 字段(Field)注入:以变量的方式,不可以注入private类型;
- 方法注入:以传递参数的方式;
“(dependency consumer)依赖调用者”通过一个“连接器”从“(dependency provider)依赖提供者”调用“依赖对象”
- Dependency provider:使用注解
@Module表示的类,用于提供可以进行注入的对象。类中的方法使用注解@Providers表示该方法的返回对象可以被依赖注入。@Moudle可将引用的类(非自己编码的类)的注入,如果是自己编码的类仅用@Inject即可 - Dependency consumer:注解
@Inject用于定义一个依赖。 - Connection consumer and producer:使用注解
@Component的接口定义module对象中provider与依赖对象之间的连接,接口的实现类由Dagger自动生成。
Dagger2的局限性
- Dagger2不能自动注入域
- Dagger2不能注入private类型
- Dagger2如果需要注入field,需要在使用
@Component注解的接口中,定义一个提供变量的方法。
注入结构图
在Android开发中通用的注入方式形成的依赖结构如下图所示:
当AppComponent通过其modules构建完成后,我们就在结构图中有了所有我们需要的实例了。如果我们需要将Activity连接到Dagger的依赖结构图中,构建一个使用@Subcomponent注解的Component即可。
在使用上述方法进行构建时,我们需要向不断向AppModule中添加subComponent,而且子component中相似的代码较多,Dagger2中提供@ContributesAndroidInjector注解来解决这一问题,依赖结构图如下图所示:
代码实现
我们采用第二种结构进行代码的实现
最简方式,向Fragment和Activity中注入UserDao对数据库进行操作。
项目结构
数据库实现
//User
@Entity
public class User {
@PrimaryKey(autoGenerate = true)
@ColumnInfo
private int id;
@ColumnInfo
private String name="";
//省略Getter和Setter
}
//UserDao
@Dao
public abstract class UserDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
public abstract void insert(User user);
@Query("select * from user")
public abstract List<User> getUsers();
}
//UserDb
@Database(entities = {User.class}, version = 1,exportSchema = false)
public abstract class UserDb extends RoomDatabase {
public abstract UserDao userDao();
}
测试用的Bean类
public class Bean {
public Bean(){
}
public void printInfo(){
Log.i("++",this.toString());
}
}
AppMoudle实现
AppMoudle中用于提供一些全局的单例,如:Retrofit、OkHttp、Room等。
@Module
public class AppModule {
@Provides
@Singleton
public Context provideContext(Application application) {
return application;
}
//用于注入DB单例
//这里只能用Application 而非AppApplication,用user_db而非user.db
@Singleton
@Provides
public UserDb provideDb(Application application) {
return Room.databaseBuilder(application, UserDb.class, "user.db").build();
}
//用于注入UserDao
@Singleton
@Provides
public UserDao provideUserDao(UserDb userDb){
return userDb.userDao();
}
}
MainActivityModule实现
在MainActivityModule提供一些需要在MainActivity中进行注入的实例。
@Module
public class MainActivityModule {
@Provides
Bean provide(){
return new Bean();
}
}
FragmentBuildersModule实现
@Module
public abstract class FragmentBuildersModule {
@ContributesAndroidInjector
abstract MainFragment contributeDetailFragment();
}
AppComponent实现
AppComponent使用注解@Component,程序在编译的工程中通过AppComponent形成依赖注入关系图,Component使用modules提供注入的实例。
@Component.Builder在构建的过程中,有时需要向关系图中绑定一些实例,在本项目中绑定的是Application。
注:如果需要在Component中提供Builder,Builder接口中需要添加一个builder()方法,该方法返回Component
@Singleton
@Component(modules = {AndroidInjectionModule.class, AppModule.class, ActivityBuildersModule.class})
public interface AppComponent {
@Component.Builder
interface Builder {
@BindsInstance
Builder application(Application application);
AppComponent build();
}
void inject(AppApplication application);
}
AppApplication实现
.application(this)方法将application实例绑定职Dagger的依赖图标中。Application需要实现HasActivityInjector接口,有Activity需要注入。如果Activity中有Fragment,则Activity中需要实现HasSupportFragmentInjector接口,
public class AppApplication extends Application implements HasActivityInjector {
@Inject
DispatchingAndroidInjector<Activity> activityDispatchingAndroidInjector;
@Override
public void onCreate() {
super.onCreate();
DaggerAppComponent
.builder()
.application(this)
.build()
.inject(this);
}
@Override
public DispatchingAndroidInjector<Activity> activityInjector() {
return activityDispatchingAndroidInjector;
}
}
MainActivity中实现
在Activity中以及Fragment中都需要将依赖进行注入, AndroidInjection.inject(this); AndroidSupportInjection.inject(this);
public class MainActivity extends AppCompatActivity implements HasSupportFragmentInjector {
@Inject
DispatchingAndroidInjector<Fragment> dispatchingAndroidInjector;
@Inject
MainFragment mainFragment;
@Inject
Context context;
@Inject
Bean bean;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AndroidInjection.inject(this);
setContentView(R.layout.activity_main);
getSupportFragmentManager().beginTransaction().replace(R.id.container, mainFragment).commitAllowingStateLoss();
}
@Override
public AndroidInjector<Fragment> supportFragmentInjector() {
bean.printInfo();
return dispatchingAndroidInjector;
}
}
MainFragment实现
public class MainFragment extends Fragment {
@Inject
UserDao userDao;
//用于获取DetailFragment实例
FragmentDetailBinding fragmentDetailBinding;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
AndroidSupportInjection.inject(this);
fragmentDetailBinding = DataBindingUtil
.inflate(inflater, R.layout.fragment_detail, container, false);
fragmentDetailBinding.insertDateTv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread(new Runnable() {
@Override
public void run() {
User user = new User("++++");
userDao.insert(user);
Log.i("User插入", "+++");
}
}).start();
}
});
fragmentDetailBinding.readDataTv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread(new Runnable() {
@Override
public void run() {
Log.i("User数量:", userDao.getUsers().size() + "");
}
}).start();
}
});
return fragmentDetailBinding.getRoot();
}
}