2014-05-07 15 views
7

Tôi muốn tiêm một singleton SqliteOpenHelper vào một số ContentProvider. Tuy nhiên, có vẻ như cá thể ContentProvider đang được tạo trước khi cá thể Ứng dụng đang được tạo (getApplicationContext() trả về null). Khi nào tôi có thể tiêm cơ sở dữ liệu? Tôi đã thử trong hàm tạo và trong phương thức onCreate() của ContentProvider.Tiêm cơ sở dữ liệu trong Trình ContentProvider với dao găm

Trả lời

5

Tôi phải đối mặt với cùng một vấn đề và phải trì hoãn việc tiêm cho đến khi có cơ sở dữ liệu. Bạn có thể sử dụng lazy injection của Dagger để đạt được hiệu quả tương tự.

Từ nhà cung cấp nội dung của onCreate documentation:

Bạn nên trì hoãn việc khởi tạo không tầm thường (ví dụ như mở cửa, nâng cấp, và cơ sở dữ liệu quét) cho đến khi các nhà cung cấp nội dung được sử dụng

Rõ ràng đề nghị này không thể bỏ qua . Implementing the onCreate() method cung cấp một ví dụ bằng cách sử dụng một SQLiteOpenHelper với một nhà cung cấp nội dung.

+0

bạn có thể vui lòng nói cách bạn trì hoãn việc tiêm, tôi đã cố gắng tiêm lớp Ứng dụng của tôi có tham chiếu đến cơ sở dữ liệu sqlite không có kết quả. đã thử tiêm nó khi gọi các phương thức chèn, truy vấn, vv của nhà cung cấp nội dung mà không thành công và việc tiêm trường sẽ không hoạt động. – irobotxxx

+0

@sparrow Bạn có thể thêm các trường lười vào nhà cung cấp nội dung của bạn, tiêm chúng vào onCreate và sử dụng phương thức get() trên trường lười bên trong chèn, truy vấn, v.v. Đây là ví dụ từ ứng dụng của tôi https://github.com /tasks/tasks/blob/7ff1ba5fbe9aa851f1e7d003c415c7463945ffcc/src/main/java/com/todoroo/astrid/provider/Astrid3ContentProvider.java –

4

Như Alex Baker đã chỉ ra, giải pháp của vấn đề là trì hoãn việc tiêm khi một hoạt động (truy vấn, chèn, cập nhật, xóa) được gọi lần đầu tiên.

để làm một ví dụ:

này sẽ không làm việc:

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

}

nhưng điều này sẽ làm việc một cách chính xác:

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

}

+0

Đây là thông tin chi tiết tuyệt vời. Bạn cũng có thể làm điều kiện bên trong deferInit() và bạn chỉ cần thực hiện một lời gọi phương thức ở khắp mọi nơi. –

4

Simple Soluti trên

Có một lý do đơn giản cho việc này, nhà cung cấp onCreate() được gọi là trước phương pháp thích hợp trong Đơn đăng ký. Bạn có thể tạo một thành phần theo phương pháp khác của ứng dụng , ví dụ: attachBaseContext.


Di chuyển logic của bạn từ onCreate để attachBaseContext trong ứng dụng của bạn.

@Override 
public void attachBaseContext(Context base){ 

    super.attachBaseContext(base); 

    mApplicationComponent = DaggerApplicationComponent.builder() 
      .applicationModule(new ApplicationModule(this)) 
      .build(); 
    mApplicationComponent.inject(this); 
} 

Bạn có thể bây giờ inject trong OnCreate trong ContentProvider của bạn:

public boolean onCreate() { 

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

    return true; 
} 

Disclaimer: Tín Full để @LeEnot từ blog Nga này: Dagger2 Inject in Content Provider. Câu trả lời được liệt kê ở đây để thuận tiện vì nó không có sẵn bằng tiếng Anh.

+1

Đây là cách tiếp cận tốt nhất. Tôi đã sử dụng một trong những đầu, và tại thời điểm thành phần là null, sau đó gây ra một lỗi 'Gây ra bởi: java.lang.NullPointerException: Cố gắng gọi phương thức giao diện 'void thông tin .... LiteComponent.inject (thông tin .... .LiteContentProvider) 'trên tham chiếu đối tượng null' –

Các vấn đề liên quan