编程开源技术交流,分享技术与知识

网站首页 > 开源技术 正文

Dagger2不用单独学,看这篇文章就能了解原理

wxchong 2024-08-19 02:14:40 开源技术 8 ℃ 0 评论

前言

以为工作需求,所以最近补了补之前没了解过的Dagger2的内容,基础篇已经发布。接下来就是Dagger2在Android中的应用了。当然,和我一样刚接触Dagger2的朋友,可以先看一下之前的基础文章:

出来混迟早要还的,技术债Dagger2:基础篇

翻译给刚入Dagger这个坑的Android开发者:简介篇

翻译给刚入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重构部分,欢迎关注我,后续在我的文章里边中阅读~

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表