2011-01-18 10 views
6

Mi objetivo¿Cuál es el objetivo de ContentResolver.bulkInsert (..)?

quiero insertar varios registros en sqlite en lotes (transaccional).

Mi pregunta

He encontrado el método android.content.ContentResolver. bulkInsert (..) interesante pero los estados de javadoc:

Esta función no garantiza la atomicidad de las inserciones.

Por qué sería androide proporcionar un método que está paralizado? ¿Me puede nombrar usecases para inserciones no atómicas? Obviamente voy a anular ContentProvider.bulkInsert(..) para asegurar la atomicidad, así que no estoy seguro de por qué es una frase como esta.

Respuesta

1

Use applyBatch() en su lugar.

Esto le permite realizar muchas operaciones diferentes de una manera transaccional, sin embargo hay un impacto en el rendimiento de este fexibilidad.

La documentación pertinente se puede encontrar aquí en el ContentResolver SDK documentation

que he proporcionado un rápido tutorial sobre el uso de applybatch en the symantics of backReferences

También recomiendo mirar this question que discute anulando applyBatch

4

Necesitamos anula el método de inserción masiva como sigue ...

public class Provider extends ContentProvider { 
    public static final Uri URI = Uri.parse("content://com.example.android.hoge/"); 
    @Override 
    public String getType(Uri uri) { 
     return null; 
    } 
    @Override 
    public boolean onCreate() { 
     return false; 
    } 
    @Override 
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { 
     Helper helper = Helper.getInstance(getContext(), null); 
     SQLiteDatabase sdb = helper.getReadableDatabase(); 
     Cursor cursor = sdb.query(
       Table.TABLENAME, 
       new String[]{Table.ID, Table.DATA, Table.CREATED}, 
       selection, 
       selectionArgs, 
       null, 
       null, 
       sortOrder, 
       null 
     ); 
     return cursor; 
    } 
    @Override 
    public Uri insert(Uri uri, ContentValues values) { 
     Helper helper = Helper.getInstance(getContext(), null); 
     SQLiteDatabase sdb = helper.getWritableDatabase(); 
     sdb.insert(Table.TABLENAME, null, values); 
     getContext().getContentResolver().notifyChange(uri, null); 
     return uri; 
    } 

    /** 
    * super.bulkInsert is implemented the loop of insert without transaction 
    * So we need to override it and implement transaction. 
    */ 
    @Override 
    public int bulkInsert(Uri uri, ContentValues[] values) { 
     Helper helper = Helper.getInstance(getContext(), null); 
     SQLiteDatabase sdb = helper.getWritableDatabase(); 

     sdb.beginTransaction(); 
     SQLiteStatement stmt = sdb.compileStatement(
      "INSERT INTO `" + Table.TABLENAME + "`(`" + Table.DATA + "`, `" + Table.CREATED + "`) VALUES (?, ?);" 
     ); 
     int length = values.length; 
     for(int i = 0; i < length; i++){ 
      stmt.bindString(1, values[i].getAsString(Table.DATA)); 
      stmt.bindLong(2, values[i].getAsLong(Table.CREATED)); 
      stmt.executeInsert(); 
     } 
     sdb.setTransactionSuccessful(); 
     sdb.endTransaction(); 
     return length; 
    } 

    @Override 
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { 
     Helper helper = Helper.getInstance(getContext(), null); 
     SQLiteDatabase sdb = helper.getWritableDatabase(); 
     int rows = sdb.update(Table.TABLENAME, values, selection, selectionArgs); 
     getContext().getContentResolver().notifyChange(uri, null); 
     return rows; 
    } 

    @Override 
    public int delete(Uri uri, String selection, String[] selectionArgs) { 
     Helper helper = Helper.getInstance(getContext(), null); 
     SQLiteDatabase sdb = helper.getWritableDatabase(); 
     int rows = sdb.delete(Table.TABLENAME, selection, selectionArgs); 
     getContext().getContentResolver().notifyChange(uri, null); 
     return rows; 
    } 

