首页 热点专区 小学知识 中学知识 出国留学 考研考公
您的当前位置:首页正文

Dagger2 封装与实战演练

来源:要发发知识网
0.jpg

本文为菜鸟窝作者 吴威龙 的连载

菜鸟窝是专业的程序猿在线学习平台,提供最系统的 Android 项目实战课程

如需转载,请联系菜鸟窝公众号(cniao5),并注明出处。

[toc]

前言

A fast dependency injector for Android and Java. 一个在 Android 和 Java 平台上使用的快速的依赖注入框架。 类似 java 开发中的 spring 框架,但使用难度比 spring 大一点点。 依赖注入框架主要用于模块间解耦,提高代码的健壮性和可维护性。

介绍分包

一般我们习惯把 Dagger2 依赖注入相关的类放在 di 包下。
根据 dagger2 的风格,一般有 module 和 component 模块
如下图所示:

image

自定义 Application

我们都知道,自定义 Application 类,可以方便的设置初始化的工作,Gson 对象,DB 对象,单例的对象,开销比较大但是只需要初始化一次的对象等等。
而使用 dagger2 实例化管理我们的类,还可以对生命周期进行管理,将显得更加方便实用。
要在 Application 中使用依赖注入的对象,那么 Application 就充当了 Dagger2 三个元素中的 Container 对象。

/**
 * Created by Veyron on 2017/5/9.
 * Function:在 AppApplication 使用依赖注入对象
 */
public class AppApplication extends Application {

    private AppComponent mAppComponent;
    public static AppApplication get(Context context){
        return (AppApplication)context.getApplicationContext();
    }

    public AppComponent getAppComponent(){

        return mAppComponent;
    }

    @Override
    public void onCreate() {
        super.onCreate();

        mAppComponent= DaggerAppComponent.builder().appModule(new AppModule(this))
                .httpModule(new HttpModule()).build();
    }

定义 APP 级别的 AppModule

AppModule 提供最常用的对象,如 Gson,Application
单例对象,单例对象需要用 @Singleton 声明。


@Module
public class AppModule {

    private Application mApplication;
    // Application 不能 new ,这里通过构造方法传递过来
    public AppModule(Application application){

        this.mApplication = application;
    }

    @Provides
    @Singleton
    public Application provideApplication(){

        return  mApplication;
    }

    @Provides
    @Singleton
    public Gson provideGson(){

        return  new Gson();
    }
}

定义全局 AppComponent

引用 AppModule、HttpModule 两个 Module .因为里面声明的是单例对象,所以这里也需要用 @Singleton 注释。

@Singleton
@Component(modules = {AppModule.class, HttpModule.class})
public interface AppComponent {

    //最后加上这个
    public ApiService getApiService();
}

定义 Http 的 Module

提供 Http 操作相关的对象,这里是三个个单例对象 OkHttpClient、Retrofit、ApiService

@Module
public class HttpModule {
    @Provides
    @Singleton
    public OkHttpClient provideOkHttpClient(){


        // log用拦截器
        HttpLoggingInterceptor logging = new HttpLoggingInterceptor();

        // 开发模式记录整个body,否则只记录基本信息如返回200,http协议版本等
        logging.setLevel(HttpLoggingInterceptor.Level.BODY);

        // 如果使用到HTTPS,我们需要创建SSLSocketFactory,并设置到client
//        SSLSocketFactory sslSocketFactory = null;

        return new OkHttpClient.Builder()
                // HeadInterceptor实现了Interceptor,用来往Request Header添加一些业务相关数据,如APP版本,token信息
//                .addInterceptor(new HeadInterceptor())
                .addInterceptor(logging)
                // 连接超时时间设置
                .connectTimeout(10, TimeUnit.SECONDS)
                // 读取超时时间设置
                .readTimeout(10, TimeUnit.SECONDS)

                .build();
    }
    @Provides
    @Singleton
    public Retrofit provideRetrofit(OkHttpClient okHttpClient){

        Retrofit.Builder builder = new Retrofit.Builder()
                .baseUrl(ApiService.BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .client(okHttpClient);

        return builder.build();
    }
    @Provides
    @Singleton
    public ApiService provideApiService(Retrofit retrofit){
        //这里使用的 retrofit 是上面提供的
        return  retrofit.create(ApiService.class);
    }
}

其中 ApiService 如下

public interface ApiService {
    public static final String BASE_URL = "http://112.124.22.238:8081/course_api/cniaoplay/";

    @GET("featured")
    public Call<PageBean<AppInfo>> getApps(@Query("p") String jsonParam);
}

实际代码中使用 apiservice 对象

仔细看下面代码就发现了一个神奇的现象:在使用 Dagger2 之前或者说在 HttpModule 没有提供 ApiService 对象之前,需要先 new 出 HttpManager 对象,通过该 对象 获得
ApiService 对象。而使用 Dagger2 在 HttpModule 中提供了 ApiService 对象之后,在这里就可以直接使用了。当然,该 ApiService 对象是通过 构造函数传过来的。

public class RecommendModel {

    private  ApiService mApiService;

    public RecommendModel(ApiService apiService){

        this.mApiService  =apiService;
    }

    public  void getApps(Callback<PageBean<AppInfo>> callback){

//       使用 Dagger2 之前
//        HttpManager manager = new HttpManager();
//
//        ApiService apiService =manager.getRetrofit(manager.getOkHttpClient()).create(ApiService.class);

       // 使用 Dagger2 之后,因为 HttpModule 中已经提供了 ApiService 对象
        mApiService.getApps("{'page':0}").enqueue(callback);

    }

}

子 Component:RecommendComponent

需要自定义 Scope,因为依赖的 AppComponent 为单例,级别不能高过 singleton

inject(RecommendFragment fragment); 意思是向 RecommendFragment 中注入对象。

@FragmentScope
@Component(modules = RemmendModule.class,dependencies = AppComponent.class)
public interface RecommendComponent {

