首页 > 解决方案 > 如何在android中使用Dagger在类中进行单例注入

问题描述

有负责管理数据库的 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 服务并将响应保存在数据库中。注入不起作用,它始终为空:

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 在评论中的问题: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;
     }

标签: javaandroiddependency-injectiondagger

解决方案


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).
}

推荐阅读