本文为菜鸟窝作者 吴威龙 的连载
菜鸟窝是专业的程序猿在线学习平台,提供最系统的 Android 项目实战课程
如需转载,请联系菜鸟窝公众号(cniao5),并注明出处。
[toc]
前言
A fast dependency injector for Android and Java. 一个在 Android 和 Java 平台上使用的快速的依赖注入框架。 类似 java 开发中的 spring 框架,但使用难度比 spring 大一点点。 依赖注入框架主要用于模块间解耦,提高代码的健壮性和可维护性。
介绍分包
一般我们习惯把 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 如下
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 所提供的对象了。
有图有真相