安卓平台上的依赖注入(一)
创始人
2024-03-01 18:33:17
0

刚开始学习软件工程的时候,我们经常会碰到像这样的事情:

软件应该符合 SOLID 原则。

但这句话实际是什么意思?让我们看看 SOLID 中每个字母在架构里所代表的重要含义,例如:

简单来说,我们需要提供一个类,这个类有它所需要的所有对象,以便实现其功能。

概述

依赖注入听起来像是描述非常复杂的东西的一个术语,但实际上它很简单,看下面这个例子你就明白了:

class NoDependencyInjection {
  private Dependency d;

  public NoDependencyInjection() {
    d = new Dependency();
  }
}

class DependencyInjection {
  private Dependency d;

  public DependencyInjection(Dependency d) {
    this.d = d;
  }
}

正如我们所见,第一种情况是我们在构造器里创建了依赖对象,但在第二种情况下,它作为参数被传递给构造器,这就是我们所说的 依赖注入 ( dependency injection ) 。这样做是为了让我们所写的类不依靠特定依赖关系的实现,却能直接使用它。

参数传递的目标是构造器,我们就称之为构造器依赖注入;或者是某个方法,就称之为方法依赖注入:

class Example {
  private ConstructorDependency cd;
  private MethodDependency md;
  Example(ConstructorDependency cd) {
    this.cd = cd; //Constructor Dependency Injection
  }

  public setMethodDependency(MethodDependency md) {
    this.md = md; //Method Dependency Injection
  }
}

要是你想总体深入地了解依赖注入,可以看看由 Dan Lew 发表的精彩的演讲,事实上是这个演讲启迪了这篇概述。

在 Android 平台,当需要框架来处理依赖注入这个特殊的问题时,我们有不同的选择,其中最有名的框架就是 Dagger 2。它最开始是由 Square 公司(LCTT 译注:Square 是美国一家移动支付公司)的一些很棒的开发者开发出来的,然后慢慢发展成由 Google 自己开发。首先开发出来的是 Dagger 1,然后 Big G 接手这个项目发布了第二个版本,做了很多改动,比如以 注解 ( annotation ) 为基础,在编译的时候完成其任务。

导入框架

安装 Dagger 并不难,但需要导入 android-apt 插件,通过向项目的根目录下的 build.gradle 文件中添加它的依赖关系:

buildscript{
  ...
  dependencies{
    ...
    classpath ‘com.neenbedankt.gradle.plugins:android-apt:1.8’
  }
}

然后,我们需要将 android-apt 插件应用到项目 build.gradle 文件,放在文件顶部 Android application 那一句的下一行:

apply plugin: ‘com.neenbedankt.android-apt’

这个时候,我们只用添加依赖关系,然后就能使用库及其 注解 ( annotation ) 了:

dependencies{
    ...
    compile ‘com.google.dagger:dagger:2.6’ 
    apt ‘com.google.dagger:dagger-compiler:2.6’
    provided ‘javax.annotation:jsr250-api:1.0’
}

需要加上最后一个依赖关系是因为 @Generated 注解在 Android 里还不可用,但它是原生的 Java 注解

Dagger 模块

要注入依赖,首先需要告诉框架我们能提供什么(比如说上下文)以及特定的对象应该怎样创建。为了完成注入,我们用 @Module 注释对一个特殊的类进行了注解(这样 Dagger 就能识别它了),寻找 @Provide 注解的方法,生成图表,能够返回我们所请求的对象。

看下面的例子,这里我们创建了一个模块,它会返回给我们 ConnectivityManager,所以我们要把 Context 对象传给这个模块的构造器。

@Module
public class ApplicationModule {
  private final Context context;

  public ApplicationModule(Context context) {
    this.context = context;
  }

  @Provides @Singleton
  public Context providesContext() {
    return context;
  }

  @Provides @Singleton
  public ConnectivityManager providesConnectivityManager(Context context) {
    return (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
  }
}

Dagger 中十分有意思的一点是简单地注解一个方法来提供一个单例(Singleton),就能处理所有从 Java 中继承过来的问题。

组件

当我们有一个模块的时候,我们需要告诉 Dagger 想把依赖注入到哪里:我们在一个 组件 ( Component ) 里完成依赖注入,这是一个我们特别创建的特殊注解接口。我们在这个接口里创造不同的方法,而接口的参数是我们想注入依赖关系的类。

下面给出一个例子并告诉 Dagger 我们想要 MainActivity 类能够接受 ConnectivityManager(或者在图表里的其它依赖对象)。我们只要做类似以下的事:

@Singleton
@Component(modules = {ApplicationModule.class})
public interface ApplicationComponent {

