前言
以为工作需求,所以最近补了补之前没了解过的Dagger2的内容,基础篇已经发布。接下来就是Dagger2在Android中的应用了。当然,和我一样刚接触Dagger2的朋友,可以先看一下之前的基础文章:
翻译给刚入Dagger这个坑的Android开发者:DI入门篇
正文
这篇文章的Demo实在是太好了。所以我就厚颜无耻的把他的代码拿过来用...这是一个外国哥们的文章,我猜他应该不会怪我的,哈哈...
原文地址:[Dagger 2 for Android Beginners?—?Advanced part I](https://medium.com/@harivigneshjayapalan/dagger-2-for-android-beginners-advanced-part-i-1e14fccf2cc8)
进入正文之前,我们先看一下背景。代码需求很简单,从一个API上获取数据,然后加载到RecycleView上,并且会涉及到图片加载。
在这么一个需求之下,我们如果使用Dagger2为我们的工程提供相应的依赖呢?
简单罗列一下代码设计
- MainActivity.java:请求API并显示项目 RecyclerView
- Result.java:用于API响应的POJO,使用JSON Schema创建到POJO
- RandomUsersAdapter.java:适配器 RecyclerView
涉及以下依赖项和库。
- Retrofit
- GsonBuilder&Gson
- HttpLoggingInterceptor
- OkHttpClient
- Picasso
以上内容不重要,都是咱们日常开发常用的东西。怎么使用啥的,大家肯定都很属性,所以下文demo很多初始化啥的就跳过了,咱们的关注是Dagger2在Android中的应用。
注意,这里不是叭叭叭的贴代码,讲API,而是从一个业务出发,以Dagger2的角度讲解Daager2的依赖关系,相信你们会我和一样,看完一定会“拨云雾见青天”,哈哈~
一般解决方案
面对这种需求,我们的常规写法:
public class MainActivity extends AppCompatActivity { // 省略变量声明 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 省略View的初始化 // 省略Gson初始化 // 省略HttpLoggingInterceptor及OkHttpClient初始化 // 不省略太多了,免得失去代入感,哈哈。 retrofit = new Retrofit.Builder() .client(okHttpClient) .baseUrl("https://randomuser.me/") .addConverterFactory(GsonConverterFactory.create(gson)) .build(); populateUsers(); } // 网络请求 private void populateUsers() { Call<RandomUsers> randomUsersCall = getRandomUserService().getRandomUsers(10); randomUsersCall.enqueue(new Callback<RandomUsers>() { @Override public void onResponse(Call<RandomUsers> call, @NonNull Response<RandomUsers> response) { if(response.isSuccessful()) { mAdapter = new RandomUserAdapter(); mAdapter.setItems(response.body().getResults()); recyclerView.setAdapter(mAdapter); } } // 省略请求失败 }); } public RandomUsersApi getRandomUserService(){ return retrofit.create(RandomUsersApi.class); } }
public class RandomUserAdapter extends RecyclerView.Adapter<RandomUserAdapter.RandomUserViewHolder> { private List<Result> resultList = new ArrayList<>(); public RandomUserAdapter() {} @Override public RandomUserViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_random_user, parent, false); return new RandomUserViewHolder(view); } @Override public void onBindViewHolder(RandomUserViewHolder holder, int position) { Result result = resultList.get(position); // setText操作 holder.textView.setText(String.format("%s %s", result.getName().getFirst(), result.getName().getLast())); // 图片库加载图片 Picasso.with(holder.imageView.getContext()) .load(result.getPicture().getLarge()) .into(holder.imageView); } // 省略部分代码 }
写完上述代码之后,让我们挺一分钟,想一想我们刚才写的东西,是不是有明显的依赖关系?比如,我们的Activity依赖Retrofit,我们的Retrofit又依赖OkHttp等等这种关系。
而且,所有的初始化操作都其中在Activity做了处理,如果此时我们需要更多的Activity,难道还有一遍遍写重复的代码?
当然可能有朋友会说可以使用基类,或者单例等等的封装方式。不过今天我们通通不考虑这些,今天只聊Dagger2
上述的业务其实还很多内容没有考虑到,比如说缓存...因此我们的业务如果更精细一些会发现,还有依赖更多的模块:
- File/DB: 持久化缓存
- 内存Cache: 内存缓存
- OkHttp3Downloader: 下载模块
所以如果完整的展开代码,应该是这样的:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initViews(); // Gson依赖 GsonBuilder gsonBuilder = new GsonBuilder(); Gson gson = gsonBuilder.create(); // File持久化依赖 File cacheFile = new File(this.getCacheDir(), "HttpCache"); cacheFile.mkdirs(); // Cache内存依赖 Cache cache = new Cache(cacheFile, 10 * 1000 * 1000); //10 MB // Log依赖 HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() { @Override public void log(@NonNull String message) { Timber.i(message); } }); httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY); // OkHttp依赖 OkHttpClient okHttpClient = new OkHttpClient() .newBuilder() .cache(cache) .addInterceptor(httpLoggingInterceptor) .build(); OkHttp3Downloader okHttpDownloader = new OkHttp3Downloader(okHttpClient); // Picasso依赖 picasso = new Picasso.Builder(this).downloader(okHttpDownloader).build(); // Retrofit依赖 retrofit = new Retrofit.Builder() .client(okHttpClient) .baseUrl("https://randomuser.me/") .addConverterFactory(GsonConverterFactory.create(gson)) .build(); populateUsers(); }
作为“久经沙场”的老司机,这些都是家常便饭,便饭之余我们聊一些茶语饭后的话题:从这些初始化代码中抽象出一个依赖图。就如果Retrofit初始化时传了一个Gson,那就说明Retrofit依赖Gson...
因此,我们差不多能够梳理一个依赖关系图:
绿色框表示它们是依赖关系中的顶级的(任何模块都不想要依赖它),它们只会被依赖。
结合我们写过的初始化代码,这个图很好理解吧?我猜肯定有朋友这张图都已经在写下代码之时出现在脑海中了...
走到这一步,其实问题就已经显现出来了。这么庞大的初始化的过程,任谁都不会想再写第二遍。因此重构迫在眉睫。既然我们都已经捋清楚了我们所需要模块的依赖关系,那么接下来就是让Dagger2大展身手的时候了...
尾声
因为篇幅原来,怕各位一次看太多的内容,效率不高,所以这里将其一分而二,Dagger2重构部分,欢迎关注我,后续在我的文章里边中阅读~
本文暂时没有评论,来添加一个吧(●'◡'●)