java - 如何在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;
}
解决方案
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).
}
推荐阅读
- r - 需要帮助创建一个循环,在 group_by() 之后将列名输入 transmute()
- php - 如何在结构化 PHP 中使用 bind_param 和 MySQL NOW () 函数更新字段?
- laravel - Laravel:在文件中调用成员函数 store()
- php - 我的服务器 Laravel Cron 计划不起作用
- node.js - 将 api.listen 添加到 Express JS API 后找不到路由
- spring-boot - 我可以将 Spring Event listener 和 Event Publisher 作为单独的应用程序吗?
- php - 错误代码 500 phpMyAdmin:无法打开数据表
- scala - 在 scala 中绑定的类型之后的另一个子类型
- c# - Index.cshtml 中的有序表布局
- mysql - JDBC MySQL 身份验证