如何在android中使用Dagger在类中进行单例注入

Posted

技术标签:

【中文标题】如何在android中使用Dagger在类中进行单例注入【英文标题】:How to get a singleton injection in a class with Dagger in android 【发布时间】:2021-12-13 01:00:12 【问题描述】:

有负责管理数据库的DataAccessInterface类:

public class DataAccessInterface 

    private DaoSession daoSession;
    public DataAccessInterface () 
    
...
     public void saveCar (Car car) 
         daoSession.getCarDao (). insert (car);
     

DataAccessInterface 注入成功用于多个 Fragment。示例:

public class LoginFragment extends BaseFragment 
    @Inject
    DataAccessInterface dataAccessInterface;

...
    public boolean initDatabase () throws SyncDataBaseException 
        try 
            dataAccessInterface.openSession (currentUser.getUsername ());
         catch (Exception e) 
            throw new SyncDataBaseException ();
        
        return true;
    
...

有一个 BackendImp 类(无 Fragment 或 Activity)在后台查询一个 rest 服务并将响应保存在数据库中。注入不起作用,始终为null:

public class BackendImp 
    @Inject
    DataAccessInterface dataAccessInterface;

public void save () 
Car car = unloadCar ()
dataAccessInterface.saveCar (car);

AbstractActivityComponent 看起来像这样

@PerActivity
@Component (dependencies = ApplicationComponent.class, modules = ActivityModule.class)
public interface AbstractActivityComponent 

   Activity activity ();
    final class Initializer 
        public static AbstractActivityComponent init (Activity activity) 
            return DaggerAbstractActivityComponent.builder ()
                    .applicationComponent (DaggerManager.getInstance (). appComponent ())
                    .activityModule (new ActivityModule (activity))
                    .build ();
        
    
    void inject (LoginFragment inject);
    void inject (BackendImp inject);

应用模块:

@Module
public class ApplicationModule 
    private final Application application;
    private final User currentUser;

    public ApplicationModule (Application application) 
        this.application = application;
        this.currentUser = getUser ();
    
    @Provides
    @Singleton
    DataAccessInterface dataAccessInterface () 
        return new DataAccessInterface (userProfile ());
    

和应用组件

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

    void inject(Application application);

    final class Initializer 

        public static ApplicationComponent init(Application app) 
            return DaggerApplicationComponent.builder()
                    .applicationModule(new ApplicationModule(app))
                    .build();
        
    

    Application application();
    Context context();
    DataAccessInterface dataAccessInterface();

错误: W/System.err:java.lang.NullPointerException:尝试在空对象引用上调用虚拟方法“void com.service.DataAccessInterface.saveCar(Car)”

编辑:

基于 Nitrodon 在 cmets 中的问题: BackendImp 函数是从 Worker 调用的,因为它们每小时都会执行一次。我想要一个实例,所以我做了以下可能是错误的:

public class MainApp extends Application 

   public static BackendService backendService;

   @Override
   public void onCreate () 
         
      super.onCreate ();
      backendService = new BackendImp ();
  

  public static void callWorker () 
      ...
   
      workManager.enqueue (updateWorkRequest);
  

还有工人:

public class updateWorker extends Worker 
   ...

   @Override
   public Result doWork () 
         Result result = Result.retry ();

         try 
            backend = MainApp.backendService;
             backend.save ();
             result = Result.success ();
          catch (Exception e) 
             result = Result.retry ();
         
         return result;
     

【问题讨论】:

你如何获得BackendImp的实例? 非常好的观察。我没想到它会影响。我在 MainApp 中获得了一个新的 backendImp,然后我用它来调用它的函数。 backendService = new BackendImp ();那是问题吗?我该怎么做?我将使用缺少的代码编辑问题 【参考方案1】:

Dagger 不会挂接到构造函数调用。你必须告诉 Dagger 将依赖注入到BackendImp

您的活动组件中有一个inject(BackendImp inject) 方法。这会起作用,但它在错误的位置,因此您的应用程序类无法访问它。将此方法放在应用程序组件中会起作用:

   @Override
   public void onCreate () 
         
      super.onCreate ();
      backendService = new BackendImp();
      // I assume you created the application component somewhere in here.
      component.inject(backendService);
  

但是,成员注入方法通常在可以避免的情况下不鼓励使用。 Activity 子类没有其他选择,因为它们是由框架实例化的,但是像 BackendImp 这样的东西完全在你的控制之下,所以你可以而且应该让 Dagger 为你创建它。

为此,将BackendImp 本身放置在应用程序组件中,为其提供@Singleton 范围和@Inject 构造函数:

@Singleton
public class BackendImp 
    final DataAccessInterface dataAccessInterface;

    @Inject
    BackendImp(DataAccessInterface dataAccessInterface) 
        this.dataAccessInterface = dataAccessInterface;
    

    // ...


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

    // ...

    // Use this in your application instead of new BackendImp()
    BackendImp backendImp(); 

    // Many tutorials instead suggest making an @Inject field in
    // your application and calling inject(application).

【讨论】:

“将 BackendImp 本身放在应用程序组件中”是什么意思。全班?您能否提供一些参考,这将有助于更好地理解您的答案。

以上是关于如何在android中使用Dagger在类中进行单例注入的主要内容,如果未能解决你的问题,请参考以下文章

Android Dagger2简单入门

Android Dagger2简单入门

Android 仪器测试中的 Dagger 2 注入

Android Annotations生成类,但dagger2 @Module类无法访问这些类

android 怎么在类中添加滚动条

Android 常用开源框架源码解析 系列 dagger2 呆哥兔 依赖注入库