기계적 인조 인간:ContentResolver 사용 시 SQLite 트랜잭션
문제
목표:XML 데이터에서 데이터베이스 새로 고침
과정:
- 거래 시작
- 삭제 테이블의 모든 기존 행
- 구문 분석된 XML의 각 주요 요소당 끼워 넣다 행을 메인 테이블에 넣고 PK를 얻습니다.
- 주요 요소의 각 하위 요소마다 끼워 넣다 이전 단계의 FK를 제공하는 두 번째 테이블에 기록
- 트랜잭션 커밋
DB 작업에 관한 한 꽤 표준적인 내용입니다.문제는 CRUD 작업이 내에서 수행되지 않는다는 것입니다. ContentProvider
하지만 오히려 사용 ContentResolver
예를 들어 삽입물은 다음과 같습니다. resolver.insert(CONTENT_URI, contentValues)
.ContentResolver API에는 트랜잭션과 관련된 내용이 없는 것 같아서 사용할 수 없습니다. bulkInsert
간헐적으로 2개의 테이블에 삽입하고 있기 때문에(게다가 delete
거래 내부에서도 마찬가지입니다).
맞춤형 등록을 하려고 생각 중이었는데 ContentProvider
리스너로 사용하여 registerContentObserver
하지만 그때부터 ContentResolver#acquireProvider
방법이 숨겨져 있습니다. 올바른 참조를 얻으려면 어떻게 해야 합니까?
나에게 운이 없는 걸까?
해결책
Google I/O 애플리케이션의 소스 코드에서 무시하고 있음을 알았습니다. ContentProvider
'에스 applyBatch()
방법과 그 안에 트랜잭션을 사용하십시오. 따라서 배치를 만듭니다 ContentProviderOperation
S와 전화하십시오 getContentResolver().applyBatch(uri_authority, batch)
.
이 접근 방식을 사용하여 작동 방식을 확인할 계획입니다. 다른 사람이 시도해도 궁금합니다.
다른 팁
kaciula가 언급한 것처럼 ContentProviderOperation을 사용하면 Android 2.1부터 트랜잭션 기반 다중 테이블 삽입을 깔끔하게 수행할 수 있습니다.
ContentProviderOperation 객체를 빌드할 때 .withValueBackReference(fieldName, refNr)를 호출할 수 있습니다.applyBatch를 사용하여 작업을 적용하면 insert() 호출과 함께 제공되는 ContentValues 객체에 정수가 주입됩니다.정수는 fieldName 문자열로 입력되며 해당 값은 refNr로 인덱싱된 이전에 적용된 ContentProviderOperation의 ContentProviderResult에서 검색됩니다.
아래 코드 샘플을 참조하세요.샘플에서는 table1에 행이 삽입되고, 결과 ID(이 경우 "1")는 table 2에 행을 삽입할 때 값으로 사용됩니다.간단히 말해서 ContentProvider는 데이터베이스에 연결되어 있지 않습니다.ContentProvider에는 트랜잭션 처리를 추가하는 데 적합한 인쇄물이 있습니다.
public class BatchTestActivity extends Activity {
/** Called when the activity is first created. */
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ArrayList<ContentProviderOperation> list = new
ArrayList<ContentProviderOperation>();
list.add(ContentProviderOperation.
newInsert(BatchContentProvider.FIRST_URI).build());
ContentValues cv = new ContentValues();
cv.put("name", "second_name");
cv.put("refId", 23);
// In this example, "refId" in the contentValues will be overwritten by
// the result from the first insert operation, indexed by 0
list.add(ContentProviderOperation.
newInsert(BatchContentProvider.SECOND_URI).
withValues(cv).withValueBackReference("refId", 0).build());
try {
getContentResolver().applyBatch(
BatchContentProvider.AUTHORITY, list);
} catch (RemoteException e) {
e.printStackTrace();
} catch (OperationApplicationException e) {
e.printStackTrace();
}
}
}
public class BatchContentProvider extends ContentProvider {
private static final String SCHEME = "content://";
public static final String AUTHORITY = "com.test.batch";
public static final Uri FIRST_URI =
Uri.parse(SCHEME + AUTHORITY + "/" + "table1");
public static final Uri SECOND_URI =
Uri.parse(SCHEME + AUTHORITY + "/" + "table2");
public ContentProviderResult[] applyBatch(
ArrayList<ContentProviderOperation> operations)
throws OperationApplicationException {
System.out.println("starting transaction");
ContentProviderResult[] result;
try {
result = super.applyBatch(operations);
} catch (OperationApplicationException e) {
System.out.println("aborting transaction");
throw e;
}
System.out.println("ending transaction");
return result;
}
public Uri insert(Uri uri, ContentValues values) {
// this printout will have a proper value when
// the second operation is applied
System.out.println("" + values);
return ContentUris.withAppendedId(uri, 1);
}
// other overrides omitted for brevity
}
알겠습니다. 따라서 이것은 목표로하지 않습니다. 제가 생각할 수있는 유일한 방법은 URL 기반 쿼리 요청으로 startTransaction 및 endTransaction을 코딩하는 것입니다. 같은 것 ContentResolver.query(START_TRANSACTION, null, null, null, null)
. 그런 다음 ContentProvider#query
등록 된 URL 호출 시작 또는 종료 거래에 따라
컨텐츠 제공 업체 객체 자체의 구현을 얻을 수 있습니다 (동일한 프로세스에서 힌트 : Multiprocess = "True"또는 Process = ""로 제공자의 프로세스를 제어 할 수 있습니다. http://developer.android.com/guide/topics/manifest/provider-lement.html) ContentProviderClient.getLocalContentProvider () 사용 공급자 구현에 캐스팅 될 수있는 Reset ()과 같은 추가 기능을 제공 할 수 있으며 데이터베이스를 닫고 삭제할 수 있으며 Save () 및 Close () 메소드를 사용하여 사용자 정의 트랜잭션 클래스 인스턴스를 반환 할 수 있습니다. .
public class Transaction {
protected Transaction (SQLiteDatabase database) {
this.database = database;
database.beginTransaction ();
}
public void save () {
this.database.setTransactionSuccessful ();
}
public void close () {
this.database.endTransaction ();
}
private SQLiteDatabase database;
}
public Transaction createTransaction () {
return new Transaction (this.dbHelper.getWritableDatabase ());
}
그 다음에:
ContentProviderClient client = getContentResolver ().acquireContentProviderClient (Contract.authorityLocal);
Transaction tx = ((LocalContentProvider) client.getLocalContentProvider ()).createTransaction ();