利用Dagger2构建的简易MVP框架

作者: oden | 来源:发表于2017-08-19 22:10 被阅读0次

    简介

    本文使用dagger2构建MVP框架,目的是加深dagger2的理解,一个小demo,记录分享之。
    相关文章:
    Android Mvp实践
    Android中利用泛型简化MVP
    CSDN同步发布

    总体框架

    工程目录结构

    整个工程的目录结构如下:



    base文件夹存放一些公用的基类文件,di文件夹存放依赖注入相关的代码,mvp中按功能模块划分。本demo实现的功能为:通过点击界面上的按钮,获取手机系统时间并显示。

    具体实现

    在项目中引入dagger

    buildscript {
        repositories {
            jcenter()
        }
        dependencies {
            classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
        }
    }
    
    apply plugin: 'com.android.application' 
    apply plugin: 'com.neenbedankt.android-apt'
    
    dependencies {
        //other dependencies
    
        //Dagger2
        compile 'com.google.dagger:dagger:2.0.2'
        compile 'javax.annotation:jsr250-api:1.0'
        apt 'com.google.dagger:dagger-compiler:2.0.2'
    }
    

    BaseActivity

    BaseActivity中传入Presenter,利用@Inject注解Presenter,Dagger2会自动去找Presenter的生成方法,并创建presenter对象,则activity中持有presenter对象,可调用presenter中的方法。

    public abstract class BaseActivity<P extends BasePresenter> extends Activity {
        protected MyApplication myApplication;
    
        @Inject
        protected P mPresenter;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(initView());
    
            myApplication = (MyApplication) getApplication();
            ComponentInject(myApplication.getAppComponent());//依赖注入
            initData();
        }
    
        /**
         * 依赖注入的入口
         */
        protected abstract void ComponentInject(AppComponent appComponent);
    
        protected abstract View initView();
    
        protected abstract void initData();
    
    }
    

    BasePresenter

    BasePresenter中传入BaseView接口,持有view接口,可调用view中的方法

    public class BasePresenter<V extends BaseView>  implements presenter{
        protected V mRootView;
    
        public BasePresenter(V rootView) {
            this.mRootView = rootView;
            onStart();
        }
    
        @Override
        public void onStart() {
    
        }
    
        @Override
        public void onDestroy() {
    
        }
    }
    

    presenter层的具体实现

    TempLatePresenter的构造方法使用了@Inject注解,在上面的BaseActivity中自动构造TempLatePresenter对象时就是从这里产生的TempLatePresenter对象,同时该构造方法中还传入了TempLateContract.View参数,因此dagger2会继续寻找TempLateContract.View的生成方法

    public class TempLatePresenter extends BasePresenter<TempLateContract.View> {
    
        @Inject
        public TempLatePresenter(TempLateContract.View rootView) {
            super(rootView);
        }
    
    
        public void getTime() {
            mRootView.setTime(System.currentTimeMillis() + "");
        }
    
    }
    
    

    依赖注入

    @Module中提供TempLateContract.View的构造方法

    @Module
    public class TempLateModule {
        private TempLateContract.View view;
    
        public TempLateModule(TempLateContract.View view) {
            this.view = view;
        }
    
        @ActivityScope
        @Provides
        TempLateContract.View provideTempLateView() {
            return this.view;
        }
    }
    

    TempLateComponent管理该module

    @ActivityScope
    @Component(modules = TempLateModule.class, dependencies = AppComponent.class)
    public interface TempLateComponent {
        void inject(TempLateActivity activity);
    }
    

    view层的具体实现

    TempLateActivity中调用ComponentInject,实现依赖注入

    public class TempLateActivity extends BaseActivity<TempLatePresenter> implements TempLateContract.View{
    
        Button btnGetTime;
        TextView tvTime;
    
        @Override
        protected void ComponentInject(AppComponent appComponent) {
            DaggerTempLateComponent
                    .builder()
                    .appComponent(appComponent)
                    .tempLateModule(new TempLateModule(this)) //请将TempLateModule()第一个首字母改为小写
                    .build()
                    .inject(this);
        }
    
        @Override
        protected View initView() {
            return LayoutInflater.from(this).inflate(R.layout.activity_template, null, false);
        }
    
        @Override
        protected void initData() {
            btnGetTime = (Button) findViewById(R.id.btn_get_time);
            tvTime = (TextView) findViewById(R.id.tv_time);
    
            btnGetTime.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    mPresenter.getTime();
                }
            });
        }
    
        @Override
        public void setTime(String time) {
            tvTime.setText(time);
        }
    
    }
    

    整体流程如下:

    • TempLateActivity继承BaseActivity并传入TempLatePresenter,view中持有TempLatePresenter对象
    • dagger2根据@inject注解知道要构造TempLatePresenter对象
    • 找到TempLatePresenter的构造方法,该方法中持有view的引用,发现还需要TempLateContract.View参数
    • 在TempLateModule中找到TempLateContract.View的构造方法
    • 依次完成TempLateContract.View和TempLatePresenter的构造

    Dagger2简单理解

    Module中提供Dependency

    @Module
    public class AppModule {
    
        public AppModule(Context context) {
            this.mContext = context;
        }
    
        @Provides
        public Context provideContext() {
            return mContext;
        }
    
        @Provides
        public OkHttpClient provideOkHttpClient() {
            OkHttpClient okhttpClient = new OkHttpClient.Builder()
                    .connectTimeout(30, TimeUnit.SECONDS)
                    .build();
            return okhttpClient;
        }
    
        @Provides
        public Retrofit provideRetrofit(OkHttpClient okhttpClient) {
            Retrofit retrofit = new Retrofit.Builder()
                    .client(okhttpClient)
                    .baseUrl("https://api.github.com")
                    .build();
            return retrofit;
        }
    }
    

    这种用来生产Dependency的、用 @Provides修饰过的方法叫Provider方法。如果最后找到的 provideOkHttpClient()方法也需要其他参数,那么管理员还会继续递归的找下去,直到所有的Dependency都被满足了,再一个一个创建Dependency

    工厂管理员:Component

    方法一:在Component里面定义一个返回Dependency的方法

    @Component(modules = {AppModule.class})
    public interface AppComponent {
        LoginPresenter loginPresenter();
    }
    
    public class LoginActivity extends AppCompatActivity {
        private LoginPresenter mLoginPresenter;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            AppComponent appComponent = DaggerAppComponent.builder().appModule(new AppModule(this)).build();  //<=
            mLoginPresenter = appComponent.loginPresenter();   //<=
        }
    }
    

    方法二:Field Injection

    DaggerAppComponent实现这个方法的方式是,去LoginActivity里面所有被 @Inject修饰的field,然后调用 AppModule相应的Provider方法,赋值给这个field。这里需要注意的是,@Inject field不能使private,不然dagger2找不到这个field。

    @Component(modules = {AppModule.class})
    public interface AppComponent {
        void inject(LoginActivity loginActivity);  //<=
    }
    
    public class LoginActivity extends AppCompatActivity {
        @Inject                             
        LoginPresenter mLoginPresenter;     
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            AppComponent appComponent = DaggerAppComponent.builder().appModule(new AppModule(this)).build(); //<=
            appComponent.inject(this); //<=
    
            //从此之后,mLoginPresenter就被实例化了
            //mLoginPresenter.isLogin()
        }
    }
    

    其实AppModule里面的很多Provider方法是不需要定义的。比如说在这种情况下,LoginPresenter的Provider方法 provideLoginPresenter(UserManager userManager, PasswordValidator validator) 就不需要定义,你只需要在定义LoginPresenter的时候,给它的Constructor加上 @Inject修饰一下:

    public class LoginPresenter {
        private final UserManager mUserManager;
        private final PasswordValidator mPasswordValidator;
    
        @Inject
        public LoginPresenter(UserManager userManager, PasswordValidator passwordValidator) {
            this.mUserManager = userManager;
            this.mPasswordValidator = passwordValidator;
        }
    
        //other methods
    }
    

    源码已上传github

    参考文章

    使用dagger2来做依赖注入,以及在单元测试中的应用

    相关文章

      网友评论

        本文标题:利用Dagger2构建的简易MVP框架

        本文链接:https://www.haomeiwen.com/subject/wrdxdxtx.html