Dagger2 封装与实战演练

Dagger2 封装与实战演练_第1张图片
0.jpg

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

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

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

[toc]

前言

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

关于 degger2 的简单介绍请看 degger2 入门例子 或者学习 菜鸟窝 官方推出的 Dagger2 从基础到高级 教程。
本文不介绍基础概念,主要介绍 Dagger2 的封装使用。

介绍分包

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

Dagger2 封装与实战演练_第2张图片
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 如下

使用过 Retrofit 的都知道这个的作用哈,不懂的可以看我另一篇文章: Retrofit2 目前最优雅的网络请求框架。

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

    @GET("featured")
    public Call> 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> 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 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  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 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 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 所提供的对象了。


Dagger2 封装与实战演练_第3张图片
有图有真相
关注菜鸟窝官网免费领取140套开源项目
Dagger2 封装与实战演练_第4张图片
菜鸟窝官网公号二维码.png
扫码进菜鸟手机助手—专属Appstore学习群,
与大咖交流
Dagger2 封装与实战演练_第5张图片
手机助手.png

你可能感兴趣的:(Dagger2 封装与实战演练)