文档章节

Android依赖注入应用

云贵高原
 云贵高原
发布于 2015/09/09 14:16
字数 1701
阅读 112
收藏 7
  • 依赖注入(DI)是一种设计模式,允许在运行时或编译时移除或改变硬编码的依赖性。使用依赖注入库可以减少编码量、把精力专注在更有价值的地方、降低维护成本。

  • Android程序通常使用注解(Annotation,例如@Click)实现“声明式编程”和依赖注入。

  • 注:“声明式编程”告诉机器在什么地方做什么事(Where to do What),让机器去决定如何干。而传统的“命令式编程”则需要告诉机器如何干(How to do What)。 声明式编程可以让程序员从具体的编码实现中解脱,减少编码量,把精力专注在更有价值的地方。

常见的依赖注入库

  • Dagger:实现了类构造注入(POJO注入),不支持函数注入。功能太简单,不建议使用。

  • ButterKnife:实现了视图注入、资源注入、事件绑定,使用自动生成的内部类实现注入。

    • 可在 Activity、Fragment 或 Adapter 类中注入视图:使用@Bind注解将每个视图字段与其资源ID关联,不用写findViewById和类型转换代码。 例如:@Bind(R.id.title) TextView title;

      支持视图数组绑定,例如:

      @Bind({ R.id.first_name, R.id.middle_name, R.id.last_name })
      List<EditText> nameViews;
      
    • 自动绑定事件处理函数:在事件处理函数上添加注解(@OnClick@OnItemSelected等),不用写事件处理的匿名侦听类和事件绑定代码。例如:

      @OnClick(R.id.submit)
      public void submit(View view) {
          // TODO submit data to server...
      }
      
    • 资源注入:使用@BindColor@BindDimen@BindDrawable@BindString等注解将资源ID与对象绑定。 例如:@BindDrawable(R.drawable.graphic) Drawable graphic;

    • 需要调用 ButterKnife.inject(activity) 在运行时动态绑定。 具体绑定关系和事件处理匿名侦听类是在预编译阶段自动生成的匿名类中实现的。

      所要绑定的视图字段的可访问性为package或public级别。

    • Eclipse中只需要一个jar包,用于自动生成依赖注入类。运行期不需要额外的jar包。

    • 在 Android Studio 开发环境中有自动添加注解的插件(Zelezny),可自动插入所有视图注解和视图字段。

  • RoboGuice:实现了视图注入、资源注入、系统服务注入、POJO注入、测试用例支持,基于 Google Guice 库实现。

    • 视图注入、资源注入、系统服务注入类似于 ButterKnife。例如: @InjectView(R.id.textView1) TextView textView1; @InjectResource(R.string.app_name) String name; @Inject LayoutInflater inflater;

    • POJO注入(类构造注入):省略构造函数,自动创建成员对象。例如 @Inject Foo foo;

    • 没有事件绑定功能。如需要可使用 ButterKnife 或 AndroidAnnotations。

    • 继承限制:你得在 RoboActivity 和 RoboFragment 中继承其中一个才能在Activity事件或Fragment中使用 RoboGuice 。

    • 安装:需要 roboguice、guice、jsr 等三个jar包。

  • AndroidAnnotations:实现了依赖注入(视图注入、事件绑定、资源注入、系统服务注入、值传递注入)、简化的线程模型、REST客户端。

    • 依赖注入和事件绑定:与 ButterKnife 类似,但需要在 Activity 等相关类前使用 @EActivitie 等注解以便使用依赖注入功能, 不需要像 ButterKnife 那样写额外的 inject() 绑定语句。

      下面的例子使用了 @EActivity@ViewById@Click@AfterViews等注解,简化了以往 onCreate 的初始化代码。

      @EActivity(R.layout.activity_main)              // 代替setContentView,@EActivity生成子类
      public class MainActivity extends Activity {
          private IViewHelper mHelper = ViewFactory.createHelper();
          @ViewById(R.id.lineWidthBar) SeekBar mLineWidthBar;     // 视图注入
      
          @Click void line_btn() {                    // 事件绑定,不指定ID就用名称查找资源
              mHelper.setCommand("line");
          }
      
          @Click(R.id.rect_btn)
          void onRectClick() {                        // 指定了ID就可以用别的函数名
              mHelper.setCommand("rect");
          }
      
          @SeekBarProgressChange(R.id.lineWidthBar)
          void onProgressChanged(SeekBar seekBar, int progress) {
              mHelper.setStrokeWidth(progress);
          }
      
          @SeekBarTouchStart(R.id.lineWidthBar)
          void onStartTrackingTouch(SeekBar seekBar) {
              mHelper.setContextEditing(true);
          }
      
          @SeekBarTouchStop(R.id.lineWidthBar)
          void onStopTrackingTouch(SeekBar seekBar) {
              mHelper.setContextEditing(false);
          }
      
          @AfterViews                                 // 视图已注入后
          void init() {
              // Do more after views injected
          }
      }
      
    • 简化的线程模型:用简单函数调用的方式使用UI线程和后台线程。例如:

      @Background             // 开启新线程后台运行,注意不要引用UI控件,而且返回值类型一定是void
      void someBackgroundWork(String name, long timeToDoSomeLongComputation) {
          try {
              TimeUnit.SECONDS.sleep(timeToDoSomeLongComputation);
          } catch (InterruptedException e) {
          }
      
          updateUi(String.format(helloFormat, name), androidColor);   // 直接调用就切到UI线程了
          showNotificationsDelayed();
      }
      
      @UiThread               // UI线程,可以指定多个参数
      void updateUi(String message, int color) {
          setProgressBarIndeterminateVisibility(false);
          textView.setText(message);  // UI线程中可访问UI控件
          textView.setTextColor(color);
      }
      
      @UiThread(delay=2000)   // 可以设置延时毫秒
      void showNotificationsDelayed() {
      }
      
    • 使用自动生成的子类实现注入,子类名为原类名加上一个下划线。例如在 AndroidManifest.xml 中使用的Activity改为android:name=".MainActivity_"

    • 在Eclipse中需要一个编译期jar包(androidannotations-X.Y.Z.jar),用于预编译阶段自动生成依赖注入的子类。 运行期需要另一个jar包(androidannotations-api-X.Y.Z.jar),约120KB。

    因为 AndroidAnnotations (简称AA)功能较多,可大幅减少代码量,易于理解和维护,所以本文推荐使用AA。

    本文接下来介绍在 ADT Bundle(Eclipse)开发环境下使用 AA 的方法。

