如何使用 CursorLoader 来一一显示各个数据库记录

发布于 2024-12-24 16:00:35 字数 2052 浏览 1 评论 0原文

我正在尝试创建一个 ContentProvider ,其中每条记录都包含一个问题和相应的答案。还有一个显示每个问题和答案的 TextView 的 Activity,以及这些 TextView 下方的“下一步”按钮。单击“下一步”按钮时,我希望显示下一个问题和答案。

我正在尝试使用 CursorLoader 和 LoaderManager,因为 CursorLoaders 在 onStop()onStart() 之间保存数据,并且我正在尝试了解 CursorLoadersLoaderManagers

我发现的示例都使用 setListAdapter(),但我不希望我的活动看起来像一个列表。我尝试通过使用 SimpleCursorAdapter 并在我的 main.xml 布局中使用 bindView() 来解决这个问题。不确定这是否有效。

如果我有一个普通的游标,我会使用 moveToNext(),但对于 LoaderManager 来说,我似乎必须使用新查询 restartLoader() 。我认为创建一个新查询比简单地使用游标转到下一条记录会花费更多时间。特别是因为我必须知道当前或下一条记录的位置。

所以我的问题是:我可以使用 CursorLoader 和 LoaderManager 逐条记录地浏览数据库,而不必为下一条记录进行新查询吗?或者 CursorLoadersLoaderManagers 真的只适用于 ListViews 吗?

这是到目前为止我的代码,我意识到它并不多,但我已经阅读并重新阅读了 Android 关于 Loaders 和 LoadManagers 的页面。

 public class Main extends Activity implements LoaderManager.LoaderCallbacks<Cursor>{

SimpleCursorAdapter adapter;
String curFilter;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    this.adapter = new SimpleCursorAdapter(getApplicationContext(),
                                           R.layout.main,
                                           null,
                                           new String[]{},
                                           new int[]{R.id.questionText,R.id.answerText},
                                           0);
    LinearLayout mainLayout = (LinearLayout)findViewById(R.id.mainLayout);

    this.adapter.bindView(mainLayout, getApplicationContext(), null);

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

    Button nextQuestionButton = (Button)this.findViewById(R.id.Nextbutton);

    nextQuestionButton.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick (View v) {
        }               
    });
}

I'm trying to make a ContentProvider with each record containing a question and corresponding answer. And an Activity showing TextViews of each question and answer and a "Next" button below those TextViews. When the Next button is clicked I would like the next question and answer to show.

I'm trying to use a CursorLoader and LoaderManager, because the CursorLoaders keep their data across onStop() and onStart(), and I am trying to learn about CursorLoaders and LoaderManagers.

The examples I have found all use setListAdapter(), but I don't want my activity to look like a list. I've tried to go around this by using a SimpleCursorAdapter and using bindView() to my main.xml layout. Not sure that is going to work.

If I had a plain Cursor I would use moveToNext(), but for a LoaderManager it seems I have to restartLoader() with a new query. I think creating a new query would cost more time than simply going to the next record with a cursor. Especially since I would have to know the position of the current or next record.

So my question is: Can I use a CursorLoader and LoaderManager to go through a database, record by record without having to make a new query for the next record? Or are CursorLoaders and LoaderManagers really only for ListViews?

Here is my code so far, I realize it's not much, but I have read and re-read Android's pages on Loaders and LoadManagers.

 public class Main extends Activity implements LoaderManager.LoaderCallbacks<Cursor>{

SimpleCursorAdapter adapter;
String curFilter;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    this.adapter = new SimpleCursorAdapter(getApplicationContext(),
                                           R.layout.main,
                                           null,
                                           new String[]{},
                                           new int[]{R.id.questionText,R.id.answerText},
                                           0);
    LinearLayout mainLayout = (LinearLayout)findViewById(R.id.mainLayout);

    this.adapter.bindView(mainLayout, getApplicationContext(), null);

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

    Button nextQuestionButton = (Button)this.findViewById(R.id.Nextbutton);

    nextQuestionButton.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick (View v) {
        }               
    });
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

暗地喜欢 2024-12-31 16:00:35

我知道我的问题很模糊,我真的很迷茫。这是我几个月后的回答,希望它对处于我过去处境的人有所帮助。

当我调用 getLoaderManager().initLoader() 或内容提供程序发生更改时(内容提供程序必须调用 getContentResolver().notifyChange() 才能正常工作), onCreateLoader() 会自动调用。我提供了在覆盖方法 LoaderManager.LoaderCallbacks.onCreateLoader() 时制作游标加载器的代码。游标加载器会自动交给 onLoadFinished()。就这样,我不再碰光标加载程序。自动调用的 onLoadFinished() 接收一个游标(由游标加载器生成)作为参数。我使用游标参数 this.adapter.setCursor(cursor) 在 onLoadFinished() 的重写中更新适配器。