  void inject(MainActivity activity);
}

正如我们所见,@Component 注解有几个参数,一个是所支持的模块的数组,代表它能提供的依赖。这里既可以是 Context 也可以是 ConnectivityManager,因为它们在 ApplicationModule 类中有声明。

用法

这时,我们要做的是尽快创建组件(比如在应用的 onCreate 阶段)并返回它,那么类就能用它来注入依赖了:

为了让框架自动生成 DaggerApplicationComponent,我们需要构建项目以便 Dagger 能够扫描我们的代码,并生成我们需要的部分。

MainActivity 里,我们要做的两件事是用 @Inject 注解符对想要注入的属性进行注解,调用我们在 ApplicationComponent 接口中声明的方法(请注意后面一部分会因我们使用的注入类型的不同而变化,但这里简单起见我们不去管它),然后依赖就被注入了,我们就能自由使用他们:

public class MainActivity extends AppCompatActivity {
  @Inject
  ConnectivityManager manager;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    ...
    ((App) getApplication()).getComponent().inject(this);
  }
}

总结

当然了,我们可以手动注入依赖,管理所有不同的对象,但 Dagger 消除了很多比如模板这样的“噪声”,给我们提供有用的附加品(比如 Singleton),而仅用 Java 处理将会很糟糕。


via: https://medium.com/di-101/di-101-part-1-81896c2858a0

作者:Roberto Orgiu 译者:GitFuture 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

相关内容

怎么用AI做短视频赚钱?小...
嘿,你是不是也刷到过那些爆火的短视频,心想:“这玩意儿咋这么赚钱?...
2025-06-06 22:12:18
JAVA集合知识整理
Java集合知识整理 HashMap相关 HashMap的底层数据...
2025-06-01 22:12:08
安卓逆向高阶之frida ...
文章目录1. 初次hook Java 层函数2. hook 修改函...
2025-06-01 20:46:39
【Java基础面试宝典】h...
目录 hashCode和equals之间的关系 final关键字的...
2025-06-01 18:07:56
Java开发一年不到,来面...
前言 我的好朋友兼大学同学老伍家庭经济情况不错,毕业...
2025-06-01 15:50:23
java LinkedHa...
目录 一、前言 二、LinkedHashSet简介 三、Linke...
2025-06-01 14:58:51

热门资讯

Helix:高级 Linux ... 说到 基于终端的文本编辑器,通常 Vim、Emacs 和 Nano 受到了关注。这并不意味着没有其他...
使用 KRAWL 扫描 Kub... 用 KRAWL 脚本来识别 Kubernetes Pod 和容器中的错误。当你使用 Kubernet...
JStock:Linux 上不... 如果你在股票市场做投资,那么你可能非常清楚投资组合管理计划有多重要。管理投资组合的目标是依据你能承受...
通过 SaltStack 管理... 我在搜索Puppet的替代品时,偶然间碰到了Salt。我喜欢puppet,但是我又爱上Salt了:)...
Epic 游戏商店现在可在 S... 现在可以在 Steam Deck 上运行 Epic 游戏商店了,几乎无懈可击! 但是,它是非官方的。...
《Apex 英雄》正式可在 S... 《Apex 英雄》现已通过 Steam Deck 验证,这使其成为支持 Linux 的顶级多人游戏之...
如何在 Github 上创建一... 学习如何复刻一个仓库,进行更改,并要求维护人员审查并合并它。你知道如何使用 git 了,你有一个 G...
2024 开年,LLUG 和你... Hi,Linuxer,2024 新年伊始,不知道你是否已经准备好迎接新的一年~ 2024 年,Lin...
什么是 KDE Connect... 什么是 KDE Connect?它的主要特性是什么?它应该如何安装?本文提供了基本的使用指南。科技日...
Opera 浏览器内置的 VP... 昨天我们报道过 Opera 浏览器内置了 VPN 服务,用户打开它可以防止他们的在线活动被窥视。不过...