插件安装和工程配置

  • 安装 Eclipse Java Development Tools 插件,以便启用 Annotation Processing

  • 下载并解压 AA的jar包

    • androidannotations-X.Y.Z.jar 用于预编译自动生成依赖注入代码文件,需要复制到项目中的某个目录(例如新建的 compile-libs 目录中,外部目录也行),不能是 libs 目录。

    • androidannotations-api-X.Y.Z.jar 用于注解和程序运行,需要放到项目的 libs 目录。

      为了查看源码,建议也放到 compile-libs 目录并 Add to Build Path,然后设置其 Java Source Attachment 为 androidannotations-api-X.Y.Z-sources.jar。 该jar文件根据自己的需要放在项目的 compile-libs 目录或外部目录,对于多人团队建议放在项目内。

  • 设置程序工程的属性,启用 Annotation Processing

    选中程序工程,打开 Project | Properties。

    查看 Java Compiler ,确定 Compiler compliance level 必须是 1.6 。

    查看 Java Compiler \ Annontation Processing ,选中 Enabled annontation processing 。 在Mac电脑上建议将自动生成的代码目录建议改为 gen,以避免 Eclipse 找不到代码目录(以点号开头的目录自动隐藏)。

    查看 Java Compiler \ Annontation Process \ Factory Path ,点击 Add JARs,把 androidannotations-X.Y.Z.jar 加进来。

    点击确定后将弹出个对话框,提示 annotation 设置变更,要求 rebuild project ,确定即可重建项目。

  • 在工程中使用 AA 的注解

    上面介绍AA时已经举例,这里不再重复,进一步阅读可参考官方Wiki文档

    Cookbook 页面中的“Enhanced components”(例如@EActivity)实质上会在预编译时生成对应的子类,在子类中实现注解注入功能。

    注意:子类的名称就是在原来的类之后加了一个下划线,例如MyActivity_, 需要在AndroidManifest.xml中改变原来的Activity类名,使用相关类时也要做相应替换。

    如果不方便在线浏览官方Wiki文档,可以下载Wiki文档: git clone https://github.com/excilys/androidannotations.wiki.git

