Мне нужно обновить ListView новыми данными из ContentProvider (в настоящее время это таблица базы данных). Логика начинается с AlertDialog, который позволяет добавить строку (в настоящее время жестко запрограммированную временную метку) с помощью пользовательского ContentProvider, выполняющего задачу CRUD для таблицы. При добавлении запустите setPositiveButton
из объекта AlertDialog, он разрешает ContentProvider выполнять вставку в базу данных. После этого (добавлено правильно) необходимо обновить ListView с новой недавно добавленной строкой.
Я следую руководствам с сайта Android и смешиваю некоторый код:
- Я использую интерфейс LoaderManager.LoaderCallbacks отсюда
- Использование (только для изучения) поставщиков содержимого здесь.
Прежде чем пытаться использовать объект ArrayAdapter и обновление ListView, все в порядке. Но с тех пор, как я добавил SimpleCursorAdapter и Loaders, я не могу обновить его.
Я пробовал (почти, я думаю) все, например:
- добавить метод
mAdapter.notifyDataSetNotifyChanged()
после вставки, но не работать. - добавьте
runOnUiThread( new Runnable( ) { mAdapter.notifyDataSetNotifyChanged(); } );
, как предложено здесь, но не работает. ((SimpleCursorAdapter) this.getListAdapter()).swap(...)
и((SimpleCursorAdapter) this.getListAdapter()).notifyDataSetNotifyChanged()
мышление может быть эталонной проблемой, но не работать
Вещь для теста:
- добавьте
getContext().getContentResolver().notifyChange( Uri uri, ContentObserver observer);
, но не знаете, как передать второй параметр.
Код, который работает для меня, состоит в том, чтобы использовать getLoaderManager().restartLoader()
каждый раз, когда пользователь нажимает кнопку «+». Но для меня это (семантически) неправильно, потому что адаптер использует шаблон Observer, но я не могу заставить его работать с логикой notifications.
Как видите, это очень простой пример использования ListActivity, SimpleCursorAdapter, ContentProviders и LoaderManager. Если у вас есть код, который работает так, как я ожидал (используя уведомления для наблюдателей), поделитесь им. Все еще думаю, что с этими классами должно работать нормально, но что-то я делаю не так.
заранее спасибо
ListViewTest.java
package cl.jago.listviewtest;
import android.app.AlertDialog;
import android.app.ListActivity;
import android.app.LoaderManager;
import android.content.ContentValues;
import android.content.Context;
import android.content.CursorLoader;
import android.content.DialogInterface;
import android.content.Loader;
import android.database.Cursor;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.SimpleCursorAdapter;
import java.util.Date;
public class ListActivityTest extends ListActivity implements LoaderManager.LoaderCallbacks<Cursor> {
// This is the Adapter being used to display the list's data
SimpleCursorAdapter mAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setContentView( R.layout.layout_listado );
// Tutorial: Api Guides > ListViews
// For the cursor adapter, specify which columns go into which views
String[] fromColumns = { "nombre"};
int[] toViews = {android.R.id.text1}; // The TextView in simple_list_item_1
// Create an empty adapter we will use to display the loaded data.
// We pass null for the cursor, then update it in onLoadFinished()
mAdapter = new SimpleCursorAdapter( this, android.R.layout.simple_list_item_1, null,
fromColumns, toViews, 0 );
setListAdapter(mAdapter);
// Prepare the loader. Either re-connect with an existing one,
// or start a new one.
getLoaderManager().initLoader( 0, null, this );
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_list_activity_test, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.agregar) {
// 1. Instantiate an AlertDialog.Builder with its constructor
AlertDialog.Builder builder = new AlertDialog.Builder( this );
// Add the buttons
builder.setPositiveButton( R.string.ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
ContentValues cv = new ContentValues();
cv.put("nombre", (new Date()).getTime());
getContentResolver().insert(ListViewContentProvider.uri, cv);
}
} );
builder.setNegativeButton( R.string.cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// User cancelled the dialog
}
} );
// 2. Chain together various setter methods to set the dialog characteristics
builder.setMessage(R.string.dialog_message).setTitle(R.string.dialog_title);
// 3. Get the AlertDialog from create()
AlertDialog dialog = builder.create();
dialog.show();
return true;
}
return super.onOptionsItemSelected(item);
}
// Called when a new Loader needs to be created
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
// Now create and return a CursorLoader that will take care of
// creating a Cursor for the data being displayed.
// return new CursorLoader(this, ContactsContract.Data.CONTENT_URI, PROJECTION, SELECTION, null, null);
return new CursorLoader( this, ListViewContentProvider.uri, new String[]{"_id", "nombre"}, null, null, null);
}
// Called when a previously created loader has finished loading
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
// Swap the new cursor in. (The framework will take care of closing the
// old cursor once we return.)
mAdapter.swapCursor(data);
}
// Called when a previously created loader is reset, making the data unavailable
public void onLoaderReset(Loader<Cursor> loader) {
// This is called when the last Cursor provided to onLoadFinished()
// above is about to be closed. We need to make sure we are no
// longer using it.
mAdapter.swapCursor(null);
}
}
ListViewContentProvider.java
package cl.jago.listviewtest;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
public class ListViewContentProvider extends ContentProvider {
public static Uri uri = Uri.parse( "content://cl.jago.listviewtest/listview" );
private ListViewDbHelper mOpenHelper;
@Override
public boolean onCreate() {
mOpenHelper = new ListViewDbHelper( getContext() );
return true;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
SQLiteDatabase db = mOpenHelper.getReadableDatabase();
Cursor c = db.query( "listview", new String[] { "_id", "nombre" }, null, null, null, null, null );
return c;
}
@Override
public String getType(Uri uri) {
return null;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
long id = db.insertOrThrow( "listview", null, values );
return Uri.parse( "content://cl.jago.listviewtest/listview/"+id );
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
return 0;
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
return 0;
}
}
ListTextViewDbHelper.java
package cl.jago.listviewtest;
import android.content.Context;
import android.database.DatabaseErrorHandler;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
public class ListViewDbHelper extends SQLiteOpenHelper {
public ListViewDbHelper( Context context ) {
super(context, "listview", null, 1 );
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("create table listview ( _id integer primary key, nombre text ) " );
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
getContext().getContentResolver().notifyChange("content://cl.jago.listviewtest/", null);
после метода insert(). - person feathersanddown   schedule 21.09.2017