이SQLiteCursors는 AIDL 파일을 내가 그들을 만들 때 나는 알림을 설정에도 불구하고,
내 SQLite는 커서가 변경 통보되지 않습니다 (2 회 수정 됨) 존재 때 DB를 통지하지 않습니다 통지되지 않습니다 액세스됩니다. 나는 방법을 테스트하기 위해이 같은 시도 : 나는 ContentResolver.notifyChange
의 소스로 파고했을 때
weatherCursor.getCount(); // returns 1
deleteAllRecords();
Uri uri = weatherCursor.getNotificationUri();
getContext().getContentResolver().notifyChange(uri, null);
weatherCursor.getCount(); // still returns 1
weatherCursor.close();
weatherCursor = getContext().getContentResolver().query(uri, null, null, null, null);
weatherCursor.getCount(); //finally returns 0
, 나는 그것이
IContentObserver
라는 클래스를 사용하려고 발견,하지만 가져 오기가 해결 될 수 없다. 이것은 try 블록에서 수행하고 catch 블록은 비어 있으므로 자동으로 실패합니다.
마찬가지로 AbstractCursor.setNotificationUri
은 IContentService
이라는 클래스를 사용하려고하는 ContentResolver.registerContentObserver
을 호출하고 catch 블록이있는 try 블록 내에서 호출합니다. 위와 달리 IContentService
에 대한 import 문도 보지 못했습니다.
코멘트 작성자 (@Lawrence Choy)는 "IContentObserver
은 실제로는 IContentObserver.aidl
에 정의 된 자동 생성 파일입니다."라고 설명했습니다. 필자는 "IContentObserver.aidl"에 대한 전체 시스템을 조사했으며, Android Studio가 최근 검색을 저장하는 데 사용하는 파일 만이 내 컴퓨터에이 파일을 저장하지 않았습니다. 파일 위치가 확실치 않지만 SDK 관리자를 통해 빌드 도구와 API를 삭제하고 다시 설치해 보았습니다. 아직 어디에도 없습니다.
[다른 수정] 위의 코드 단편 (평가자에서 실행)은 다음 코드를 모두 관련 부분으로 압축하기위한 것이지만 여기에는 완전한 코드 집합이 있습니다. 첫 번째는 deleteAllRecords()
의 코드입니다. 내 테스트 단위 중 하나에서 오류가 발생했습니다. 그것은 성공적으로 모든 레코드를 삭제하지만 내가 당연시 여겼던 커서를 업데이트하지 못했습니다. WeatherProvider
의 .delete
및 .query
방법 여기에
public static Cursor queryWholeTable(Context context, Uri uri){
return context.getContentResolver().query(uri, null, null, null, null);
}
: 그리고 여기
public void deleteAllRecords() {
Cursor weatherCursor = queryWholeTable(mContext, WeatherEntry.CONTENT_URI);
Cursor locationCursor = queryWholeTable(mContext, LocationEntry.CONTENT_URI);
int initialWeatherCount = weatherCursor.getCount();
int initialLocationCount = locationCursor.getCount();
int deletedWeatherCount = mContext.getContentResolver().delete(
WeatherEntry.CONTENT_URI,
null,
null
);
int finalWeatherCount = weatherCursor.getCount();
int deletedLocationCount = mContext.getContentResolver().delete(
LocationEntry.CONTENT_URI,
null,
null
);
int finalLocationCount = locationCursor.getCount();
assertEquals(initialWeatherCount, deletedWeatherCount);
//ASSERT BELOW FAILS!
assertEquals(0, finalWeatherCount);
weatherCursor.close();
assertEquals(initialLocationCount, deletedLocationCount);
//ASSERT BELOW FAILS!
assertEquals(0, finalLocationCount);
locationCursor.close();
//Added when above tests failed to see if records were actually deleted.
weatherCursor = queryWholeTable(mContext, WeatherEntry.CONTENT_URI);
locationCursor = queryWholeTable(mContext, LocationEntry.CONTENT_URI);
int weatherVeryFinal = weatherCursor.getCount();
int locationVeryFinal = locationCursor.getCount();
assertEquals(0, weatherVeryFinal);
assertEquals(0, locationVeryFinal);
locationCursor.close();
weatherCursor.close();
}
이 .queryWholeTable
입니다
@Override
public int delete(Uri targetUri, String selection, String[] selectionArgs) {
final int match = sUriMatcher.match(targetUri);
final String table;
final Uri notificationUri;
switch (match) {
case WEATHER:
table = WeatherEntry.TABLE_NAME;
notificationUri = WeatherEntry.CONTENT_URI;
break;
case LOCATION:
table = LocationEntry.TABLE_NAME;
notificationUri = LocationEntry.CONTENT_URI;
break;
default:
throw new UnsupportedOperationException("Unknown delete uri: " + targetUri.toString());
}
int affected = mOpenHelper.getWritableDatabase().delete(table, selection, selectionArgs);
if (selection == null || affected > 0) {
getContext().getContentResolver().notifyChange(notificationUri, null);
}
return affected;
}
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
String sortOrder) {
// Here's the switch statement that, given a URI, will determine what kind of request it is,
// and query the database accordingly.
Cursor retCursor;
switch (sUriMatcher.match(uri)) {
// "weather/*/*"
case WEATHER_WITH_LOCATION_AND_DATE: {
retCursor = getWeatherByLocationSetting(uri, projection, sortOrder, true);
break;
}
// "weather/*"
case WEATHER_WITH_LOCATION: {
retCursor = getWeatherByLocationSetting(uri, projection, sortOrder, false);
break;
}
// "weather"
case WEATHER: {
retCursor = mOpenHelper.getReadableDatabase().query(
WeatherEntry.TABLE_NAME,
projection,
selection,
selectionArgs,
null,
null,
sortOrder
);
break;
}
// "location/*"
case LOCATION_ID: {
retCursor = mOpenHelper.getReadableDatabase().query(
LocationEntry.TABLE_NAME,
projection,
LocationEntry._ID + " = " + ContentUris.parseId(uri),
selectionArgs,
null,
null,
sortOrder
);
break;
}
// "location"
case LOCATION: {
retCursor = mOpenHelper.getReadableDatabase().query(
LocationEntry.TABLE_NAME,
projection,
selection,
selectionArgs,
null,
null,
sortOrder
);
break;
}
default:
throw new UnsupportedOperationException("Unknown uri: " + uri);
}
retCursor.setNotificationUri(getContext().getContentResolver(), uri);
return retCursor;
}
당신이 볼 수 있듯이, .setNotificationUri
항상 커서가 생성 될 때 호출은, 어떤 것이 삭제되면 항상 .notifyChange
이 호출됩니다.
당신은'ContentResolver'를 오버라이드하려고하거나 단순히 일반적인 사용으로 프로젝트를 빌드 할 수 없습니까? –
ContentResolver를 오버라이드하려고하지 않고 실제로 프로젝트가 빌드 및 실행되지만 커서에 변경 사항이 통지되지 않고'ContentResolver.notifyChange()'에 대한 소스를 살펴볼 때 나는 그것은 IContentObserver.notifyChange'라고 불렸고 당황했습니다. 이로 인해 내 코드가 문제를 일으키고 있는지 또는 누락 된 파일인지 여부를 알 수 없습니다. –
이것이 문제의 원인이 아닌 것 같습니다. 'IContentObserver'는 실제로'IContentObserver.aidl'에 정의 된 자동 생성 된 파일입니다. 이 파일은 SDK 관리자에서 다운로드 한 소스에없는 Android 소스 파일에서 빌드 할 때 생성됩니다. 응용 프로그램을 실행하면 장치에서이 파일을 사용할 수있게됩니다. –