    private static class Helper extends SQLiteOpenHelper { 
     static Helper INSTANCE = null; 
     private Helper(Context context, CursorFactory factory) { 
      super(context, Table.FILENAME, factory, Table.VERSION); 
     } 
     public static Helper getInstance(Context context, CursorFactory factory) { 
      if (INSTANCE == null) { 
       INSTANCE = new Helper(context, factory); 
      } 
      return INSTANCE; 
     } 
     @Override 
     public void onCreate(SQLiteDatabase db) { 
      db.execSQL(
       "CREATE TABLE `" + Table.TABLENAME + "`(" + 
       " `" + Table.ID  + "` INTEGER PRIMARY KEY AUTOINCREMENT," + 
       " `" + Table.CREATED + "` INTEGER," + 
       " `" + Table.DATA + "` TEXT" + 
       ");" 
      ); 
     } 
     @Override 
     public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 
     } 
    } 
} 
1

Esta función no ofrecen ninguna garantía sobre la atomicidad de las inserciones .

me corrija si estoy equivocado, pero esto es porque no tenemos ni idea de si el proveedor de contenido dado reemplaza el método bulkInsert() a menos que sea nuestro propio proveedor. Si no está anulado el método bulkInsert(), la aplicación por defecto será iterar sobre los valores y llamar insert(Uri, ContentValues) en cada uno de ellos. Que debería estar bien si está utilizando su propio proveedor y saber que ha implementado el método bulkInsert() como siguiente ejemplo y utilizar el método endTransaction() en bloque finally:

@Override 
    public int bulkInsert(Uri uri, ContentValues[] values) { 
     final SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 
     final int match = sUriMatcher.match(uri); 
     switch (match) { 
      case WEATHER: 
       db.beginTransaction(); 
       int returnCount = 0; 
       try { 
        for (ContentValues value : values) { 
         normalizeDate(value); 
         long _id = db.insert(WeatherEntry.TABLE_NAME, 
           null, value); 
         if (_id != -1) { 
          returnCount++; 
         } 
        } 
        db.setTransactionSuccessful(); 
       } finally { 
        db.endTransaction(); 
       } 
       getContext().getContentResolver().notifyChange(uri, null); 
       return returnCount; 
      default: 
       return super.bulkInsert(uri, values); 
     } 
    } 
0

primero Añadir método para inserción masiva en su proveedor de contenidos

@Override 
public int bulkInsert(@NonNull Uri uri, @NonNull ContentValues[] values) { 
    switch (uriMatcher.match(uri)) { 
     case USERS: 
      for (ContentValues value : values) { 
       long rowID = sqLiteDatabase.insert(YOUR_TABLENAME, "", value); 
       if (rowID > 0) { 
        Uri _uri = ContentUris.withAppendedId(CONTENT_URI, rowID); //append ID into CONTENT_URI 
        getContext().getContentResolver().notifyChange(_uri, null); 
        return values.length; //return total number of data inserted 
       } 
      } 
      break; 
    } 
    return super.bulkInsert(uri, values); 
} 

Añadir a continuación el código en el botón de clic (continuación se ejecuta para insertar datos en bloque)

  String userName = editTextUserName.getText().toString(); 
      String userCity = editTextUserCity.getText().toString(); 

      Log.d("BulkInsert", "onClick: -------START------"); 
      ContentValues[] contentValue = new ContentValues[5000]; 
      for (int i = 0; i < 5000; i++) { 

       contentValue[i] = new ContentValues(); // initialize Array of content values 

       //store data in content values object 
       contentValue[i].put(UserModel.USER_CITY, userCity); 
       contentValue[i].put(UserModel.USER_NAME, userName); 
       contentValue[i].put(UserModel.USER_PINCODE, userPincode); 
      } 
      int count = getContentResolver().bulkInsert(YOUR_TABLE_URI, contentValue); //insert data 
      Log.d("BulkInsert", "onClick: " + count); //Display number of data inserted 
      Log.d("BulkInsert", "onClick: -------STOP------"); 
Cuestiones relacionadas