数据库更新和adapter.notifyDataSetChanged()后列表视图未更新; [英] Listview not updating after database update and adapter.notifyDataSetChanged();

查看:16
本文介绍了数据库更新和adapter.notifyDataSetChanged()后列表视图未更新;的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经在网上浏览了 2 天并尝试了很多东西,但似乎无法弄清楚这有什么问题.

I was browsing the net for 2 days allready and tryed alot of stuff but can't seem to figure out what is wrong with this.

我对 Android 开发还很陌生,所以我可能错过了一些明显的东西.

I am still fairly new to the Android deevelopment so I probably missed something obvious.

我有一个应用程序女巫正在使用 sqllite 数据库来存储一些数据,并且为了在列表视图中显示该概念证明的目的.我可以将项目添加到列表中,也可以删除它们.

I have an app witch is using a sqllite databse to store some data and for the porpose of this Proof of concept displaying that in a listview. I can add items to the list, delete them.

到目前为止一切顺利.我遇到的问题是当我而不是删除更新数据库中名为已删除"的列并将其设置为 1 然后让适配器更新列表时.好像不行.

So far so good. The problem I have is when I instead of delete update a column in the databse called "deleted" and set it to 1 and then have the adapter to update the list. It seems not to work.

如果我使用 delete 语句,它会起作用.它更新,一切都很好,但我想在数据库中删除已删除的项目但不显示它们(所以基本上是隐藏"项目)

If I use the delete statement it works. It updates and everything is fine but I whant to have the deleted items in the database but not to show them (So basicly "hiding" items)

如果我检查数据库,更新本身会导致列更改和所有内容发生变化,所以我想这是一个刷新问题,因为适配器不会重新查询数据库或该方向的某些内容

If I check the database the update itself succeded the column changes and everything so I guess it is a refresh problem because the adapter does not requery the database or something in that direction

列表视图加载器:

public void fillData() {

    if(lw.getAdapter() == null){
        // Fields from the database (projection)
        // Must include the _id column for the adapter to work
        String[] from = new String[] { TodoTable.COLUMN_SUMMARY, TodoTable.COLUMN_ID};
        String where = TodoTable.COLUMN_DELETED + " = ?";


        Cursor cursor = getContentResolver().query(TodoContentProvider.CONTENT_URI,from,where,new String[] {"0"},null);
        // Fields on the UI to which we map
        int[] to = new int[] { R.id.label };

        adapter = new SimpleCursorAdapter(this, R.layout.todo_row, cursor, from,
                to, 0);
        Log.v("Count",Integer.toString(cursor.getCount()));
        lw.setAdapter(adapter);
    }
    else
        adapter.notifyDataSetChanged();
    }

删除功能

@Override
public boolean onContextItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case DELETE_ID:
            /* Code for actual delete
            AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item
                    .getMenuInfo();
            Uri uri = Uri.parse(TodoContentProvider.CONTENT_URI + "/"
                    + info.id);
            getContentResolver().delete(uri, null, null);
            fillData();
            */

            /* Code for update and hide */
            AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item
                    .getMenuInfo();
            Uri uri = Uri.parse(TodoContentProvider.CONTENT_URI + "/"
                    + info.id);
            ContentValues values = new ContentValues();
            values.put(TodoTable.COLUMN_DIRTY, 1);
            values.put(TodoTable.COLUMN_DELETED, 1);
            getContentResolver().update(uri,values,null,null);
            fillData();
            return true;
    }
    return super.onContextItemSelected(item);
}

如果我将日志放入 ContentProvider 的查询函数中,它实际上不会触发.

if I put a log to the ContentProvider's query function it actually does not fire.

关于如何解决这个问题有什么建议吗?

Any suggestions on how to figure this out?

如果我使用 adapter.swapCursor(cursor); 它工作正常只是不知道这是否是这样做的正确方法.

If I use adapter.swapCursor(cursor); it works fine just just don't know if this is the correct way of doing this.

