ListActivity doesn't update as data arrives

大城市里の小女人 提交于 2019-12-22 08:57:43

问题


I'm building a small application that I'd like to automatically update when new data arrives.

From what I've read of the android documentation, I thought that because I'm using the newer techniques that a ContentObserver would be created in the background for me, and I would just get automatic calls to the Loader.

If there's any more information that would be helpful, I'd be glad to add it, or to upload the complete project somewhere.

Additionally, I'm targeting KitKat (sdk version 19).

Application Overview

  1. We have a ListActivity using the builtin ListView.
  2. The ListActivity gets data by using a Loader and a SimpleCursorAdapter.
  3. The Loader retrieves its data by querying a ContentProvider.
  4. The ContentProvider is backed by a SQLite Database.

Additionally, in the action bar, I've added two actions, one to add an item, and one to clear all items.

As I add items, the ListView is not updated with the new entries, and I can also see that no new query has been run on the ContentProvider. If I close the application, and restart it, those entries are now visible in the ListView.

Source Code Follows

Activity.java

package us.lynch.listdemo;

import java.text.DateFormat;
import java.util.Date;

import us.lynch.listdemo.R;
import android.app.ListActivity;
import android.app.LoaderManager.LoaderCallbacks;
import android.content.ContentValues;
import android.content.CursorLoader;
import android.content.Loader;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.CursorAdapter;
import android.widget.SimpleCursorAdapter;

public class Activity extends ListActivity implements LoaderCallbacks<Cursor> {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setListAdapter(new SimpleCursorAdapter(this, R.layout.listitem, null, new String[] { "string" }, new int[] { R.id.text }, 0));
        getLoaderManager().initLoader(0, null, this);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        ContentValues values = new ContentValues();

        switch (item.getItemId()) {
            case R.id.action_add:
                values.put("string", DateFormat.getDateTimeInstance().format(new Date()));
                getContentResolver().insert(Uri.parse("content://us.lynch.listdemo/data"), values);
                return true;

            case R.id.action_clear:
                getContentResolver().delete(Uri.parse("content://us.lynch.listdemo/data"), null, null);
                return true;

            default:
                return super.onOptionsItemSelected(item);
        }
    }

    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
        Uri uri = Uri.parse("content://us.lynch.listdemo/data");
        String[] projection = { "_id", "string" };
        return new CursorLoader(this, uri, projection, null, null, "_id");
    }

    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
        ((CursorAdapter) getListAdapter()).swapCursor(cursor);
    }

    @Override
    public void onLoaderReset(Loader<Cursor> loader) {
        ((CursorAdapter) getListAdapter()).swapCursor(null);
    }
}

ContentProvider.java

package us.lynch.listdemo;

import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.DatabaseUtils;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.net.Uri;
import android.text.TextUtils;

public class ContentProvider extends android.content.ContentProvider {
    private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
    private Database mDatabase;

    private static final int MATCH = 1;
    private static final int MATCH_ID = 2;

    static {
        sUriMatcher.addURI("us.lynch.listdemo", "data", MATCH);
        sUriMatcher.addURI("us.lynch.listdemo", "data/#", MATCH_ID);
    }

    @Override
    public boolean onCreate() {
        mDatabase = new Database(getContext());
        return true;
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
        switch (sUriMatcher.match(uri)) {
            case MATCH:
                return database().query("data", projection, selection, selectionArgs, null, null, sortOrder);
            case MATCH_ID:
                selection = addIdToSelection(uri, selection);
                return database().query("data", projection, selection, selectionArgs, null, null, sortOrder);
            default:
                throw new IllegalArgumentException("Unknown URI " + uri);
        }
    }

    @Override
    public Uri insert(Uri uri, ContentValues values) {
        switch (sUriMatcher.match(uri)) {
            case MATCH: {
                return ContentUris.withAppendedId(uri, database().insertOrThrow("data", null, values));
            }
            default:
                throw new IllegalArgumentException("Unknown URI " + uri);
        }
    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        switch (sUriMatcher.match(uri)) {
            case MATCH:
                return database().delete("data", selection, selectionArgs);
            case MATCH_ID:
                selection = addIdToSelection(uri, selection);
                return database().delete("data", selection, selectionArgs);
            default:
                throw new IllegalArgumentException("Unknown URI " + uri);
        }
    }

    @Override
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
        switch (sUriMatcher.match(uri)) {
            case MATCH:
                return database().update("data", values, selection, selectionArgs);
            case MATCH_ID:
                selection = addIdToSelection(uri, selection);
                return database().update("data", values, selection, selectionArgs);
            default:
                throw new IllegalArgumentException("Unknown URI " + uri);
        }
    }

    @Override
    public String getType(Uri uri) {
        throw new IllegalArgumentException("Unknown URI " + uri);
    }

    private SQLiteDatabase database() {
        return mDatabase.getWritableDatabase();
    }

    private static String addIdToSelection(Uri uri, String selection) {
        return DatabaseUtils.concatenateWhere(selection, "_id = " + Long.toString(ContentUris.parseId(uri)));
    }
}

class Database extends SQLiteOpenHelper {
    Database(Context context) {
        super(context, "database", null, 1);
    }

    @Override
    public void onCreate(SQLiteDatabase database) {
        final String[] columns = new String[] {
                "_id integer primary key autoincrement",
                "string text not null",
        };

        database.execSQL("create table data (" + TextUtils.join(",", columns) + ");");
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        assert (false);
    }
}

res/layout/listitem.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <TextView
        android:id="@+id/text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"
        android:text="Large Text"
        android:textAppearance="?android:attr/textAppearanceLarge" />

</RelativeLayout>

res/menu/main.xml

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >

    <item
        android:id="@+id/action_clear"
        android:title="Clear Items"
        android:visible="true">
    </item>
    <item
        android:id="@+id/action_add"
        android:title="Add Item"
        android:visible="true">
    </item>

</menu>

回答1:


You don't use the Uri notification mechanism.

In the query() method write:

Cursor cursor = database().query("data", projection, selection, selectionArgs, null, null, sortOrder);
cursor.setNotificationUri(getContext().getContentResolver(), uri);
return cursor;

In the methods where content is modified (insert, update, delete), notify the same Uri:

ContentResolver cr = getContext().getContentResolver();
cr.notifyChange(uri, null);


来源:https://stackoverflow.com/questions/24087741/listactivity-doesnt-update-as-data-arrives

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!