У меня проблема с провайдером содержимого Android с помощью loadermanager. Я использую LoaderManager для загрузки моего CursorLoader из ContentProvider, а ContentProvider вызывает мой класс sqlite. В классе Sqlite я вызываю sql-запрос и возвращаю курсор, не закрывая курсор или базу данных. Как я понял, вот как он должен работать (и он не работает, когда я закрываю курсор/db), но после второго посещения в действии я получаю это исключение из того, что база данных не закрывается. Это должно быть что-то глупое.Закрытие никогда не вызывалось при использовании ContentProvider
Я вызываю initLoader LoaderManager в свой onActivityCreated моего фрагмента.
Вот мой метод запроса в ContentProvider:
public synchronized Cursor query(final Uri uri, final String[] projection, final String selection, final String[] selectionArgs, final String sortOrder) {
final SongDbHandler songDbHandler = AbstractActivity.getLocalService(getContext()).getDbHandler();
String order = " ";
if ("author".equals(sortOrder)) {
order = Constants.ORDER_AUTHOR;
} else if ("song".equals(sortOrder)) {
order = Constants.ORDER_SONG;
}
System.out.println("getAllSongs");
final Cursor cursor = songDbHandler.getAllSongs(order);
cursor.setNotificationUri(getContext().getContentResolver(), uri);
return cursor;
}
Вот мой код в SQLite классе (Singleton SQLiteOpenHelper подкласс):
public Cursor getAllSongs(String order) {
SQLiteDatabase db = null;
Cursor cursor;
try {
db = this.getReadableDatabase();
String sql = "";
sql += "select " + Constants.AUTHOR_SELECT_COLUMNS + ", " + Constants.SONG_SELECT_COLUMNS + ", " + Constants.GLOBAL_ID;
sql += " from " + Constants.SONG_TABLE_NAME + ", " + Constants.AUTHOR_TABLE_NAME + " ";
sql += " where " + Constants.SONG_TABLE_NAME + "." + Constants.AUTHOR_FK + " = " + Constants.AUTHOR_TABLE_NAME + "." + Constants.AUTHOR_ID + " AND " + Constants.SONG_TABLE_NAME + "."
+ Constants.SONG_SOURCE_TYPE + " = " + Constants.AUTHOR_TABLE_NAME + "." + Constants.AUTHOR_SOURCE_TYPE;
// sql += " order by " + Constants.AUTHOR_TABLE_NAME + "." +
// Constants.AUTHOR_NAME + COLLATE;
sql += order;
// sql += " limit 20 ";
cursor = db.rawQuery(sql, new String[] {});
return cursor;
} finally {
//closeQuietly(db);
}
}
Любая помощь будет высоко ценится!
Edit: Вот мой LoaderManager обратный вызов:
@Override
public Loader<Cursor> onCreateLoader(int loaderId, Bundle bundle) {
return (Loader<Cursor>) new CursorLoader(getActivity().getApplicationContext(), SongContentProvider.getLocalProviderUri(), null, null, null, bundle.getString("order"));
}
@Override
public void onLoadFinished(Loader<Cursor> arg0, Cursor songs) {
updateData(songs);
}
@Override
public void onLoaderReset(Loader<Cursor> arg0) {
adapter.swapCursor(null);
}
Edit2:
private void updateData(Cursor songs) {
adapter.swapCursor(songs);
if (songs == null || songs.getCount() == 0) {
vysledky.setVisibility(View.GONE);
vysledkyMsg.setText(getString(R.string.no_results));
vysledkyMsg.setVisibility(View.VISIBLE);
} else {
vysledky.setVisibility(View.VISIBLE);
vysledkyMsg.setText(getString(R.string.progress_loading_content));
vysledkyMsg.setVisibility(View.GONE);
}
}
проблема с вашей реализацией 'LoaderManager.LoaderCallbacks' (вы не называете swapCursor адаптера или не закрываете курсор) не с этим кодом –
Selvin
Спасибо, я отредактировал сообщение и добавил мой код с LoaderCallbacks. Я использую swapCursor там. Где мне закрыть курсор? –
Что делать updateData ... если вы используете адаптер, вы должны вызывать только «adapter.swapCursor (песни);' in 'onLoadFinished' ... вот почему я люблю ContentProviders ... если вы не используете адаптер (одна строка без адаптера/ListView), затем закройте курсор в конце updateData – Selvin