作为数据到达ListActivity不更新 [英] ListActivity doesn't update as data arrives

查看:253
本文介绍了作为数据到达ListActivity不更新的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我建立一个小型应用程序,我想新数据到达时自动更新。

这是我读过的Andr​​oid文档的,我还以为是因为我使用的一个ContentObserver会在后台创建为我的新的技术,并且我只想得到自动呼叫装载机。

如果有任何这将是有用的信息,我会很高兴加入,或在某处上传完整的项目。

此外,我针对奇巧(SDK版本19)。

应用程序概述


  1. 我们必须使用内置的ListView一个ListActivity。

  2. 的ListActivity用装载机和SimpleCursorAdapter获取数据。

  3. 装载程序通过查询ContentProvider的检索数据。

  4. 的ContentProvider的是由一个SQLite数据库的支持。

此外,在行动起来吧,我已经添加了两个动作,一是增加一个项目,一个以清除所有项目。

当我添加项目,在ListView不会更新与新的项目,我也可以看到,没有任何新的查询已经在ContentProvider的运行。如果我关闭应用程序,并重新启动,这些项目现在在ListView可见。

来源$ C ​​$ C遵循

Activity.java

 包us.lynch.listdemo;进口java.text.DateFormat中;
进口java.util.Date;进口us.lynch.listdemo.R;
进口android.app.ListActivity;
进口android.app.LoaderManager.LoaderCallbacks;
进口android.content.ContentValues​​;
进口android.content.CursorLoader;
进口android.content.Loader;
进口android.database.Cursor;
进口android.net.Uri;
进口android.os.Bundle;
进口android.view.Menu;
进口android.view.MenuInflater;
进口android.view.MenuItem;
进口android.widget.CursorAdapter;
进口android.widget.SimpleCursorAdapter;公共类活动扩展了ListActivity实现LoaderCallbacks<&光标GT; {
    @覆盖
    保护无效的onCreate(捆绑savedInstanceState){
        super.onCreate(savedInstanceState);        setListAdapter(新SimpleCursorAdapter(这一点,R.layout.listitem,空,新的String [] {字符串},新的INT [] {} R.id.text,0));
        getLoaderManager()initLoader(0,null,则此)。
    }    @覆盖
    公共布尔onCreateOptionsMenu(菜单菜单){
        MenuInflater吹气= getMenuInflater();
        inflater.inflate(R.menu.main,菜单);
        返回true;
    }    @覆盖
    公共布尔onOptionsItemSelected(菜单项项){
        ContentValues​​值=新ContentValues​​();        开关(item.getItemId()){
            案例R.id.action_add:
                values​​.put(字符串,DateFormat.getDateTimeInstance()格式(新的Date()));
                getContentResolver()插入(Uri.parse(内容://us.lynch.listdemo/data)的值)。
                返回true;            案例R.id.action_clear:
                getContentResolver()删除(Uri.parse(内容://us.lynch.listdemo/data),NULL,NULL);
                返回true;            默认:
                返回super.onOptionsItemSelected(项目);
        }
    }    @覆盖
    公共装载机<&光标GT; onCreateLoader(INT ID,捆绑参数){
        URI URI = Uri.parse(内容://us.lynch.listdemo/data);
        的String [] =投影{_id,串};
        返回新CursorLoader(这一点,URI,投影,NULL,NULL,_id);
    }    @覆盖
    公共无效onLoadFinished(装载机<&光标GT;装载机,光标光标){
        ((CursorAdapter的)getListAdapter())swapCursor(光标)。
    }    @覆盖
    公共无效onLoaderReset(装载机<&光标GT;装载机){
        ((CursorAdapter的)getListAdapter())swapCursor(空)。
    }
}

ContentProvider.java

 包us.lynch.listdemo;进口android.content.ContentUris;
进口android.content.ContentValues​​;
进口android.content.Context;
进口android.content.UriMatcher;
进口android.database.Cursor;
进口android.database.DatabaseUtils;
进口android.database.sqlite.SQLiteDatabase;
进口android.database.sqlite.SQLiteOpenHelper;
进口android.net.Uri;
进口android.text.TextUtils;公共类ContentProvider的扩展android.content.ContentProvider {
    私有静态最终UriMatcher sUriMatcher =新UriMatcher(UriMatcher.NO_MATCH);
    私有数据库mDatabase;    私有静态最终诠释MATCH = 1;
    私有静态最终诠释MATCH_ID = 2;    静态{
        sUriMatcher.addURI(us.lynch.listdemo,数据,MATCH);
        sUriMatcher.addURI(us.lynch.listdemo,数据/#,MATCH_ID);
    }    @覆盖
    公共布尔的onCreate(){
        mDatabase =新的数据库(的getContext());
        返回true;
    }    @覆盖
    公共光标查询(URI URI,字符串[]投影,选择字符串,字符串[] selectionArgs两个,字符串中将sortOrder){
        开关(sUriMatcher.match(URI)){
            案例MATCH:
                返回数据库()查询(数据,投影,选择,selectionArgs两个,NULL,NULL,中将sortOrder)。
            案例MATCH_ID:
                选择= addIdToSelection(URI,选择);
                返回数据库()查询(数据,投影,选择,selectionArgs两个,NULL,NULL,中将sortOrder)。
            默认:
                抛出新抛出:IllegalArgumentException(未知URI+ URI);
        }
    }    @覆盖
    公共乌里插入(URI URI,ContentValues​​值){
        开关(sUriMatcher.match(URI)){
            案例MATCH:{
                返回ContentUris.withAppendedId(URI,数据库()insertOrThrow(数据,NULL,值)。);
            }
            默认:
                抛出新抛出:IllegalArgumentException(未知URI+ URI);
        }
    }    @覆盖
    公众诠释删除(URI URI,选择字符串,字符串[] selectionArgs两个){
        开关(sUriMatcher.match(URI)){
            案例MATCH:
                返回数据库()中删除(数据,选择selectionArgs两个)。
            案例MATCH_ID:
                选择= addIdToSelection(URI,选择);
                返回数据库()中删除(数据,选择selectionArgs两个)。
            默认:
                抛出新抛出:IllegalArgumentException(未知URI+ URI);
        }
    }    @覆盖
    公众诠释更新(开放的URI,ContentValues​​价值观,选择字符串,字符串[] selectionArgs两个){
        开关(sUriMatcher.match(URI)){
            案例MATCH:
                返回数据库()更新(数据,价值观念,选择selectionArgs两个)。
            案例MATCH_ID:
                选择= addIdToSelection(URI,选择);
                返回数据库()更新(数据,价值观念,选择selectionArgs两个)。
            默认:
                抛出新抛出:IllegalArgumentException(未知URI+ URI);
        }
    }    @覆盖
    公共字符串的getType(URI URI){
        抛出新抛出:IllegalArgumentException(未知URI+ URI);
    }    私人SQLiteDatabase数据库(){
        返回mDatabase.getWritableDatabase();
    }    私人静态字符串addIdToSelection(URI URI,弦乐选择){
        返回DatabaseUtils.concatenateWhere(选择_id =+ Long.toString(ContentUris.parseId(URI)));
    }
}类数据库扩展SQLiteOpenHelper {
    数据库(上下文的背景下){
        超(背景下,数据库,NULL,1);
    }    @覆盖
    公共无效的onCreate(SQLiteDatabase数据库){
        最终的String [] =列新的String [] {
                _id整数主键自动增量
                字符串文本不为空,
        };        database.execSQL(创建表数据(+ TextUtils.join(,,列)+););
    }    @覆盖
    公共无效onUpgrade(SQLiteDatabase分贝,INT oldVersion,诠释静态网页){
        断言(假);
    }
}

RES /布局/ listitem.xml

 <?XML版本=1.0编码=UTF-8&GT?;
<的RelativeLayout的xmlns:机器人=htt​​p://schemas.android.com/apk/res/android
    的xmlns:工具=htt​​p://schemas.android.com/tool​​s
    机器人:layout_width =match_parent
    机器人:layout_height =match_parent>    <的TextView
        机器人:ID =@ + ID /文
        机器人:layout_width =WRAP_CONTENT
        机器人:layout_height =WRAP_CONTENT
        机器人:layout_alignParentLeft =真
        机器人:layout_alignParentRight =真
        机器人:layout_alignParentTop =真
        机器人:文字=大文本
        机器人:textAppearance =:/>中的Andr​​oid ATTR / textAppearanceLarge?< / RelativeLayout的>

RES /菜单/ main.xml中

 <?XML版本=1.0编码=UTF-8&GT?;
<菜单的xmlns:机器人=htt​​p://schemas.android.com/apk/res/android>    <项目
        机器人:ID =@ + ID / action_clear
        机器人:标题=清除项目
        机器人:可见=真>
    < /项目>
    <项目
        机器人:ID =@ + ID / action_add
        机器人:标题=添加项目
        机器人:可见=真>
    < /项目>&所述; /菜单>


解决方案

您不要使用乌里的通知机制。

在query()方法写:

 光标光标=数据库()查询(数据,投影,选择,selectionArgs两个,NULL,NULL,中将sortOrder)。
cursor.setNotificationUri(的getContext()getContentResolver(),URI);
返回游标;

在,其中的内容被修改(插入,更新,删除)的方法,同时通知同一个URI:

  ContentResolver的CR =的getContext()getContentResolver()。
cr.notifyChange(URI,NULL);

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>

解决方案

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);

这篇关于作为数据到达ListActivity不更新的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