How to update listview whose data was queried from

2019-02-16 02:00发布

问题:

I want to show the items queried from database in the listview with SimpleCursorAdapter. For example, there may be 20,000 items in the database. I want to just load 100 items(_id : 1-100) queried instead of load all items, when scrolling in the end of listview, load another 100 items(_id : 101-200) queried, how to achieve it? Any suggestion is welcome, thanks.

Relative codes are as follows:

protected void onCreate(Bundle savedInstanceState) {
    mCursor = managedQuery(CONTENT_URI, PROJECTION, null, null, "_id DESC");
    mAdapter = new SimpleCursorAdapter(this,R.layout.list_content,  mCursor, keys,  values);
    setListAdapter(mAdapter);
}

In my defined listview, i want to load more items by query database.

public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) 
{
    int lastItem = firstVisibleItem + visibleItemCount - 1;

    if (mListAdapter != null) {
        if ((lastItem == mListAdapter.getCount()-1) && (mRefreshState != REFRESHING)) {
            mFooterView.setVisibility(View.VISIBLE);
            mRefreshState = REFRESHING;
            new Handler().postDelayed(new Runnable() {  
                public void run() {  
                    //execute the task ,  i want to load more items by query database
                    RefreshListView(LOADING_STORED_INFO);                                           
                }  
             }, DEFAULT_DELAY_TIMER);           
        }
    }
}

In the AsyncTask loading data, i do the query operation.

    protected Integer doInBackground(Integer... params)
    { 
        Uri uri = ContentUris.withAppendedId(CONTENT_URI, mCursor.getInt(0)-1);
        cursor = managedQuery(uri, PROJECTION, null, null, "_id DESC");
        return (0 == params[0]) ? 1 : 0;
    }

    @Override
    protected void onPostExecute(Integer result)
    {
        mAdapter.changeCursor(cursor);//is this OK?
        mAdapter.notifyDataSetChanged();
        /*
        if (1 == result)
        {
            mListView.setSelection(1);
        }
        else
        {
            mListView.setSelection(mCount-1);               
        }*/
        // Call onRefreshComplete when the list has been refreshed.
        mListView.onRefreshComplete(result); 
        super.onPostExecute(result);
    } 

回答1:

Use the LIMIT statement in the SQL query in this way:

SELECT your_column FROM your_table ORDER BY your_order LIMIT limit_skip, limit_count

Then you can use a OnScrollListener to retrieve the index of the first visible cell and the number of visible cells so you can increment limit_skip and limit_count coherently.

Instead of the generic AsyncTask use a CursorLoader and implement LoaderManager.LoaderCallbacks<Cursor> as follow:

public Loader<Cursor> onCreateLoader(int id, Bundle args){
    String orderBy = "_id DESC"
    if(args != null){
        orderBy += " LIMIT " + args.getInt("LIMIT_SKIP") + "," + args.getInt("LIMIT_COUNT");
    }

    return new CursorLoader(this /*context*/, CONTENT_URI, PROJECTION, null, null, orderBy);
}

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

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

Then, in onCreate(), pass null as cursor to new SimpleCursorAdapter() and create the CursorLoader in this way:

getLoaderManager().initLoader(0, null, this /*LoaderCallbacks<Cursor>*/);

Then, in onScroll(), reset everytime the loader in this way:

Bundle args = new Bundle();
args.putInt("LIMIT_SKIP", limit_skip_value);
args.putInt("LIMIT_COUNT", limit_count_value);
getLoaderManager().restartLoader(0, args, this /*LoaderCallbacks<Cursor>*/);