我有问题,我的ListView只显示一次数据。如果我关闭应用程序并再次打开它,它就不会显示任何内容。
我有一个Content Provider,用于从SQLite数据库中检索数据。我有一个SyncAdapter,它从服务器获取数据并将其放入SQLite数据库。然后我使用SimpleCursorAdapter将数据显示到ListView中。该查询是一个内部联接'。
MainActivity Code:
public class MainActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<Cursor> {
private static final int URL_LOADER = 1;
private ListView employeeList;
public static SimpleCursorAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
employeeList = (ListView) findViewById(R.id.listView);
/**
* Creating a dummyAccount for the content provider
*/
Account account = new Account("dummyAccount", TrackingContentProvider.AUTHORITY);
AccountManager accountManager = (AccountManager) this.getSystemService(ACCOUNT_SERVICE);
accountManager.addAccountExplicitly(account, null, null);
/**
* Set the sync adapter to an automatic state
*/
ContentResolver.setSyncAutomatically(account, TrackingContentProvider.AUTHORITY, true);
/**
* The projection for the SimpleCursorLoader
*/
String[] from = new String[] {EmployeesTable.COLUMN_FIRST_NAME, EmployeesTable.COLUMN_LAST_NAME, StatesTable.COLUMN_STATE, EmployeesTable.COLUMN_ID};
/**
* The ids of the views where the content is going to be put in
*/
int[] to = new int[] {R.id.tV_emplFirstNameInsert, R.id.tV_emplLastNameInsert, R.id.tV_stateInsert};
/**
* Make a new cursor adapter for the list view
*/
adapter = new SimpleCursorAdapter(this, R.layout.employee_list_item, null, from, to, 0);
/**
* Calls the loader manager and query another time
*/
getSupportLoaderManager().restartLoader(URL_LOADER, null, MainActivity.this);
/**
* Sets the list view to the SimpleCursorAdapter
*/
employeeList.setAdapter(adapter);
registerClickCallback();
}
/**
* Registers the clicks on the elements
*/
private void registerClickCallback() {
employeeList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
startActivity(new Intent(MainActivity.this, LocationActivity.class));
}
});
}
/**
* Is called by the loader manager
* @param id The unique id of the loader
* @param args Bundle of arguments
* @return The cursor of the query
*/
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
String[] projection = new String[] {"E." + EmployeesTable.COLUMN_ID, "E." + EmployeesTable.COLUMN_FIRST_NAME,
"E." + EmployeesTable.COLUMN_LAST_NAME, "S." + StatesTable.COLUMN_STATE};
String clause = "S." + StatesTable.COLUMN_ID + " = " + "E." + EmployeesTable.COLUMN_STATE_ID;
return new CursorLoader(this,
TrackingContentProvider.EMPLOYEE_LIST_CONTENT_URI, projection, clause, null, null);
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
adapter.swapCursor(data);
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
adapter.swapCursor(null);
}
@Override
protected void onRestart() {
super.onRestart();
getSupportLoaderManager().restartLoader(URL_LOADER, null, MainActivity.this);
}
}
Content Provider使用SQLiteQueryBuilder查询数据。我用于查询的表格如下所示:
private static final String EMPLOYEE_LIST_INNER_JOIN = "" +
EmployeesTable.TABLE_NAME + " AS E " +
"INNER JOIN " +
StatesTable.TABLE_NAME + " AS S";
onPerformSync如下所示:
@Override
public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) {
try {
deleteDatabase(provider);
insertEmployeesTable(provider);
insertStatesTable(provider);
insertLocationsTable(provider);
} catch (RemoteException | IOException e) {
Log.e("Sync: Error:", e.toString());
}
}
因此,每次同步时,它都会删除数据库的所有条目并插入新数据。它有效,我在同步后检查了数据库。
首次启动应用程序后,由于同步适配器正在同步,因此它不会显示任何内容。然后我关闭应用程序并再次打开它,它显示数据。然后同步适配器同步另一个时间(相同的数据),但它不再显示数据。有什么建议?我现在正试图找错误3天......
编辑1:ContentProvider代码:
public class TrackingContentProvider extends ContentProvider {
private static final int TRACKING_CONTENT = 100;
private static final int TRACKING_CONTENT_ID = 200;
private static final int EMPLOYEE_LIST_CONTENT = 300;
private static final int EMPLOYEE_LIST_CONTENT_ID = 400;
/**
* Table declaration
*/
private static final int EMPLOYEES_TABLE_CONTENT = 500;
private static final int EMPLOYEES_TABLE_CONTENT_ID = 600;
private static final int STATES_TABLE_CONTENT = 700;
private static final int STATES_TABLE_CONTENT_ID = 800;
private static final int LOCATIONS_TABLE_CONTENT = 900;
private static final int LOCATIONS_TABLE_CONTENT_ID = 1000;
public static final String AUTHORITY = "***";
private static final String TRACKING_BASE_PATH = "tracking";
private static final String EMPLOYEE_LIST_BASE_PATH = "employees";
/**
* Table base paths
*/
private static final String EMPLOYEES_TABLE_BASE_PATH = "employeesTable";
private static final String STATES_TABLE_BASE_PATH = "statesTable";
private static final String LOCATIONS_TABLE_BASE_PATH = "locationsTable";
/**
* Table INNER JOIN declarations
*/
private static final String EMPLOYEE_LIST_INNER_JOIN = "" +
EmployeesTable.TABLE_NAME + " AS E " +
"INNER JOIN " +
StatesTable.TABLE_NAME + " AS S";
public static final Uri TRACKING_CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/" + TRACKING_BASE_PATH);
public static final Uri EMPLOYEE_LIST_CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/" + EMPLOYEE_LIST_BASE_PATH);
/**
* Tables Uris
*/
public static final Uri EMPLOYEES_TABLE_URI = Uri.parse("content://" + AUTHORITY + "/" + EMPLOYEES_TABLE_BASE_PATH);
public static final Uri STATES_TABLE_URI = Uri.parse("content://" + AUTHORITY + "/" + STATES_TABLE_BASE_PATH);
public static final Uri LOCATIONS_TABLE_URI = Uri.parse("content://" + AUTHORITY + "/" + LOCATIONS_TABLE_BASE_PATH);
private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
static {
sUriMatcher.addURI(AUTHORITY, TRACKING_BASE_PATH, TRACKING_CONTENT);
sUriMatcher.addURI(AUTHORITY, TRACKING_BASE_PATH + "/#", TRACKING_CONTENT_ID);
sUriMatcher.addURI(AUTHORITY, EMPLOYEE_LIST_BASE_PATH, EMPLOYEE_LIST_CONTENT);
sUriMatcher.addURI(AUTHORITY, EMPLOYEE_LIST_BASE_PATH + "/#", EMPLOYEE_LIST_CONTENT_ID);
/**
* Table matcher
*/
sUriMatcher.addURI(AUTHORITY, EMPLOYEES_TABLE_BASE_PATH, EMPLOYEES_TABLE_CONTENT);
sUriMatcher.addURI(AUTHORITY, EMPLOYEES_TABLE_BASE_PATH + "/#", EMPLOYEES_TABLE_CONTENT_ID);
sUriMatcher.addURI(AUTHORITY, STATES_TABLE_BASE_PATH, STATES_TABLE_CONTENT);
sUriMatcher.addURI(AUTHORITY, STATES_TABLE_BASE_PATH + "/#", STATES_TABLE_CONTENT_ID);
sUriMatcher.addURI(AUTHORITY, LOCATIONS_TABLE_BASE_PATH, LOCATIONS_TABLE_CONTENT);
sUriMatcher.addURI(AUTHORITY, LOCATIONS_TABLE_BASE_PATH + "/#", LOCATIONS_TABLE_CONTENT_ID);
}
private SQLiteHelper database;
@Override
public boolean onCreate() {
database = new SQLiteHelper(getContext());
return false;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
int uriType = sUriMatcher.match(uri);
checkColumns(projection);
switch (uriType) {
case TRACKING_CONTENT:
break;
case TRACKING_CONTENT_ID:
break;
case EMPLOYEE_LIST_CONTENT:
queryBuilder.setTables(EMPLOYEE_LIST_INNER_JOIN);
break;
case EMPLOYEE_LIST_CONTENT_ID:
queryBuilder.setTables(EMPLOYEE_LIST_INNER_JOIN);
queryBuilder.appendWhere("E." + EmployeesTable.COLUMN_ID + " = " + uri.getLastPathSegment());
break;
case STATES_TABLE_CONTENT:
queryBuilder.setTables(StatesTable.TABLE_NAME);
break;
case STATES_TABLE_CONTENT_ID:
queryBuilder.setTables(StatesTable.TABLE_NAME);
queryBuilder.appendWhere(StatesTable.COLUMN_ID + " = " + uri.getLastPathSegment());
break;
case EMPLOYEES_TABLE_CONTENT:
queryBuilder.setTables(EmployeesTable.TABLE_NAME);
break;
case EMPLOYEES_TABLE_CONTENT_ID:
queryBuilder.setTables(EmployeesTable.TABLE_NAME);
queryBuilder.appendWhere(EmployeesTable.COLUMN_ID + " = " + uri.getLastPathSegment());
break;
case LOCATIONS_TABLE_CONTENT:
queryBuilder.setTables(LocationsTable.TABLE_NAME);
break;
case LOCATIONS_TABLE_CONTENT_ID:
queryBuilder.setTables(LocationsTable.TABLE_NAME);
queryBuilder.appendWhere(LocationsTable.COLUMN_ID + " = " + uri.getLastPathSegment());
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
SQLiteDatabase db = database.getReadableDatabase();
Cursor cursor = queryBuilder.query(
db,
projection,
selection,
selectionArgs,
null,
null,
sortOrder
);
cursor.setNotificationUri(getContext().getContentResolver(), uri);
return cursor;
}
@Override
public String getType(Uri uri) {
return null;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
int uriType = sUriMatcher.match(uri);
SQLiteDatabase db = database.getWritableDatabase();
long id;
String path;
switch (uriType) {
case STATES_TABLE_CONTENT:
id = db.insert(StatesTable.TABLE_NAME, null, values);
path = STATES_TABLE_BASE_PATH;
break;
case LOCATIONS_TABLE_CONTENT:
id = db.insert(LocationsTable.TABLE_NAME, null, values);
path = LOCATIONS_TABLE_BASE_PATH;
break;
case EMPLOYEES_TABLE_CONTENT:
id = db.insert(EmployeesTable.TABLE_NAME, null, values);
path = EMPLOYEES_TABLE_BASE_PATH;
break;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return Uri.parse(path + "/" + id);
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
int uriType = sUriMatcher.match(uri);
SQLiteDatabase db = database.getWritableDatabase();
int rowsDeleted = 0;
switch (uriType) {
case EMPLOYEES_TABLE_CONTENT:
rowsDeleted = db.delete(EmployeesTable.TABLE_NAME,
selection,
selectionArgs);
break;
case EMPLOYEES_TABLE_CONTENT_ID:
String employeeID = uri.getLastPathSegment();
if (TextUtils.isEmpty(selection)) {
rowsDeleted = db.delete(EmployeesTable.TABLE_NAME,
EmployeesTable.COLUMN_ID + " = " + employeeID, null);
}
break;
case STATES_TABLE_CONTENT:
rowsDeleted = db.delete(StatesTable.TABLE_NAME,
selection,
selectionArgs);
break;
case STATES_TABLE_CONTENT_ID:
String stateID = uri.getLastPathSegment();
if (TextUtils.isEmpty(selection)) {
rowsDeleted = db.delete(StatesTable.TABLE_NAME,
StatesTable.COLUMN_ID + " = " + stateID, null);
}
break;
case LOCATIONS_TABLE_CONTENT:
rowsDeleted = db.delete(StatesTable.TABLE_NAME,
selection,
selectionArgs);
break;
case LOCATIONS_TABLE_CONTENT_ID:
String locationID = uri.getLastPathSegment();
if (TextUtils.isEmpty(selection)) {
rowsDeleted = db.delete(LocationsTable.TABLE_NAME,
LocationsTable.COLUMN_ID + " = " + locationID, null);
}
break;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return rowsDeleted;
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
int uriType = sUriMatcher.match(uri);
SQLiteDatabase sqlDb = database.getWritableDatabase();
int rowsUpdated;
switch (uriType) {
case EMPLOYEES_TABLE_CONTENT:
rowsUpdated = sqlDb.update(EmployeesTable.TABLE_NAME,
values,
selection,
selectionArgs);
break;
case EMPLOYEE_LIST_CONTENT_ID:
String employeeID = uri.getLastPathSegment();
if (TextUtils.isEmpty(selection)) {
rowsUpdated = sqlDb.update(EmployeesTable.TABLE_NAME,
values,
EmployeesTable.COLUMN_ID + "=" + employeeID
+ " AND "
+ selection,
selectionArgs);
} else {
rowsUpdated = sqlDb.update(EmployeesTable.TABLE_NAME,
values,
EmployeesTable.COLUMN_ID + "=" + employeeID
+ " AND "
+ selection,
selectionArgs);
}
break;
case STATES_TABLE_CONTENT:
rowsUpdated = sqlDb.update(StatesTable.TABLE_NAME,
values,
selection,
selectionArgs);
break;
case STATES_TABLE_CONTENT_ID:
String stateID = uri.getLastPathSegment();
if (TextUtils.isEmpty(selection)) {
rowsUpdated = sqlDb.update(StatesTable.TABLE_NAME,
values,
StatesTable.COLUMN_ID + "=" + stateID
+ " AND "
+ selection,
selectionArgs);
} else {
rowsUpdated = sqlDb.update(StatesTable.TABLE_NAME,
values,
StatesTable.COLUMN_ID + "=" + stateID
+ " AND "
+ selection,
selectionArgs);
}
break;
case LOCATIONS_TABLE_CONTENT:
rowsUpdated = sqlDb.update(LocationsTable.TABLE_NAME,
values,
selection,
selectionArgs);
break;
case LOCATIONS_TABLE_CONTENT_ID:
String locationID = uri.getLastPathSegment();
if (TextUtils.isEmpty(selection)) {
rowsUpdated = sqlDb.update(LocationsTable.TABLE_NAME,
values,
LocationsTable.COLUMN_ID + "=" + locationID
+ " AND "
+ selection,
selectionArgs);
} else {
rowsUpdated = sqlDb.update(LocationsTable.TABLE_NAME,
values,
LocationsTable.COLUMN_ID + "=" + locationID
+ " AND "
+ selection,
selectionArgs);
}
break;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return rowsUpdated;
}
/**
* Checks if the column exists
* @param projection The array of the existing columns
*/
private void checkColumns(String[] projection) {
String[] available = {
"E." + EmployeesTable.COLUMN_ID,
"E." + EmployeesTable.COLUMN_LAST_NAME,
"E." + EmployeesTable.COLUMN_FIRST_NAME,
"E." + EmployeesTable.COLUMN_STATE_ID,
"E." + EmployeesTable.COLUMN_ENTRY_DATE,
"S." + StatesTable.COLUMN_ID,
"S." + StatesTable.COLUMN_STATE,
"L." + LocationsTable.COLUMN_ID,
"L." + LocationsTable.COLUMN_DATE,
"L." + LocationsTable.COLUMN_EMPLOYEE_ID,
"L." + LocationsTable.COLUMN_LONGITUDE,
"L." + LocationsTable.COLUMN_LATITUDE,
EmployeesTable.COLUMN_ID,
EmployeesTable.COLUMN_LAST_NAME,
EmployeesTable.COLUMN_FIRST_NAME,
EmployeesTable.COLUMN_STATE_ID,
EmployeesTable.COLUMN_ENTRY_DATE,
StatesTable.COLUMN_ID,
StatesTable.COLUMN_STATE,
LocationsTable.COLUMN_ID,
LocationsTable.COLUMN_DATE,
LocationsTable.COLUMN_EMPLOYEE_ID,
LocationsTable.COLUMN_LONGITUDE,
LocationsTable.COLUMN_LATITUDE,
};
if (projection != null) {
HashSet<String> requestedColumns = new HashSet<>(Arrays.asList(projection));
HashSet<String> availableColumns = new HashSet<>(Arrays.asList(available));
if (!availableColumns.containsAll(requestedColumns)) {
throw new IllegalArgumentException("Unknown columns in projection");
}
}
}
}
更新:
我终于找到了错误。在同步期间,自动增量出错。所以,他没有找到这个Inner Join声明的条目。结束。