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

Cat*_*san 10 android dagger

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

Mic*_*ick 9

简单解决方案

这有一个简单的原因,onCreate()在Application中的相应方法之前调用提供程序.例如,您可以在Application的另一个方法中创建组件attachBaseContext.


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

@Override
public void attachBaseContext(Context base){

    super.attachBaseContext(base);

    mApplicationComponent = DaggerApplicationComponent.builder()
            .applicationModule(new ApplicationModule(this))
            .build();
    mApplicationComponent.inject(this);
}
Run Code Online (Sandbox Code Playgroud)

2现在,您可以injectOnCreate您的ContentProvider:

public boolean onCreate() {

    YourMainApplication.get(getContext()).getComponent().inject(this);

    return true;
}
Run Code Online (Sandbox Code Playgroud)

免责声明:来自俄罗斯博客 @LeEnot的完全信誉:内容提供商中的Dagger2 Inject.为方便起见,此处列出了答案,因为它没有英文版本.

  • 这是最好的方法。我正在使用最上面的一个,有时组件为空,然后导致错误` 引起:java.lang.NullPointerException: Attempt to invoke interface method 'void info....LiteComponent.inject(info.... .LiteContentProvider)' 在一个空对象引用上` (2认同)

Ale*_*ker 6

我遇到了同样的问题,不得不推迟注射,直到需要数据库.您可以使用Dagger的懒惰注射来达到相同的效果.

来自内容提供商的onCreate文档:

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

显然这个建议不能被忽视.实现onCreate()方法提供了一个使用SQLiteOpenHelper和内容提供程序的示例.


Noy*_*oya 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);
}
Run Code Online (Sandbox Code Playgroud)

}

但这将正常工作:

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);
}
Run Code Online (Sandbox Code Playgroud)

}

  • 这是很棒的见识。您也可以在deferInit()中执行条件,并且只需在各处进行方法调用即可。 (2认同)