SimpleCursorAdapter 没有 moveToNext 或 moveToPrevious,所以我做了一个 SteppedAdapter,如下所示:

public class SteppedAdapter {
    private Cursor cursor = null;
    // This class uses a reference which may be changed
    // by the calling class.
    public SteppedAdapter (Cursor cursor) {
    this.cursor = cursor;
    }

    private int getColumnIndexOrThrow (String columnName) {
    return cursor.getColumnIndexOrThrow(columnName);
    }   

    public void moveToNext () {     
    if (null != cursor && !cursor.isClosed()) {
        if (cursor.isLast()) {
            cursor.moveToFirst();
        }
        else {
            cursor.moveToNext();
        }
    }   
    }

    public void moveToPrevious () {
    if (null != cursor && !cursor.isClosed()) {
        if (cursor.isFirst()) {
            cursor.moveToLast();
        }
        else {
            cursor.moveToPrevious();
        }
    }
    }

    public String getCurrentTarget (String targetColumn) throws EmptyCursorException {
    int idx = cursor.getColumnIndex(targetColumn);  
    String value = null;
    try {
        value = cursor.getString(idx);  
    }
    catch (CursorIndexOutOfBoundsException e){
        if ( 0 == cursor.getCount()) {
            throw new EmptyCursorException("Cursor is empty: "+e.getMessage()); 
        }
        else {
            throw e;
        }
    }
    return value;
    }   

    public void setCursor (Cursor cursor) {
    this.cursor = cursor;
    }

    public void setCursorToNull () {
    this.cursor = null; 
    }

    public int getPosition () {
    return this.cursor.getPosition();
    }

    public boolean cursorIsClosed () {
    return this.cursor.isClosed();
    }   

    public int getCount () {
    return cursor.getCount();
    }
} // end

由于适配器是在 onLoadFinished() 中使用适配器.setCursor(Cursor) 方法设置的,并在 onLoaderReset() 中使用适配器.setCursorToNull 方法清除的()。那么适配器就必须有这些方法。

I understand that my question was vague, I was really lost. Here's my answer, many months later, hope it helps someone who is in my past position.

onCreateLoader() is automatically called when I call getLoaderManager().initLoader() or when there has been a change to the content provider (content provider has to call getContentResolver().notifyChange() for this to work). I provide the code to make the cursor loader when overwriting the method LoaderManager.LoaderCallbacks.onCreateLoader(). The cursor loader is automatically handed to onLoadFinished(). That's it, I don't touch the cursor loader again. onLoadFinished(), which is called automatically, receives a cursor (made from the cursor loader) as an argument. I update the adapter in my override of onLoadFinished() using the cursor argument, this.adapter.setCursor(cursor).

SimpleCursorAdapter doesn't have a moveToNext or moveToPrevious, so I made a SteppedAdapter, see below:

public class SteppedAdapter {
    private Cursor cursor = null;
    // This class uses a reference which may be changed
    // by the calling class.
    public SteppedAdapter (Cursor cursor) {
    this.cursor = cursor;
    }

    private int getColumnIndexOrThrow (String columnName) {
    return cursor.getColumnIndexOrThrow(columnName);
    }   

    public void moveToNext () {     
    if (null != cursor && !cursor.isClosed()) {
        if (cursor.isLast()) {
            cursor.moveToFirst();
        }
        else {
            cursor.moveToNext();
        }
    }   
    }

    public void moveToPrevious () {
    if (null != cursor && !cursor.isClosed()) {
        if (cursor.isFirst()) {
            cursor.moveToLast();
        }
        else {
            cursor.moveToPrevious();
        }
    }
    }

    public String getCurrentTarget (String targetColumn) throws EmptyCursorException {
    int idx = cursor.getColumnIndex(targetColumn);  
    String value = null;
    try {
        value = cursor.getString(idx);  
    }
    catch (CursorIndexOutOfBoundsException e){
        if ( 0 == cursor.getCount()) {
            throw new EmptyCursorException("Cursor is empty: "+e.getMessage()); 
        }
        else {
            throw e;
        }
    }
    return value;
    }   

    public void setCursor (Cursor cursor) {
    this.cursor = cursor;
    }

    public void setCursorToNull () {
    this.cursor = null; 
    }

    public int getPosition () {
    return this.cursor.getPosition();
    }

    public boolean cursorIsClosed () {
    return this.cursor.isClosed();
    }   

    public int getCount () {
    return cursor.getCount();
    }
} // end

Since the adapter is set in onLoadFinished() using the method adapter.setCursor(Cursor), and cleared in onLoaderReset() using the method adapter.setCursorToNull(). Then the adapter has to have these methods.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文