注:本文首发于新博客(rhcad.com)

© 著作权归作者所有

云贵高原

云贵高原

粉丝 83
博文 38
码字总数 21429
作品 12
海淀
技术主管
私信 提问
Spring for Android 将 Spring 引到 Android 上

近日,SpringSource发布了Spring for Android 1.0。Spring for Android是Spring Framework的扩展,有助于简化原生Android应用的开发。此次发布最为引入关注之处是提供了一个REST客户端(Res...

墙头草
2012/07/09
4.6K
4
使用 Kotlin 构建 MVVM 应用程序—提高篇:Dagger-Android

写在前面 本篇是对于使用Kotlin构建MVVM应用程序—第四部分:依赖注入 Dagger2 的补充。 在依赖注入 Dagger2 这篇文章中,我们了解了 Dagger2 是如何进行依赖注入的。 可以简单的将Dagger2理...

ditclear
2018/08/19
0
0
当Dagger2撞上ViewModel

本文已授权 微信公众号 玉刚说 (@任玉刚)独家发布。 写在前面 过去一年多的时间里,我一直在致力于打造一个最简单,并能让普通Android开发者都能快速上手的框架,并陆续发表了多篇开发心得...

ditclear
2018/12/18
0
0
当Dagger2撞上ViewModel,一种更简单的注入方式

简书地址:www.jianshu.com/p/d3c43b9dd… 写在前面 过去一年多的时间里,我一直在致力于打造一个最简单,并能让普通Android开发者都能快速上手的框架,并陆续发表了多篇开发心得,最终汇总为...

ditclear
2018/12/03
0
0
当Dagger2遇上ViewModel

写在前面 过去一年多的时间里,我一直在致力于打造一个最简单,并能让普通Android开发者都能快速上手的框架,并陆续发表了多篇开发心得,最终汇总为了《使用Kotlin构建MVVM应用程序》系列文章...

ditclear
2018/12/01
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Knowage 6.2安装部署

注意:需要正确配置JAVA_HOME和JRE_HOME还有catalina_home,否则启动的时候tomcat一闪而过,想要获得报错信息,可以打开cmd,在dos命令行运行开始命令 官网:https://www.knowage-suite.com/s...

阿伦哥-
9分钟前
4
0
c++11 左值引用和右值引用

#include <iostream>using namespace std;void Print(string& s){ cout << s;}int main(){ string s="abc"; Print(s); // OK Print("abc"); // parse error......

SibylY
11分钟前
3
0
浅谈Facade外观模式

一、前言 外观模式是一种非常简单的模式,简单到我们经常都会使用,比如对于类A和B,如果两者需要交互,经过一定的处理过程才能实现某一个具体的功能,那么我们可以将这个处理的过程定义为一...

青衣霓裳
11分钟前
3
0
AnalyticDB for PostgreSQL 6.0 新特性介绍

阿里云 AnalyticDB for PostgreSQL 为采用MPP架构的分布式集群数据库,完备支持SQL 2003,部分兼容Oracle语法,支持PL/SQL存储过程,触发器,支持标准数据库事务ACID。ADB PG通过行存储、列存...

Mr_zebra
13分钟前
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部