【问题标题】:Inject database in a ContentProvider with dagger用匕首在 ContentProvider 中注入数据库
【发布时间】:2014-05-07 14:47:21
【问题描述】:

我想在ContentProvider 中注入一个单例SqliteOpenHelper。但是,似乎 ContentProvider 实例是在创建 Application 实例之前构建的(getApplicationContext() 返回 null)。什么时候可以注入数据库?我已经在构造函数和ContentProvideronCreate() 方法中尝试过。

【问题讨论】:

    标签: android dagger


    【解决方案1】:

    简单的解决方案

    这有一个简单的原因,onCreate() provider 被调用 在应用程序中的适当方法之前。你可以 用另一种方法创建组件 应用程序,例如attachBaseContext


    1 将您的逻辑从您的应用程序中的onCreate 移动到attachBaseContext

    @Override
    public void attachBaseContext(Context base){
    
        super.attachBaseContext(base);
    
        mApplicationComponent = DaggerApplicationComponent.builder()
                .applicationModule(new ApplicationModule(this))
                .build();
        mApplicationComponent.inject(this);
    }
    

    2 您现在可以在 ContentProvider 中的 injectOnCreate

    public boolean onCreate() {
    
        YourMainApplication.get(getContext()).getComponent().inject(this);
    
        return true;
    }
    

    免责声明: 来自此俄罗斯博客的@LeEnot 的全部功劳:Dagger2 Inject in Content Provider。为方便起见,此处列出了答案,因为它没有英文版本。

    【讨论】:

    • 这是最好的方法。我使用的是最上面的,有时组件为空,然后导致错误`原因:java.lang.NullPointerException:尝试调用接口方法'void info....LiteComponent.inject(info.... .LiteContentProvider)' 在空对象引用上`
    【解决方案2】:

    基于@Mick 的回答和@LeEnot 文章,我在 Medium 上发布了一篇使用 Dagger 2 新功能的文章。

    https://medium.com/@pedro.henrique.okawa/content-providers-dependency-injection-dagger-2-4ee3e49777b

    但基本上我把 Dagger-Android 依赖:

    // In my case I used 2.16 version
    implementation 'com.google.dagger:dagger-android:[DaggerVersion]'
    

    使用 HasContentProviderInjector 接口实现了我的自定义 Application 类,并更改为在 attachBaseContext 上注入我的依赖项:

    class App : Application(), HasActivityInjector, HasContentProviderInjector {
    
        @Inject
        lateinit var androidInjector: DispatchingAndroidInjector<Activity>
    
        @Inject
        lateinit var contentProviderInjector: DispatchingAndroidInjector<ContentProvider>
    
        override fun activityInjector() = androidInjector
    
        override fun contentProviderInjector() = contentProviderInjector
    
        override fun attachBaseContext(base: Context?) {
            super.attachBaseContext(base)
            setupDependencyInjection()
        }
    
        /**
         * Injects the app component
         */
        private fun setupDependencyInjection() {
            DaggerAppComponent.builder().application(this).build().inject(this)
        }
    
    }
    

    并在我的 ContentProvider 类上注入了我的 databaseHelper 实例:

    class VoIPAppProvider: ContentProvider() {
    
        @Inject
        lateinit var databaseHelper: DatabaseHelper
    
        override fun onCreate(): Boolean {
            AndroidInjection.inject(this)
            return true
        }
    
        override fun insert(uri: Uri?, contentValues: ContentValues?): Uri? {
            ...
            return uri
        }
    
        override fun query(uri: Uri?, projection: Array<out String>?, selection: String?, selectionArgs: Array<out String>?, sortOrder: String?): Cursor {
            ...
            return cursor
        }
    
        override fun getType(uri: Uri?): String {
            ...
            return type
        }
        override fun update(uri: Uri?, contentValues: ContentValues?, selection: String?, selectionArgs: Array<out String>?): Int {
            ...
            return rowsUpdated
        }
    
        override fun delete(uri: Uri?, selection: String?, selectionArgs: Array<out String>?): Int {
            ...
            return rowsDeleted
        }
    }
    

    PS:我决定不使用 DaggerContentProvider 类,因为我们大多数人可能已经有一些 Android 组件的基类。

    希望对您有所帮助,再次感谢@Mick 和@LeEnot

    【讨论】:

    【解决方案3】:

    正如 Alex Baker 所指出的,该问题的解决方案是在第一次调用操作(查询、插入、更新、删除)时推迟注入。

    举个例子:

    这行不通:

    public class YourProviderNull extends ContentProvider {
    
    
    @Inject
    YourSQLHelper yourHelper;
    
    
    @Override
    public boolean onCreate() {
        YourActivity.getComponent().inject(this); //NPE!!!
        //other logic
        return true;
    }
    
    @Override
    public Cursor query(@NonNull Uri uri, String[] projection, String selection, String[] selectionArgs,
                        String sortOrder) {
        SQLiteDatabase db = yourHelper.getReadableDatabase();
        //other logic
    }
    
    
    @Override
    public Uri insert(@NonNull Uri uri, ContentValues values) {
        SQLiteDatabase db = yourHelper.getWritableDatabase();
        //other logic
    }
    
    @Override
    public int delete(@NonNull Uri uri, String selection, String[] selectionArgs) {
        SQLiteDatabase db = yourHelper.getWritableDatabase();
        //other logic
    }
    
    @Override
    public int update(@NonNull Uri uri, ContentValues values, String selection, String[] selectionArgs) {
        SQLiteDatabase db = yourHelper.getWritableDatabase();
        //other logicreturn db.update(resolveTableNameForUri(uri), values, selection, selectionArgs);
    }
    

    }

    但这会正常工作:

    public class YourProviderWorking extends ContentProvider {
    
    
    @Inject
    YourSQLHelper yourHelper;
    
    
    @Override
    public boolean onCreate() {
    
        //other logic
        return true;
    }
    
    @Override
    public Cursor query(@NonNull Uri uri, String[] projection, String selection, String[] selectionArgs,
                        String sortOrder) {
        if(yourHelper == null){
            deferInit();
        }
        SQLiteDatabase db = yourHelper.getReadableDatabase();
        //other logic
    }
    
    
    @Override
    public Uri insert(@NonNull Uri uri, ContentValues values) {
        if(yourHelper == null){
            deferInit();
        }
        SQLiteDatabase db = yourHelper.getWritableDatabase();
        //other logic
    }
    
    @Override
    public int delete(@NonNull Uri uri, String selection, String[] selectionArgs) {
        if(yourHelper == null){
            deferInit();
        }
        SQLiteDatabase db = yourHelper.getWritableDatabase();
        //other logic
    }
    
    @Override
    public int update(@NonNull Uri uri, ContentValues values, String selection, String[] selectionArgs) {
        if(yourHelper == null){
            deferInit();
        }
        SQLiteDatabase db = yourHelper.getWritableDatabase();
        //other logicreturn db.update(resolveTableNameForUri(uri), values, selection, selectionArgs);
    }
    
    private void deferInit(){
        YourActivity.getComponent().inject(this);
    }
    

    }

    【讨论】:

    • 这是一个很好的洞察力。您也可以在 deferInit() 中执行条件,然后在任何地方进行方法调用。
    • 活动对内容提供者意味着什么??
    【解决方案4】:

    我遇到了同样的问题,不得不推迟注入,直到需要数据库。你或许可以使用 Dagger 的lazy injection 来达到同样的效果。

    来自内容提供者的onCreate documentation

    您应该将重要的初始化(例如打开、升级和扫描数据库)推迟到使用内容提供程序之前

    显然,这个建议不容忽视。 Implementing the onCreate() method 提供了一个使用 SQLiteOpenHelper 和内容提供程序的示例。

    【讨论】:

    • 能否请您说一下您是如何延迟注入的,我试图注入我的应用程序类,该类引用了一个 sqlite 数据库,但无济于事。尝试在调用内容提供者的 Insert、Query 等方法时注入它,但没有成功,并且字段注入不起作用。
    • @sparrow 您可以将惰性字段添加到您的内容提供程序,将它们注入 onCreate,并在插入、查询等内部的惰性字段上使用 get() 方法。这是我的应用程序中的一个示例github.com/tasks/tasks/blob/…
    【解决方案5】:

    我知道这个问题已经有了答案,但我发布了我的经验希望这对某人有所帮助

    我添加了一个名为 ContentProviderBuilder 的模块:

    @Module
    abstract class ContentProviderBuilder {
    
    @ActivityScope
    @ContributesAndroidInjector
    abstract fun myCustomSuggestionProvider(): MyCustomSuggestionProvider?
    }
    

    然后我将此模块添加到我的组件中,并从 DaggerContentProvider 扩展了 contentProvider

    您必须将super.onCreate 添加到您的cotnentProvider 中,就是这样

    这是我的组件:

    @Singleton
    @ApplicationScope
    @Component(modules = [AppModule::class, AndroidSupportInjectionModule::class, 
    RemoteModule::class, ContentProviderBuilder::class, ActivityBuilder::class, 
    FragmentBuilder::class, ViewModelModule::class])
    interface ApplicationComponent: AndroidInjector<MyApplication> {
    
    @Component.Builder
    interface Builder {
    
        @BindsInstance
        fun application(application: MyApplication): Builder
    
        fun build(): ApplicationComponent
    }
    
    override fun inject(app: MyApplication)
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多