本文为菜鸟窝作者 吴威龙 的连载
菜鸟窝是专业的程序猿在线学习平台,提供最系统的 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 模块
如下图所示:
自定义 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<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 所提供的对象了。
有图有真相
网友评论