【Android 进阶】Dagger 封装与实战演练

来源:互联网 发布:淘宝上出售游戏账号 编辑:程序博客网 时间:2024/04/29 22:54

  • 前言
  • 介绍分包
  • 自定义 Application
  • 定义 APP 级别的 AppModule
  • 定义全局 AppComponent
  • 定义 Http 的 Module
  • 其中 ApiService 如下
  • 实际代码中使用 apiservice 对象
  • 子 ComponentRecommendComponent
  • 自定义的 scope
  • RemcomendModule
  • BaseFragment
  • 实际 View 中使用 Dagger2 依赖注入
  • 总结

前言

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

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

介绍分包

一般我们习惯把 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 声明。

@Modulepublic 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

@Modulepublic 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<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。

@Modulepublic 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 所提供的对象了。




欢迎关注我的微信公众号:

这里写图片描述