public void fillData() {

    // Fields from the database (projection)
    // Must include the _id column for the adapter to work
    String[] from = new String[] { TodoTable.COLUMN_SUMMARY, TodoTable.COLUMN_ID};
    String where = TodoTable.COLUMN_DELETED + " = ?";

    Cursor cursor = getContentResolver().query(TodoContentProvider.CONTENT_URI,from,where,new String[] {"0"},null);

    // Fields on the UI to which we map
    int[] to = new int[] { R.id.label };

    if(lw.getAdapter() == null){
        adapter = new SimpleCursorAdapter(this, R.layout.todo_row, cursor, from,
                to, 0);
        Log.v("Count",Integer.toString(cursor.getCount()));
        lw.setAdapter(adapter);
    }
    else
    {
        adapter.swapCursor(cursor);
    }
}

你的帮助

推荐答案

使用 adapter.swapCursor(cursor) 是正确的,因此您几乎可以回答自己的问题.

Using adapter.swapCursor(cursor) is correct so you're almost there in answering your own question.

您的第一段代码不起作用,因为当您在数据库更新后调用 fillData() 时,您只需调用 adapter.notifyDataSetChanged() 并且数据集实际上并未更改,因为光标相同.游标是对数据库中行的引用,更新基础数据库不会刷新游标.您的第二段代码确实刷新了游标并将新的游标交换到适配器中(这也会触发对其绑定到的视图的更新).

Your first piece of code doesn't work because when you call fillData() after your database update, you simply call adapter.notifyDataSetChanged() and the dataset hasn't actually changed because the cursor is the same. A cursor is a reference to rows from your database and updating the underlying database doesn't refresh the cursor. Your second piece of code does refresh the cursor and swaps the new one in to the adapter (which also triggers an update to the view it is bound to).

更常见的编码方式是:

将此界面添加到您的活动中:

Add this interface to your activity:

public class MyActivity extends Activity implementsLoaderManager.LoaderCallbacks<Cursor>

在onCreate中,设置适配器(注意此时光标为空):

In onCreate, set up the adapter (note that the cursor is null at this point):

String[] from = new String[] { TodoTable.COLUMN_SUMMARY, TodoTable.COLUMN_ID};
int[] to = new int[] { R.id.label };
adapter = new SimpleCursorAdapter(this, R.layout.todo_row, null, from, to, 0);  //Note that the cursor is null
lw.setAdapter(adapter);

启动加载器:

getLoaderManager().initLoader(0, null, this);

这会在后台线程中调用 onCreateLoader(因此,如果您的查询长时间运行,它不会阻塞 UI 线程).完成后,在 UI 线程上调用 onLoadFinished,您可以在其中交换新光标.

This calls onCreateLoader in a background thread (so if your query is long running it won't block the UI thread). When it finishes, onLoadFinished is called on the UI thread where you can swap in the new cursor.

执行删除或更新后,重新启动加载程序:

After you do a delete or update, restart the loader:

getLoaderManager().restartLoader(0, null, this);

这会调用 onLoaderReset 从适配器中移除现有的游标,然后再次调用 onCreateLoader 以换入一个新的游标.

This calls onLoaderReset which removes the existing cursor from the adapter and then calls onCreateLoader again to swap in a new one.

最后添加这些方法:

public Loader<Cursor> onCreateLoader(int id, Bundle args)
{
    String[] from = new String[] { TodoTable.COLUMN_SUMMARY, TodoTable.COLUMN_ID};
    String where = TodoTable.COLUMN_DELETED + " = ?";

    Loader<Cursor> loader = new CursorLoader(this, TodoContentProvider.CONTENT_URI, from, where, new String[] {"0"}, null);     
    return loader;
}

public void onLoadFinished(Loader<Cursor> loader, Cursor cursor)
{
    adapter.swapCursor(cursor);
}

public void onLoaderReset(Loader<Cursor> loader)
{
    adapter.swapCursor(null);
}

这篇关于数据库更新和adapter.notifyDataSetChanged()后列表视图未更新;的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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