精华内容
下载资源
问答
  • 安卓依赖注入

    2015-09-09 17:20:11
    Android开发进阶:使用依赖注入函数库Roboguice 2014-01-07 14:53 蒋晨毅 ImportNew 字号:T | T Roboguice是一个用于Android应用的依赖注入框架,使用Google官方的Guice库位极大地简化了Android...

    Android开发进阶:使用依赖注入函数库Roboguice

    2014-01-07 14:53 蒋晨毅 ImportNew 字号:T | T
    一键收藏,随时查看,分享好友!

    Roboguice是一个用于Android应用的依赖注入框架,使用Google官方的Guice库位极大地简化了Android的依赖注入。让你的Android应用开发之路更加平坦顺利,编程更加简单有趣。

    AD:

    本文原标题是如何成为一个偷懒又高效的Android开发人员,我敢肯定你对这个标题肯定心存疑惑,但事实就是如此,这个标题完全适合Android开发人员。据我所知, Android程序员不情愿写 findViewById()、点击事件监听等重复率较高的代码。那我们如何才能缩短编写业务逻辑代码的时间,并且避免写那些重复的代码呢?所以让我们来成为一个能偷懒又有高效率的Android程序员。想知道怎么做吗?不用急,接下来我就会写到。

    有许多第三方的库和框架是可供我们使用。出于种种原因,我们并不知道这些库或者知道但还没用过。有的开发者开发了自己定义的库或者并不想使用第三方的库。如果我们在应用程序开发的过程中使用一些第三方库,也许可以提高程序的可兼容性、漂亮的UI界面、让代码变得整洁等等。所以,我将研究更多像这样的 第三方库来帮助初学者和有经验的开发人员。

    今天,让我们来讨论下“依赖注入函数库”。

    什么是依赖注入?

    依赖注入是一种软件设计模式,无论是在运行时还是在编译时,允许删除、改变硬编码依赖性。[来自Wikipedia](维基百科资源):

    一些常用和普遍的依赖注入库有:

    RoboGuice:

    Roboguice是一个用于Android应用的依赖注入框架,使用Google官方的Guice库位极大地简化了Android的依赖注入。让你的Android应用开发之路更加平坦顺利,编程更加简单有趣。

    当你调用 getIntent(),getExtras()这些函数时你是否经常忘记检查是否为Null?RoboGuice可以帮助你。初始化TextView有必要调用findViewById()吗?不用,RoboGuice已经为你完成了。

    通过使用RoboGuice,你可以注入View视图控件、资源、系统服务或者其他任何对象。RoboGuice能帮你精简应用程序的代码。代码越少意味着出现问题或bug的次数也就越少,从而可以把更多的精力花在项目中那些需要编写或修改的部分,使得阅读代码更加容易。

    让我们来看看各种RoboGuice 库的使用方法。

    使用RoboGuice库 :

    • 控件注入:用@InjectViews方法初始化控件,例如:@InjectView(R.id.textview1)TextView textView1。
    • 资源注入:用@InjectResources方法初始化资源,例如:@InjectResource(R.string.app_name)String name。
    • 系统服务注入:用@Inject方法初始化并获取系统服务,例如:@Inject LayoutInflater inflater。
    • POJO对象注入:用@Inject方法注入并初始化POJO对象,例如:@Inject Foo foo。

    安装

    要使用RoboGuice,你需要下载JAR文件并把他们添加到环境变量中:

    我们来看看一个简单的一般事件代码:

    实例

    1. public class TestActivity extends Activity{ 
    2.   
    3.     TextView textView1; 
    4.     TextView textView2; 
    5.     ImageView imageView1; 
    6.     String name; 
    7.     Drawable icLauncher; 
    8.     LocationManager locManager; 
    9.     LayoutInflater inflater; 
    10.     NotificationManager notifyManager; 
    11.   
    12.     @Override 
    13.     protected void onCreate(Bundle savedInstanceState) { 
    14.         // TODO Auto-generated method stub 
    15.         super.onCreate(savedInstanceState); 
    16.         setContentView(R.layout.layout_test); 
    17.         textView1 = (TextView) findViewById(R.id.textView1); 
    18.         textView2 = (TextView) findViewById(R.id.textView2); 
    19.         imageView1 = (ImageView) findViewById(R.id.imageView1); 
    20.         name = getString(R.string.app_name); 
    21.         icLauncher = getResources().getDrawable(R.id.ic_launcher); 
    22.         locManager = (LocationManager) getSystemService(Activity.LOCATION_SERVICE); 
    23.         inflater = (LayoutInflater) getSystemService(Activity.LAYOUT_INFLATER_SERVICE); 
    24.         notifyManager = (NotificationManager) getSystemService(Activity.NOTIFICATION_SERVICE); 
    25.         textView1.setText("Hello World! RoboGuice demo"); 
    26.      } 

    再看看使用RoboGuice精简代码后神奇之处。

    使用RoboGuice

    你先要继承RoboActivity或者RoboFragment,才能使用RoboGuice的依赖注入功能。

    1. public class TestActivity extends RoboActivity{ 
    2.   
    3.     @InjectView(R.id.textView1) TextView textView1; 
    4.     @InjectView(R.id.textView2) TextView textView2; 
    5.     @InjectView(R.id.imageView1) ImageView imageView1; 
    6.     @InjectResource(R.string.app_name) String name; 
    7.     @InjectResource(R.drawable.ic_launcher) Drawable icLauncher; 
    8.     @Inject LocationManager locManager; 
    9.     @Inject LayoutInflater inflater; 
    10.     @Inject NotificationManager notifyManager; 
    11.     @Override 
    12.     protected void onCreate(Bundle savedInstanceState) { 
    13.         // TODO Auto-generated method stub 
    14.         super.onCreate(savedInstanceState); 
    15.         setContentView(R.layout.layout_test); 
    16.         textView1.setText(name); 
    17.     } 

    这么一对比,我想你肯定明白了为什么要使用RoboGuice?再来看看有哪些好处:

    使用RoboGuice的好处

    • 不需要初始化控件,如有需要就用@InjectViews。
    • 不需要初始化系统服务,如有需要就用@Inject。
    • 不需要初始化像Drawable,string以及其他的资源,如有需要就用@InjectResource。
    • 以上实践能帮助你精简代码。
    • 越少的代码,越少的问题和bugs。
    • 少量的代码让Android开发人员省力同时,也让他们能更专注于实际的业务逻辑。

    RoboGuice和ActionBarSherlock

    正如我前面提到的,你得在RoboActivity和RoboFragment中继承其中一个才能在Activity事件或Fragment中使用 RoboGuice。但是如果你已经在项目中使用了ActionBarSherlock去编译呢?那问题就在于,你已经继承了 SherlockActivity或SherlockFragmentActivity中的一个。现在问题是,你不能同时使用RoboGuice和 ActionBarSherlock。

    解决方法是,为Activities和Fragments定义一个基类。然后你就能同时使用RoboGuice和ActionBarSherlock了。

    你可以在这里下载一些基类:
    https://github.com/rtyley/roboguice-sherlock 或者下载JAR包也是一样:RoboGuice+Sherlock.jar,你可以任选一个添加到你的项目。

    展开全文
  • Android依赖注入

    2016-10-21 23:03:55
    依赖注入则是将这些依赖对象传递给被依赖对象,而不是被依赖对象自己创建这些对象,说白了注入就是对象作为参数传递。 public class MyClass{ private AnotherClass mAnotherObject; public MyClass(){ ...
    • 1.含义
      • 1)依赖是指一个对象持有其他对象的引用。依赖注入则是将这些依赖对象传递给被依赖对象,而不是被依赖对象自己创建这些对象,说白了注入就是对象作为参数传递。
    public class MyClass{
         private AnotherClass mAnotherObject;
    
         public MyClass(){
              mAnotherObject = new AnotherClass();
         }
    }

    2)通过传递对象的方式,所传递对象的更改不会影响代码。

    public class MyClass{
         private MyInterface mAnotherObject;
    
         public MyClass(MyInterface anotherObject){
              mAnotherObject = anotherObject;
         }
    }

    3)依赖注入可以简化代码编写,并提供一个可适配的环境,方便进行单元测试以及功能模块的配置。

    • 2.例子以及应用场景

      • 1)问题:某Android应用需要一个列表来显示用户的好友。
        “`java
        public class FriendListFragment{
        private FriendListAPI mFriendListAPI;
        ……

        public FriendListFragment(){
        mFriendListAPI = new FriendListAPI();
        }

        private void getFriendList(){
        mFriendListAPI.getFriendList(new Callback(){
        public void onSuccess(List list){
        ……
        }
        ……
        });
        }
        }
        public class FriendListAPI{
        private OkHttpClient mHttpClient;

        public FriendListAPI(){
        mHttpClient= new OkHttpClient();
        //接下来各种Http配置 ……
        }
        }

     - 2)技巧一:后台API没有准备好或者没有数据怎么办?自己添点测试数据试试吧。在FriendListFragment里面添加一个生成测试数据的方法buildTestData(),并替换getFriendList()方法。等后台API准备好后再改回来。
     - 3)技巧二:测试网络有延迟或错误的时候,程序是否会出现异常。这需要通过配置OkHttpClient参数来实现测试场景,于是又要更改FriendListAPI中相关HttpClient配置代码,测试完后再修改回来。
     - 4)以上两点虽然是技巧,其实也是问题,那么问题来了:这样对代码进行多次修改,很容易出错。因此,对于多次使用的模块,我们可以通过注入的方式,将引用传入需要使用的类中,而不是自己创建。通过编写两个API,一个是直接请求后台数据,另一个则只是一些静态测试数据。需要测试的时候注入可生成测试数据的API,测试完后则切换为正式API。
     ```java
     public class FriendListFragment{
         private FriendListAPI mFriendListAPI;
    
         public FriendListFragment(FriendListAPI friendListAPI){
              mFriendListAPI = friendListAPI;
         }
    }
     public class FriendListAPI{
         private OkHttpClient mHttpClient;
    
         public FriendListAPI(HttpClient okHttpClient){
              mHttpClient= okHttpClient;
              ......
         }
    }
     ```
    
     - 5)继续引入问题:引入一个稍微复杂的场景,更多的Fragment需要使用FriendListAPI,我们需要在两个不同的地方进行注入,因此产生了许多重复代码。 
    
     - 6)解决方案:因此,我们需要一个容器,它知道什么地方需要注入,注入什么样的对象。 
     - 7)Dagger:展示轻量级依赖注入库Dagger实现的注入
    首先定义模块:
    

    public class MyModule{
    @Provides @Singleton OkHttpClient provideOkHttpClient(){
    //这里可进行各种Http配置
    return new OkHttpClient();
    }

     @Provides @Singleton FriendListAPI provideFriendListAPI(){
          return newFriendListAPI();
     }
    

    }
    初始化模块以及依赖对象图:
    public class MyApplication extends Application{
    private ObjectGraph graph;

     @Override public void onCreate() {
          super.onCreate();
          graph = ObjectGraph.create(getModules().toArray());
     }
    
     protected List<Object> getModules() {
          return Arrays.asList(
               new MyModule(this));
     }
    
     public void inject(Object object) {
          graph.inject(object);
     }
    

    }
    最后添加注入点并进行注入
    public abstract class BaseActivity extends FragmentActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    ((MyApplication) getApplication()).inject(this);
    }
    }
    public class FriendListFragment{
    @Inject FriendListAPI mFriendListAPI;
    ……
    }
    public class FriendListAPI{
    @Inject OkHttpClient mHttpClient;
    ……
    }
    “`
    3.应用场景
    1)当你需要将配置数据注入到一个或多个模块时。在开发过程中前端访问后台服务器地址会分为测试服务器和正式服务器,以及各种第三方分享key和ID,依赖注入都是非常好的选择。
    2)当需要将同一依赖注入到多个模块时。如加载图片以及图片存储管理组件(Picasso, Android-Universal-Image-Loader)
    3)当需要对同一依赖注入不同的实现时。为方便开发和单元测试,后台API可有正式API和模拟API,通过依赖注入方便切换环境。
    4)当同一模块需要注入不同的配置时。

    4.原理
    1)基于反射的依赖注入框架(Guice、RoboGuice):性能差。已经废弃,原因是他们会在程序运行的时候需要扫描代码中的注解,并映射到内存中,耗时。
    2)Dagger:因为它使用了编译时注解,也就是说在编译代码的时候,Dagger就已经完成传统依赖注入框架在运行时所执行的任务,把它当做应用中的一个模块, 负责为其它模块提供实例并且注入依赖关系。那是它的基本职责。模块的创建位于我们应用中的一个点上,这样我们可以拥有完全的控制权。

    http://www.mamicode.com/info-detail-599464.html
    http://square.github.io/dagger/
    http://blog.csdn.net/zjbpku/article/details/18732295
    https://github.com/JakeWharton/butterknife
    http://blog.csdn.net/sbvfhp/article/details/47451835
    http://objccn.io/issue-11-6/
    推荐butterknief和androidstudio上面的一个插件配合使用,叫ButterKnief Zelezny。

    展开全文
  • android 依赖注入 应该研究一切使生活更轻松地为Android开发的事物。 有几个库可以简化测试,提高代码的模块化并提供已经创建的模拟对象: RoboGuice –这是Google依赖注入库的改编,但适用于Android ...

    android 依赖注入

    应该研究一切使生活更轻松地为Android开发的事物。 有几个库可以简化测试,提高代码的模块化并提供已经创建的模拟对象:
    1. RoboGuice –这是Google依赖注入库的改编,但适用于Android
    2. Robolectric-这是一个测试框架/平台,可消除对Android对象进行持续模拟的需要。 它也可以与RoboGuice一起使用。

    我不能感谢最初向我介绍依赖注入的那个人。 来自C ++世界,在C ++世界中,对象无法描述自己,除非开发人员有目的地自己实现它,否则就没有反射。对于一种更现代的语言,我经常创建自己的静态工厂来模拟@inject模式。 但是,如果对象可以完美地描述虚拟机,为什么还要每次都重新发明轮子呢?

    如果您从未看过Dependency Injection(DI),请先看一下RoboGuice在其网页上提供的“简单示例” 乍一看,这似乎是清除代码的一种好方法,以便维护人员可以仅关注每种方法中操作的细节。 那是一个附带好处(那是一个非常不错的好处),但仅仅是附带好处。 该示例并未展示这种框架在测试和声明无错误代码中的真正威力。

    您的代码库中没有DI

    让我们看一个关于DI可以帮助征服和缓解痛苦点的人为例子。 假设我有一个需要某种需要用户输入的小部件的方法。 我如何测试这种方法而无需他人逐步执行脚本(如书面说明中所述),在该脚本中,他们手动输入所有可能导致现实情况的不同组合? 这既昂贵又费时。 我什至不会提及错误的人为因素(例如意外跳过测试)。 糟糕,我刚刚做到了(看?容易犯错!)

    如果有一种方法可以实例化模拟结构,而又不会使父对象的构造函数长到20个参数,那么我很乐意跳过所有内容。 回顾设计模式101, 工厂对象提供了一种将对象创建逻辑与对象实例解耦的方法。 使用静态工厂对象,我可以随时插入测试版本。 看一看:

    public abstract class WidgetBase implements IWidget{
       protected ISomeObject mSomeObject;
    
       public WidgetBase(ISomeObject _obj){
          mSomeObject = _obj;
       }
    }
    
    public AlertWidgetFactory{
       static private WidgetBase mTest = null;
       static private boolean mTestFlag = false;
       static WidgetBase create(ISomeObject _obj){
          if(mTestFlag){
             return mTest;
          }
          return new AlertWidget(_obj);
       }
    
       static void setTest(WidgetBase _testWidget){
          mTest = _testWidget;
       }
    
       static void setTestFlag(boolean _flag){
          mTestFlag = _false;
       }
    }

    现在,当我开始测试我的代码时,我可以使一切自动化。 在我的JUnit单元测试的“ setUp”阶段,我可以替代某些模拟版本的“ WidgetBase”以返回许多可能的用户条目。 看看测试它使以下代码变得多么容易:

    public void someMethod(String _value){
        if(_value == ""){
          ISomeObject foo = new SomeValueAssigner( _value );
          IWidget alert = AlertWidgetFactory.create(foo);
       }
       //more code...
    }

    当然,如果我要从工厂生产不同的类类型,则将不得不为该对象编写工厂代码。 (在C ++中我只是模板,并有但对于一个工厂的类。有时候,模板是个东西,不是吗?就拿泛型!)。

    在代码中添加DI

    有些人可能因为不使用普通接口而不是抽象类而对我大喊大叫。 有一点很重要。 接口无法描述构造函数,我希望对象在构造函数中采用参数。 但为什么?

    首先仔细看一下上面的代码。 您是否在上面注意到我在“ SomeValueAssigner”中有一个硬编码的依赖项? 我不能真正地对“ someMethod”功能进行单元测试,因为在没有先为此创建工厂方法的情况下,我也无法消除相互依赖! 哦,人类。 仅为了测试大小合适的代码库,我们将必须创建多少个工厂对象? 每次我想要一个新对象时,都可能需要为其创建接口,抽象基类和/或工厂对象。 对于它具有的每个不同的构造函数,我可能还需要向工厂对象添加一个新方法。

    我不需要这么说,但这是很多工作。 实际上,即使对于Google的工程师来说,这也是繁重的工作。 这就是为什么他们首先提出Guice的原因。 DI解决了很多麻烦,并且省去了重新设计轮子的时间,但有一些限制(请参阅构造函数参数上的InjectionPoints )。 它不能替代标准设计模式,也不能避免将参数传递给构造函数。 RoboGuice只是工具集中的另一个工具(一种非常强大且便捷的工具)。

    避免仿真阶段

    您不知道吗,但是测试UI组件是一项艰巨的工作。 我们不仅需要首先查看事物,以查看所有形状/大小/颜色是否正确显示,而且还需要确保它能够实现预期的功能。 然后是模拟Android设备预热的等待期。 从Robolectric的网站报价:

    在Android模拟器或设备上运行测试很慢! 构建,部署和启动应用程序通常需要一分钟或更长时间。 那不是做TDD的方法。 肯定有更好的办法。

    我完全同意。 等待仿真器编译和加载应用程序以进行小的修复是很痛苦的。
    Robolectric使您可以更快地迭代。 快速迭代可以带来更好的设计。 更好的设计导致更少的维护问题。 较少的维护问题导致增加了更多时间来添加新功能或优化功能。 所有这些事情为最终用户带来了更好的产品体验。
    这对您的底线非常有利。 即使本节很短,但与节省您的时间几乎成反比。

    结论

    RoboGuice让您更轻松地进行测试,并添加了另一个工具/习惯用法来帮助分离代码。 Robolectric让您测试更快。 将它们放在一起,您将获得一个环境,在此环境中您可以更高效,更高效地工作。 这是您不应该缺少的两个库。

    参考: Android:您应该从我们的JCG合作伙伴静态类型博客中 使用的库

    相关文章 :

    翻译自: https://www.javacodegeeks.com/2011/06/android-dependency-injection-testing.html

    android 依赖注入

    展开全文
  • android 依赖注入 什么是依赖注入? (What is Dependency Injection?) Classes often require references to other classes. For example, a Car class might need a reference to an Engine class. These required ...

    android 依赖注入

    什么是依赖注入? (What is Dependency Injection?)

    Classes often require references to other classes. For example, a Car class might need a reference to an Engine class. These required classes are called dependencies, the Car class is dependent on having an instance of the Engine class to run.

    类通常需要引用其他类。 例如,Car类可能需要引用Engine类。 这些必需的类称为依赖项,Car类依赖于要运行Engine类的实例。

    There are three ways for a class to get an object it needs:

    类通过三种方式获取所需的对象:

    • The class constructs the dependency it needs. In the example above, Car would create and initialize its own instance of Engine.

      该类构造所需的依赖项。 在上面的示例中,Car将创建并初始化其自己的Engine实例。
    • Grab it from somewhere else. Some Android APIs, such as Context getters and getSystemService(), work this way.

      从其他地方抓取它。 某些Android API(例如Context getters和getSystemService())以这种方式工作。
    • Have it supplied as a parameter. The app can provide these dependencies when the class is constructed or pass them into the functions that need each dependency. In the example above, the Car constructor would receive Engine as a parameter.

      将其作为参数提供。 应用程序可以在构造类时提供这些依赖关系,或将它们传递给需要每个依赖关系的函数。 在上面的示例中,Car构造函数将接收Engine作为参数。

    The third option is dependency injection! With this approach, you take the dependencies of a class and provide them rather than having the class instance obtain them itself.

    第三种选择是依赖注入! 使用这种方法,您可以获取类的依赖关系并提供它们,而不是让类实例自己获取它们。

    在Android中通过三种主要方式进行依赖项注入: (There are three major ways to do dependency injection in Android:)

    • Constructor Injection. This is the way described above. You pass the dependencies of a class to its constructor.

      构造函数注入。 这就是上面描述的方式。 您将类的依赖项传递给其构造函数。
    • Field Injection (or Setter Injection). Certain Android framework classes such as activities and fragments are instantiated by the system, so constructor injection is not possible. With field injection, dependencies are instantiated after the class is created.

      场注入(或二传手注入)。 系统会实例化某些Android框架类(例如活动和片段),因此无法进行构造函数注入。 使用字段注入,在创建类后实例化依赖项。
    • Method Injection, you can use @Inject annotation with method also.

      方法注入,您也可以在方法中使用@Inject注释。

    Note: — If a class contains all types of Injection i.e constructor, field and method injection, dagger will inject all types in the following sequence :

    注意:—如果一个类包含所有类型的Injection,即构造函数,字段和方法注入,则dagger将按以下顺序注入所有类型:

    1. Constructor

      建设者

    2. Field

      领域

    3. Method

      方法

    依赖注入为您的应用程序提供以下优势: (Dependency injection provides your app with the following advantages:)

    • Reusability of classes and decoupling of dependencies: It’s easier to swap out implementations of a dependency. Code reuse is improved because of inversion of control, and classes no longer control how their dependencies are created, but instead work with any configuration.

      类的可重用性和依赖关系的解耦:交换依赖关系的实现更加容易。 由于控制反转,因此代码重用得到了改善,并且类不再控制其依赖关系的创建方式,而是可以与任何配置一起使用。
    • Ease of refactoring: The dependencies become a verifiable part of the API surface, so they can be checked at the object-creation time or at compile time rather than being hidden as implementation details.

      易于重构:依赖关系成为API表面的可验证部分,因此可以在对象创建时或编译时对其进行检查,而不必将其隐藏为实现细节。
    • Ease of testing: A class doesn’t manage its dependencies, so when you’re testing it, you can pass in different implementations to test all of your different cases.

      易于测试:类不管理其依赖关系,因此在测试它时,您可以传入不同的实现来测试所有不同的情况。

    什么是Dagger2? (What is Dagger2?)

    Dagger is a popular dependency injection library for Java, Kotlin, and Android that is maintained by Google. Dagger facilitates using DI in your app by creating and managing the graph of dependencies for you. It provides fully static and compile-time dependencies addressing many of the development and performance issues of reflection-based solutions such as Guice.

    Dagger是Google维护的Java,Kotlin和Android流行的依赖项注入库。 Dagger通过为您创建和管理依赖关系图来促进在应用程序中使用DI。 它提供了完全静态和编译时的依赖性,解决了基于反射的解决方案(例如Guice)的许多开发和性能问题。

    To demonstrate how you can work with Dagger, let’s create a simple factory for the UserRepository class shown in the following diagram:

    为了演示如何使用Dagger,让我们为下图所示的UserRepository类创建一个简单的工厂:

    Image for post

    Dagger components

    匕首组件

    Dagger can create a graph of the dependencies in your project that it can use to find out where it should get those dependencies when they are needed. To make Dagger do this, you need to create an interface and annotate it with @Component.

    Dagger可以在您的项目中创建依赖关系图,可用于查找需要时从何处获取这些依赖关系。 为了使Dagger做到这一点,您需要创建一个接口并使用@Component对其进行注释。

    Inside the @Component interface, you can define functions that return instances of the classes you need (i.e. UserRepository). @Component tells Dagger to generate a container with all the dependencies required to satisfy the types it exposes. This is called a Dagger component; it contains a graph that consists of the objects that Dagger knows how to provide and their respective dependencies.

    在@Component接口内,您可以定义函数以返回所需类的实例(即UserRepository)。 @Component告诉Dagger生成一个容器,该容器具有满足其公开的类型所需的所有依赖关系。 这称为Dagger组件; 它包含一个图形,该图形由Dagger知道如何提供的对象及其各自的依存关系组成。

    // @Component makes Dagger create a graph of dependencies
        @Singleton
        @Component
        interface ApplicationGraph {
          // The return type of functions inside the component interface is
         // what can be provided from the container
              fun repository(): UserRepository
          }

    Add an @Inject annotation to the UserRepository constructor so Dagger knows how to create a UserRepository.

    将@Inject批注添加到UserRepository构造函数,以便Dagger知道如何创建UserRepository。

    // @Inject lets Dagger know how to create instances of this object
    class UserRepository @Inject constructor(
        private val localDataSource: UserLocalDataSource,
        private val remoteDataSource: UserRemoteDataSource
    ) { ... }

    Now Dagger knows how to create an instance of UserRepository, but it doesn't know how to create its dependencies. If you annotate the other classes too, Dagger knows how to create them:

    现在Dagger知道如何创建UserRepository的实例,但它不知道如何创建其依赖项。 如果您还要注释其他类,则Dagger知道如何创建它们:

    // @Inject lets Dagger know how to create instances of these objects
    class UserLocalDataSource @Inject constructor() { ... }
    class UserRemoteDataSource @Inject constructor() { ... }

    When you build the project, Dagger generates an implementation of the ApplicationGraph interface for you: DaggerApplicationGraph

    在构建项目时,Dagger会为您生成ApplicationGraph接口的实现:DaggerApplicationGraph

    // Create an instance of the application graph
    val applicationGraph: ApplicationGraph = DaggerApplicationGraph.create()
    // Grab an instance of UserRepository from the application graph
    val userRepository: UserRepository = applicationGraph.repository()

    Above are the basics of constructor injection using Dagger2.

    上面是使用Dagger2进行构造函数注入的基础。

    开始在Android中使用Dagger2(现场注入) (Start Working with Dagger2 in Android (Field Injection))

    Adding dependencies

    添加依赖

    apply plugin: 'kotlin-kapt'
    
    
    ...
    
    
    dependencies {
      implementation 'com.google.dagger:dagger:2.x'
      kapt 'com.google.dagger:dagger-compiler:2.x'
    }

    Consider an example Android app with the dependency graph : -

    考虑带有依赖关系图的示例Android应用程序:-

    Image for post

    Because certain Android framework classes such as activities and fragments are instantiated by the system, Dagger can’t create them for you. For activities specifically, any initialization code needs to go into the onCreate() method. That means you cannot use the @Inject annotation in the constructor of the class (constructor injection) as you did in the previous examples. Instead, you have to use field injection.

    由于某些Android框架类(例如活动和片段)是由系统实例化的,因此Dagger无法为您创建它们。 对于特定的活动,任何初始化代码都需要放入onCreate()方法中。 这意味着您不能像前面的示例中那样在类的构造函数(构造函数注入)中使用@Inject批注。 相反,您必须使用场注入。

    class LoginActivity: Activity() {    
        // You want Dagger to provide an instance of LoginViewModel from the graph
        @Inject lateinit var loginViewModel: LoginViewModel
       }

    Dagger needs to know that LoginActivity has to access the graph in order to provide the ViewModel it requires.

    Dagger需要知道LoginActivity必须访问图形才能提供所需的ViewModel。

    In this case, you need to tell Dagger about an object (LoginActivity in this case) that requires a dependency to be injected. For that, you expose a function that takes as a parameter the object that requests injection.

    在这种情况下,您需要告诉Dagger有关需要注入依赖项的对象(在这种情况下为LoginActivity)。 为此,您公开了一个函数,该函数将请求注入的对象作为参数。

    @Component
    interface ApplicationComponent {
        // This tells Dagger that LoginActivity requests injection so the graph needs to
        // satisfy all the dependencies of the fields that LoginActivity is requesting.
        fun inject(activity: LoginActivity)
    }

    Note — When using activities, inject Dagger in the activity’s onCreate() method before calling super.onCreate() to avoid issues with fragment restoration. During the restore phase in super.onCreate(), an activity attaches fragments that might want to access activity bindings.

    注—使用活动时,请在调用super.onCreate()之前将Dagger插入活动的onCreate()方法中,以避免片段恢复问题。 在super.onCreate()的还原阶段,活动会附加可能要访问活动绑定的片段。

    When using fragments, inject Dagger in the fragment’s onAttach() method. In this case, it can be done before or after calling super.onAttach().

    使用片段时,将Dagger插入片段的onAttach()方法中。 在这种情况下,可以在调用super.onAttach()之前或之后完成。

    class LoginActivity: Activity() {
          // You want Dagger to provide an instance of LoginViewModel from the graph
          @Inject lateinit var loginViewModel: LoginViewModel
    	override fun onCreate(savedInstanceState: Bundle?) {
    	// Make Dagger instantiate @Inject fields in LoginActivity
    	 (applicationContext as MyApplication).appComponent.inject(this)
    	 // Now loginViewModel is available
    	 super.onCreate(savedInstanceState)
       	 }
    }
    // @Inject tells Dagger how to create instances of LoginViewModel
    class LoginViewModel @Inject constructor(
       private val userRepository: UserRepository
    ) { ... }

    Let’s tell Dagger how to provide the rest of the dependencies to build the graph:

    让我们告诉Dagger如何提供其余的依赖关系来构建图形:

    class UserRepository @Inject constructor(
        private val localDataSource: UserLocalDataSource,
        private val remoteDataSource: UserRemoteDataSource
    ) { ... }
    class UserLocalDataSource @Inject constructor() { ... }
    class UserRemoteDataSource @Inject constructor(
        private val loginService: LoginRetrofitService
    ) { ... }

    Note: — All injected constructor, fields and methods should not be private.

    注意:—所有注入的构造函数,字段和方法都不应该是私有的。

    Dagger Modules

    匕首模块

    Apart from the @Inject annotation, there’s another way to tell Dagger how to provide an instance of a class: the information inside Dagger modules. A Dagger module is a class that is annotated with @Module. There, you can define dependencies with the @Provides annotation.

    除了@Inject批注之外,还有另一种告诉Dagger如何提供类实例的方法:Dagger模块内部的信息。 Dagger模块是用@Module注释的类。 在那里,您可以使用@Provides批注定义依赖关系。

    // @Module informs Dagger that this class is a Dagger Module
    @Module
    class NetworkModule {
        // @Provides tell Dagger how to create instances of the type that this function
        // returns (i.e. LoginRetrofitService).
        // Function parameters are the dependencies of this type.
        @Provides
        fun provideLoginRetrofitService(): LoginRetrofitService {
    	 // Whenever Dagger needs to provide an instance of type LoginRetrofitService,
    	 // this code (the one inside the @Provides method) is run.
    	 return Retrofit.Builder()
    		 .baseUrl("https://example.com")
    		 .build()
    		 .create(LoginService::class.java)
        }
    }

    In order for the Dagger graph to know about this module, you have to add it to the @Component interface as follows:

    为了使Dagger图了解此模块,必须将其添加到@Component接口,如下所示:

    // The "modules" attribute in the @Component annotation tells Dagger what Modules
    // to include when building the graph
    @Component(modules = [NetworkModule::class])
    interface ApplicationComponent {
        ...
    }

    Note: — You can also use @Binds annotation in place of @Provides but @Binds work with an abstract method.

    注意:—您也可以使用@Binds批注代替@Provides,但是@Binds使用抽象方法。

    Dagger subcomponents

    匕首子组件

    If your login flow (managed by a single LoginActivity) consists of multiple fragments, you should reuse the same instance of LoginViewModel in all fragments. @Singleton cannot annotate LoginViewModel to reuse the instance for the following reasons:

    如果您的登录流(由单个LoginActivity管理)包含多个片段,则应在所有片段中重用LoginViewModel的相同实例。 由于以下原因,@ Singleton无法注释LoginViewModel重用实例:

    The instance of LoginViewModel would persistent in memory after the flow has finished.

    流完成后,LoginViewModel实例将在内存中保留。

    You want a different instance of LoginViewModel for each login flow. For example, if the user logs out, you want a different instance of LoginViewModel, rather than the same instance as when the user logged in for the first time.

    您需要每个登录流的LoginViewModel的不同实例。 例如,如果用户注销,则需要其他LoginViewModel实例,而不是与用户首次登录时相同的实例。

    To scope LoginViewModel to the lifecycle of LoginActivity you need to create a new component (a new subgraph) for the login flow and a new scope.

    要将LoginViewModel的范围限定为LoginActivity的生命周期,您需要为登录流程和新的范围创建一个新组件(一个新的子图)。

    Let’s create a graph specific to the login flow.

    让我们创建一个特定于登录流程的图形。

    // @Subcomponent annotation informs Dagger this interface is a Dagger Subcomponent
    @Subcomponent
    interface LoginComponent {
        // This tells Dagger that LoginActivity requests injection from LoginComponent
        // so that this subcomponent graph needs to satisfy all the dependencies of the
        // fields that LoginActivity is injecting
        fun inject(loginActivity: LoginActivity)
    }

    LoginComponent must be able to access the objects from ApplicationComponent because LoginViewModel depends on UserRepository. The way to tell Dagger that you want a new component to use part of another component is with Dagger subcomponents. The new component must be a subcomponent of the component containing shared resources.

    LoginComponent必须能够从ApplicationComponent访问对象,因为LoginViewModel取决于UserRepository。 告诉Dagger您希望新组件使用其他组件的一部分的方法是使用Dagger子组件。 新组件必须是包含共享资源的组件的子组件。

    You also must define a subcomponent factory inside LoginComponent so that ApplicationComponent knows how to create instances of LoginComponent.

    您还必须在LoginComponent内定义一个子组件工厂,以便ApplicationComponent知道如何创建LoginComponent的实例。

    @Subcomponent
    interface LoginComponent {
        // Factory that is used to create instances of this subcomponent
        @Subcomponent.Factory
        interface Factory {
    	 fun create(): LoginComponent
        }
        fun inject(loginActivity: LoginActivity)
    }

    To tell Dagger that LoginComponent is a subcomponent of ApplicationComponent, you have to indicate it by:

    要告诉Dagger LoginComponent是ApplicationComponent的子组件,必须通过以下方式指示它:

    • Creating a new Dagger module (e.g. SubcomponentsModule) passing the subcomponent’s class to the subcomponents attribute of the annotation.

      创建一个新的Dagger模块(例如SubcomponentsModule),将子组件的类传递给注释的subcomponents属性。
    // The "subcomponents" attribute in the @Module annotation tells Dagger what
    // Subcomponents are children of the Component this module is included in.
    @Module(subcomponents = LoginComponent::class)
    class SubcomponentsModule {}
    • Adding the new module (i.e. SubcomponentsModule) to ApplicationComponent:

      将新模块(即SubcomponentsModule)添加到ApplicationComponent中:
    // Including SubcomponentsModule, tell ApplicationComponent that
    // LoginComponent is its subcomponent.
    @Singleton
    @Component(modules = [NetworkModule::class, SubcomponentsModule::class])
    interface ApplicationComponent {
    }
    • Expose the factory that creates instances of LoginComponent in the interface:

      公开在界面中创建LoginComponent实例的工厂:
    @Singleton
    @Component(modules = [NetworkModule::class, SubcomponentsModule::class])
    interface ApplicationComponent {
    // This function exposes the LoginComponent Factory out of the graph so consumers
    // can use it to obtain new instances of LoginComponent
    fun loginComponent(): LoginComponent.Factory
    }

    You can use the ApplicationComponent to get a reference to LoginComponent and then inject LoginActivity as follows:

    您可以使用ApplicationComponent获取对LoginComponent的引用,然后按如下所示注入LoginActivity:

    class LoginActivity: Activity() {
    	// Reference to the Login graph
        lateinit var loginComponent: LoginComponent
        // Fields that need to be injected by the login graph
        @Inject lateinit var loginViewModel: LoginViewModel
        override fun onCreate(savedInstanceState: Bundle?) {
    	 // Creation of the login graph using the application graph
    	 loginComponent = (applicationContext as MyDaggerApplication)
    					appComponent.loginComponent().create()
    	// Make Dagger instantiate @Inject fields in LoginActivity
    	 loginComponent.inject(this)
    	 // Now loginViewModel is available
    	 super.onCreate(savedInstanceState)
        }
    }

    Now, if you had two fragments that need LoginViewModel, both of them are provided with the same instance. For example, if you have a LoginUsernameFragment and a LoginPasswordFragment they need to get injected by the LoginComponent:

    现在,如果您有两个需要LoginViewModel的片段,则它们都具有相同的实例。 例如,如果您有一个LoginUsernameFragment和LoginPasswordFragment,则它们需要由LoginComponent注入:

    @ActivityScope
    @Subcomponent
    interface LoginComponent {
        @Subcomponent.Factory
        interface Factory {
    	fun create(): LoginComponent
        }
        // All LoginActivity, LoginUsernameFragment and LoginPasswordFragment
        // request injection from LoginComponent. The graph needs to satisfy
        // all the dependencies of the fields those classes are injecting
        fun inject(loginActivity: LoginActivity)
        fun inject(usernameFragment: LoginUsernameFragment)
    }

    The components access the instance of the component that lives in the LoginActivity object. Example code for LoginUserNameFragment appears in the following code snippet:

    组件访问位于LoginActivity对象中的组件实例。 以下代码段中显示了LoginUserNameFragment的示例代码:

    class LoginUsernameFragment: Fragment() {
    	// Fields that need to be injected by the login graph
        @Inject lateinit var loginViewModel: LoginViewModel
        override fun onAttach(context: Context) {
    	 super.onAttach(context)
    	// Obtaining the login graph from LoginActivity and instantiate
    	// the @Inject fields with objects from the graph
    	 (activity as LoginActivity).loginComponent.inject(this)
    	 // Now you can access loginViewModel here and onCreateView too
    	 // (shared instance with the Activity and the other Fragment)
        }
    }

    These are the basics to start working with dagger in Android. There is a lot of things in dagger. The best way to learn Dagger is by playing with it.

    这些是开始在Android中使用匕首的基础知识。 匕首里有很多东西。 学习Dagger的最好方法是通过使用它。

    翻译自: https://medium.com/@nikitaverma081996/dependency-injection-in-android-6eca8d41ae17

    android 依赖注入

    展开全文
  • 自从 2009年 JSR 330 发布以后, Java 中的依赖注入框架就踏上了一个新台阶。由于 JSR 330 是一个通用的标准,所以只定义了依赖注入最基本的概念,这样各种依赖注入的实现框架可以在满足基本规范的基础上去做各种...
  • 主要介绍了Dagger2 Android依赖注入学习笔记,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
  • 因此官方也是为了让咱们更好使用依赖注入框架,为咱们封装了一个新的框架——Hilt,今天一块儿来看看:框架依赖注入是啥?为何须要她?Hilt是啥,怎么用?Hilt支持哪些类的依赖注入依赖注入是啥?为何须要她?简单...
  • Android 依赖注入

    2015-08-25 21:43:00
    Android 依赖注入 Dagger2 ![https://github.com/google/dagger](github托管地址) 1. 安装依赖: ```  compile 'com.google.dagger:dagger:2.0.1'  compile '...
  • Android依赖注入框架依赖注入的框架类型什么是控制反转——IOC(inversion of control)什么是DI(dependency injection)依赖注入IOC的优势IOC的缺点Hilt如何使用step1配置应用程序step2 配置需要依赖注入的类step...
  • Android依赖注入框架选型

    千次阅读 2019-05-24 04:53:40
    说到Android依赖注入框架,网上比较推崇的是google维护的Dagger2框架,使用依赖注入可以带来以下好处: 1、依赖的注入和配置独立于组件之外。2、因为对象是在一个独立、不耦合的地方初始化,所以当注入抽象方法的...
  • Android依赖注入-Hilt

    2020-12-26 23:03:08
    将依赖关系传递给其他对象或框架,其中方法依赖就是依赖注入,在Android中有两种主要的依赖注入方式分别是构造函数注入和字段注入(setter注入) 依赖注入方式: (1)人工依赖注入:人工编写大量样板代码 (2)自动...
  • Android依赖注入: Dagger (Part 1)在这篇文章中我将会解释什么是依赖注入,它的主要目的是什么,如何在Android项目中通过Dagger来完成依赖注入,Dagger是我认为Android中最好的依赖注入实现.这篇文章将会接着我上一篇...
  • android依赖注入注解的实现

    千次阅读 2017-04-01 15:06:54
    android依赖注入,注解功能,本demo实现view注入,点击事件注入. 首先实现两个注解类: @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface InjectView { //只接收一个int类型的...
  • Android依赖注入:Dagger(Part 3)如果你一直跟着阅读这个系列,那么你已经读过了依赖注入基本知识和依赖注入基础.这篇是最后一篇,将会讲scoped object graphs(指定域的对象图表).Dagger的指定域对象图表有什么用?当...
  • Android依赖注入: Dagger (Part 2)如果你读了依赖注入的第一篇文章,那么你可能正在寻找一些真实的代码.这里有一些不错的例子,coffee makers at Dagger page,还有一个特别好的model project by Jake Wharton适合有...
  • 在开发的过程中....这时候就体现了依赖注入的好处,如果还不太明白什么是依赖注入,请参考: 依赖注入daggerdagger的用途就是 你不用初始化对象,达到成员变量申明就能用.dagger通过依赖注入构建对象图
  • 为什么需要依赖注入? 答:解耦。 解谁和谁的耦? 解对象创建与对象使用的耦。 如何理解? 此处引出两个概念:IoC容器、DI依赖注入,我们将对象的创建过程、销毁过程交给IoC容器(称为控制反转),在需要...
  • 关于依赖注入(Dependency Injection,简称DI)类和类之间要建立联系,比如A类需要B类的实例对象,我们就说A类依赖B类,反过来,就说B类注入到A类中,所以“依赖注入”表示两层含义,依赖和注入。View层面的DI看了两...
  • Android 依赖注入框架 Dagger2使用

    千次阅读 2016-06-15 08:00:03
    前言Dagger 2这个匕首确实很难上手,上手后又比较难瞬间掌握,可以这么说,刚...它毕竟是一个依赖注入DI框架,Spring在服务器开发中起到的作用相信它也能。在了解使用前,先了解概念,什么是控制反转,什么是依赖注入
  • 依赖注入(DependencyInjection):在类A中要用到一个B的对象(依赖),需要通过新建B的实例或其他一些主动的方式来获取对象,然后才能调用。而通过外部的方式自动将B的对象分配给A(注入),实现相对被动的获取对象,...
  • 简介最近Dagger这套android依赖注入框架比较多人关注,感觉跟后端Spring 框架的IOC差不多。这个框架它的好处是它没有采用反射技术(Android 中的Butterknife和后端的Spring都是用反射),而是用预编译技术,因为...
  • 很多做过安卓的人都会用到最当下最流行的框架dragger2 和ButterKnife,这些依赖注入框架用起来非常方便,并且解耦,现在看看java依赖注入的简单用法,它的底层还是注解和反射,呵呵呵。所以java的反射是多么的重要先...
  • 1.依赖注入 (Dependency Injection) 1.1 面向接口编程 public interface Drivable { void drive(); } public class Bike implements Drivable { @Override public void drive() { System.out.println("骑车"); ...
  • 依赖注入是从应用程序的角度在描述,可以把依赖注入描述完整点:应用程序依赖容器创建并注入它所需要的外部资源;而控制反转是从容器的角度在描述,描述完整点:容器控制应用程序,由容器反向的向应用程序注入应用...
  • Java/Android依赖注入

    2016-02-24 20:43:30
    Dagger 是一种Android平台的依赖注入框架,是有一家专注于移动支付的公司,Square公司推出的库。 特性 使用 JSR-330标准注解进行构造器注入 使用@Provides注解创建对象 针对依赖树的中心...
  • 转载并修改自,天天博客 ...http://frogermcs.github.io/dependency-injection-with-dagger-2-the-api/关于Dagger2的作用,以及依赖注入就不做介绍了,下面这边文章介绍的很好: http://frogermc
  • 依赖注入 面向对象编程的一种设计模式,目的是为了降低程序中类与类之间的依赖引起的耦合。 在Java中,依赖注入有 通过接口注入 通过set方法注入 通过构造方法注入 通过注解注入 Dagger2 官网 为...
  • dagger2 注入In this tutorial, we’ll discuss and implement Dependency Injection (DI) in our android application. For those of you who have used DI in the past (possibly in Spring), the following ...
  • 依赖注入是从应用程序的角度在... Dagger1是Android上最流行的依赖注入框架。它是由Square公司受到Guice启发创建的。Dagger2是Dagger1的分支,由谷歌公司接手开发,目前的版本是2.2。Dagger2是受到AutoValue项目的启发
  • Android 依赖注入函数库Roboguice(一)

    千次阅读 2014-11-17 15:11:51
    Roboguice是一个用于Android应用的依赖注入框架,使用Google官方的Guice库位极大地简化了Android依赖注入。使用他使编程变得更加简单有趣。 使用Roboguice需要几个jar点击下载 下载知道导入到自己的项目中 使用...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 27,038
精华内容 10,815
关键字:

安卓依赖注入