使用匕首在ContentProvider中注入数据库

时间:2014-05-07 14:47:21

标签: android dagger

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

5 个答案:

答案 0 :(得分:7)

简单解决方案

  

这有一个简单的原因,onCreate()提供程序被调用   在应用程序中的适当方法之前。您可以   在另一个方法中创建一个组件   应用程序,例如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的inject OnCreatepublic boolean onCreate() { YourMainApplication.get(getContext()).getComponent().inject(this); return true; }

def appendCount(l: List[String]): List[String] = {
  // Since we're doing zero-based counting, we need to use `getOrElse(e, -1) + 1`
  // to indicate a first-time element count as 0. 
  val counts = 
    l.foldLeft(Map[String, Int]())((acc, e) => 
      acc + (e -> (acc.getOrElse(e, -1) + 1))
    )

  val (appendedList, _) = 
    l.foldRight(List[String](), counts){ case (e, (li, m)) =>
      // Prepend the element with its count to the accumulated list.
      // Decrement that element's count within the map of element counts
      (s"$e${m(e)}" :: li, m + (e -> (m(e) - 1)))
    }
  appendedList
}

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

答案 1 :(得分:6)

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

来自内容提供商的onCreate documentation

  

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

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

答案 2 :(得分:6)

正如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);
}

}

答案 3 :(得分:0)

基于@Mick答案和@LeEnot文章,我在Diddle上发布了一篇使用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)
    }

}

并将我的databaseHelper实例注入到我的ContentProvider类中:

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

答案 4 :(得分:0)

我知道问题已经有了答案,但是我发表经验希望这对某人有帮助

我添加了一个名为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)
}