在Android中使用Dagger2-Part3

770 阅读2分钟

如果没有阅读Part1和Part2请先阅读

在Android中使用Dagger2-Part1

在Android中使用Dagger2-Part2

注入带构造函数的ViewModel

在初始化一个带参数的ViewModel,需要使用ViewModelProvider.Factory的实例进行初始化,如果将一个ViewModelFactory用在不同的ViewModel上,ViewModelFactory需要对各种不同的参数进行处理。

在本项目中使用线程池对插入和读取数据的线程进行管理;使用UserRepo对User的插入和读取进行管理。

在Dagger2中有 Multibindings为对象创建一个Map:

  • Key:表示ViewModel的类型,在本项目中表示为MainFragmentViewModel::class
  • Vaule:表示ViewModel的实例

Dagger2在编译的时候会创建Map,我们将该Map以参数的形式传入到ViewModelFactory中,当我们调用create()方法时,将会从map中取出正确的实例。

AppExecutors创建

使用Javax包中@Singleton注解,表示其为单例模式;对于自定义类直接在构造函数AppExecutors()上添加注解@Inject,可以直接进行注入,无需在Module中提供providers

    @Singleton
    public class AppExecutors {

    private final Executor diskIO;

    public AppExecutors(Executor diskIO){
            this.diskIO=diskIO;
    }

    @Inject
    public AppExecutors(){
         this(Executors.newSingleThreadExecutor());
    }
    public Executor getDiskIO() {
         return diskIO;
    }
}
UserRepo 创建

直接在构造函数添加@Inject进行注入

    @Singleton
    public class UserRepo {

    private final UserDb userDb;

    private final UserDao userDao;

    private final AppExecutors appExecutors;

    @Inject
    public UserRepo(UserDb userDb,UserDao userDao,AppExecutors appExecutors){
        this.userDb=userDb;
        this.userDao=userDao;
        this.appExecutors=appExecutors;
    }

    public void insertUser(final User user){
        appExecutors.getDiskIO().execute(new Runnable() {
        @Override
        public void run() {
            userDao.insert(user);
        }
    });
}

    public void readUser(){
        appExecutors.getDiskIO().execute(new Runnable() {
        @Override
        public void run() {
            int m =userDao.getUsers().size();
            Log.i("+++","++++"+m);
        }
        });
    }
}

ViewModelFactory创建

    @Singleton
    public class ViewModelFactory implements ViewModelProvider.Factory {

    private final Map<Class<? extends ViewModel>, Provider<ViewModel>> creators;
    
        @Inject
        public ViewModelFactory(Map<Class<? extends ViewModel>, Provider<ViewModel>> creators) {
            this.creators = creators;
        }

    @NonNull
    @Override
    public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
        Provider<? extends ViewModel> creator = creators.get(modelClass);
        if (creator == null) {
            for (Map.Entry<Class<? extends ViewModel>, Provider<ViewModel>> entry : creators.entrySet()) {
                  if (modelClass.isAssignableFrom(entry.getKey())) {
                         creator = entry.getValue();
                         break;
                }
            }
        }
        if (creator == null) {
            throw new IllegalArgumentException("未知类" + modelClass);
        }
        try {
            return (T)creator.get();
        }catch (Exception e){
            throw new RuntimeException(e);
        }
// return null;
    }
}

ViewModelModule创建

创建ViewModelModule并使用@Binds注解提供注入


    @Module
    public abstract class ViewModelModule {

    @Binds
    abstract ViewModelProvider.Factory bindViewModelFactory(ViewModelFactory factory);
    }

ViewModelKey创建

创建需要进行多重绑定的Map,并绑定ViewModel


    @Target({ ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @MapKey
    public @interface ViewModelKey {
    Class<? extends ViewModel> value();
    }

在ViewModelModule中添加需要注入的ViewModel

通过@Binds @IntoMap @ViewModelKey 注解,提供给前文创建的Map数据,Key为 MainFragmentViewModel.class value为MainFragmentViewModel 实例


    @Module
    public abstract class ViewModelModule {

    @Binds
    @IntoMap
    @ViewModelKey(MainFragmentViewModel.class)
    abstract ViewModel bindViewModel(MainFragmentViewModel detailViewModel);
    }
在AppMoudle中添加ViewModelModule

    @Module(includes = {DbModule.class,ViewModelModule.class})
    public class AppModule {

    }

修改MainFragment

    public class MainFragment extends DaggerFragment

    @Inject
    ViewModelProvider.Factory viewModelFactory;

    private MainFragmentViewModel mainFragmentViewModel;


    //用于获取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) {
        mainFragmentViewModel.insertUser();
    }
    });

    fragmentDetailBinding.readDataTv.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            mainFragmentViewModel.readUser();
        }
    });
    return fragmentDetailBinding.getRoot();
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
            super.onActivityCreated(savedInstanceState);
            mainFragmentViewModel = ViewModelProviders.of(this, viewModelFactory).get(MainFragmentViewModel.class);
    }
    }

源码地址