    void inject(RecommendFragment fragment);
}

自定义的 scope

照猫画虎的自定义如下

@Scope
@Documented
@Retention(RUNTIME)
public @interface FragmentScope {
}

RemcomendModule

提供的对象有:RecommendContract.View (先从构造函数传入)、RecommendModel、ProgressDialog。


@Module
public class RemmendModule {

    private RecommendContract.View mView;

    public RemmendModule(RecommendContract.View view){


        this.mView = view;
    }

    @Provides
    public RecommendContract.View provideView(){

        return mView;
    }

    @Provides
    public RecommendModel privodeModel(ApiService apiService){

        return  new  RecommendModel(apiService);
    }

    @Provides
    public ProgressDialog provideProgressDialog(RecommendContract.View view){

        return new ProgressDialog(((RecommendFragment)view).getActivity());
    }

}

BaseFragment

关于 Fragment、Activity 的封装下一篇文章再详细介绍,现在贴出来的 BaseFragment,关键点是封装了一下重要的方法:setupAcitivtyComponent() 获得 AppComponent 对象。

public  abstract  class BaseFragment<T extends BasePresenter> extends Fragment {
    private Unbinder mUnbinder;
    private AppApplication mApplication;
    private View mRootView;

    @Inject
    T mPresenter ;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

         mRootView = inflater.inflate(setLayout(), container, false);
         mUnbinder=  ButterKnife.bind(this, mRootView);

        return mRootView;
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        this.mApplication = (AppApplication) getActivity().getApplication();
        setupAcitivtyComponent(mApplication.getAppComponent());

        init();
    }
    @Override
    public void onDestroy() {
        super.onDestroy();

        if(mUnbinder != Unbinder.EMPTY){
            mUnbinder.unbind();
        }
    }
    public abstract int setLayout();
    public abstract  void setupAcitivtyComponent(AppComponent appComponent);
    public abstract void  init();
}

实际 View 中使用 Dagger2 依赖注入

这里只演示依赖注入 ProgressDialog 对象。

public class RecommendFragment extends BaseFragment<RecommendPresenter>  implements RecommendContract.View {

    @BindView(R.id.recycle_view)
    RecyclerView mRecyclerView;

    private RecomendAppAdatper mAdatper;

    @Inject
    ProgressDialog mProgressDialog;

    @Override
    public int setLayout() {
        return R.layout.fragment_recomend;
    }

    @Override
    public void setupAcitivtyComponent(AppComponent appComponent) {

        //Rebuild 一下,会根据 RecommendComponent 类生成 DaggerRecommendComponent 类
        DaggerRecommendComponent.builder().appComponent(appComponent)
                .remmendModule(new RemmendModule(this)).build().inject(this);
    }

    @Override
    public void init() {
        mPresenter.requestDatas();
    }

    private void initRecycleView(List<AppInfo> datas){

        //为RecyclerView设置布局管理器
        mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));


        //为RecyclerView设置分割线(这个可以对DividerItemDecoration进行修改,自定义)
        mRecyclerView.addItemDecoration(new DividerItemDecoration(getActivity(), DividerItemDecoration.HORIZONTAL_LIST));

        //动画
        mRecyclerView.setItemAnimator(new DefaultItemAnimator());


        mAdatper = new RecomendAppAdatper(getActivity(),datas);

        mRecyclerView.setAdapter(mAdatper);

    }


    @Override
    public void showResult(List<AppInfo> datas) {
        initRecycleView( datas);
    }

    @Override
    public void showNodata() {

        Toast.makeText(getActivity(),"暂时无数据,请吃完饭再来",Toast.LENGTH_LONG).show();
    }

    @Override
    public void showError(String msg) {
        Toast.makeText(getActivity(),"服务器开小差了:"+msg,Toast.LENGTH_LONG).show();
    }

    @Override
    public void showLodading() {

        mProgressDialog.show();
    }

    @Override
    public void dimissLoading() {

        if(mProgressDialog.isShowing()){
            mProgressDialog.dismiss();
        }
    }
}

总结

代码贴了很多,估计有的朋友都看晕了吧。其实思想可以简单归纳会如下几点:

  • 自定义 APP 级别的 AppModule:提供 Gson、Application 全局对象。

  • 自定义专职的 Module ---- HttpModule:主要负责提供 HTTP 相关的对象,如:OkHttpClient、Retrofit、ApiService。

  • 自定义 App 级别的 AppComponent:关联 modules:AppModule、HttpModule。声明 ApiService getApiService() 抽象方法。

  • 自定义 AppApplication:依赖注入 App 级别的 AppComponent,方便程序的使用,在程序的任何地方都可以 获得 AppComponent 对象。这样意味着在整个程序任何地方都可以很方便的使用 AppComponent 所关联的 AppModule 所提供的 Gson、Application 对象,以及 HttpModule 所提供的 OkHttpClient、Retrofit、ApiService 对象。

  • 自定义 Module ---- RecommendModule:主要负责提供 RecommendFragment 中需要用到的一些对象:RecommendContract.View、RecommendModel、ProgressDialog。

  • 自定义 Component ---- RecommendComponent:关联 mopdules:RemmendModule、依赖 AppComponent。把对象注入到 RecommendFragment 中。这样在 RecommendFragment 中就可以很方便的使用 RecommendModule 所提供的对象了。


有图有真相
关注菜鸟窝官网免费领取140套开源项目
菜鸟窝官网公号二维码.png
扫码进菜鸟手机助手—专属Appstore学习群,
与大咖交流
手机助手.png
显示全文