I have one EditText which is used for the purpose of taking user input. Once the user enters certain data, the text changing listener associated with the EditText calls for a refreshed cursor and tries to update the result which is being displayed in the ListView, placed just below.
Everything is fine. But whenever any change in the search query occurs, the resulting cursor and ListView update takes some time, say around n seconds. During this span of n second, the UI stops (halts/hangs whatever you may call) and does not respond until a refreshed cursor is available and the entire ListView is populated.
When I tried to put the updating of the cursor in a different thread, it did not allow the same to be reflected in the UI as the UI-thread does not allow being commanded by other threads in action. Any UI activity such as the list update has to be implemented through runOnUiThread in the MainActivity class.
Kindly suggest ways by which I can allow the EditText to be modified by the user as well as the updated cursor refreshing the ListView happen without affecting the former.
Basically, you are trying the wrong approach. When we want the data for the list to be sourced directly from an SQLite database query, we can use a CursorAdapter.
Create an adapter
public class MyCursorAdapter extends CursorAdapter {
// Default constructor
public MyCursorAdapter(Context context, Cursor cursor, int flags) {
...
}
public void bindView(View view, Context context, Cursor cursor) {
...
}
public View newView(Context context, Cursor cursor, ViewGroup parent) {
...
return null;
}
}
Get Values from database
Cursor todoCursor = db.rawQuery("SELECT * FROM todo_items", null);
Now, we can use the CursorAdapter in the Activity to display an array of items into the ListView:
// Find ListView to populate
ListView lvItems = (ListView) findViewById(R.id.lvItems);
// Setup cursor adapter using cursor from last step
TodoCursorAdapter todoAdapter = new TodoCursorAdapter(this, todoCursor);
// Attach cursor adapter to the ListView
lvItems.setAdapter(todoAdapter);
This will then trigger the CursorAdapter iterating through the result set and populating the list. We can change the cursor to update the adapter at any time with:
// Switch to new cursor and update contents of ListView
todoAdapter.changeCursor(newCursor);
Related
I have a custom ListView and used CursorAdapter to expose data from a Cursor. One challenge I got was to add Serial number in each List Items. I know there has to be a column named "_id" and It's a primary field.
What I could do is add Serial number by grabbing up the value of "_id" column, But It was not possible because I showed all data in descending order.
Another way I tried was by declaring a variable and added 1 each time the item is created.
My Adapter class which extends CursorAdapter simply looks like this
public class BalanceInfoAdapter extends CursorAdapter {
Context context;
List<Balance> listOfBalance;
int serialNo = 0; //Declared as field
//Some constructers to initialise fields
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
serialNo+=1; //Added +1 to the variable
return LayoutInflater.from(context).inflate(
R.layout.myLayout, parent, false);
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
mySerialNumberTextView.setText(String.valueOf(serialNo)); //Shown Serial Number in a TextView of List Item
}
Problem
It worked fine till List Items fills the screen at first time. But as I scroll down and up, the way I mentioned above failed, because CursorAdapter recycles it's List Items as it is scrolled and Serial Number of first item became most higher.
Question
Is there any other way to add S/N in recycling List Items ? OR I can prevent this from happening in the same Adapter class.
You can use the public abstract int getPosition () method of Cursor.
For more reference click here
eg: int rowNum = cursor.getPosition();
Note: in public abstract void bindView (View view, Context context, Cursor cursor) method of CursorAdapter, cursor automatically moves to the current row.
So using cursor we can get the current row position in .
Picking up from the documentation http://developer.android.com/reference/android/widget/CursorAdapter.html#newView%28android.content.Context,%20android.database.Cursor,%20android.view.ViewGroup%29
public abstract View newView (Context context, Cursor cursor, ViewGroup parent)
cursor - The cursor from which to get the data. The cursor is already moved to the correct position.
So here cursor is already at its correct position. So you can use cursor.getPosition() method to get the correct serial number.
I'm sorry, I've tried looking at a bunch of other answers, but I can't get my particular implementation to work.
I have a ListView populated by an extended SimpleCursorAdapter. In the onCreate() method I set it up this way:
list = (ListView) findViewById(R.id.duty_history_list);
list.setOnItemClickListener(this);
list.setOnItemLongClickListener(this);
masterCursor = db.rawQuery("SELECT * FROM WorkLog", null);
list.setAdapter(new NotSoSimpleCursorAdapter(this,
R.layout.log_list_item,
masterCursor,
columns,
views,
CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER));
When an item is long clicked, the corresponding row is deleted from the db. Here is my attempt to update the view. With this code, nothing happens, I'm not sure why. IT is called at the very end of handleItemLongClick(), after the db is updated.
public void refreshView() {
CursorAdapter cA = (CursorAdapter) list.getAdapter();
masterCursor = db.rawQuery("SELECT * FROM WorkLog", null);
cA.changeCursor(masterCursor);
}
Hey i use a listview for demonstrate entries which are stored in a database. I also have a EditText element and a button which adds the content of the EditText into the Database. To bind the view to the database content i use the SimpleCursorAdapter and following populate function:
private void populate() {
cursor = dbAdapter.getAllItems();
startManagingCursor(cursor);
String[] from = new String[] { DBAdapter.KEY_TASK };
int[] to = new int[] { android.R.id.text1 };
// Now create an array adapter and set it to display using our row
cursorAdapter = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_1, cursor, from, to);
list.setAdapter(cursorAdapter);
}
If i added a new entry, by clicking on the button i want to refresh the listview but this only works with the populate function and not with the common adapter function notifyDataSetChanged();. Do i have a bug or is this the right way to refresh a listview?
Have you seen this, tried the swap cursor method, or tried just simply calling setAdapter() again?
I had a similar issue where I could not get my list to update, and what I did was just create a refreshListView() method. Now you can call this initially from your onCreate(), AND anytime a user adds something to the DB. All it does is re-bind the listview to a cursor. With all the deprecating methods (requery()), and issues with notifyDataSetChanged(), I decided this was the easiest way.
Please refer this link...it works like charm
Update SimpleCursorAdapter while maintaining scroll position in ListView
for dynamic listview on scroll i added new item from database ..
I did mistake here ..
i was assigning new adapter for each time for same simplecursoradapter .
Instead of creating new adapter.
just use
adapter.changecursor(newcursorValue);
adapter.notifydatasetChanged();
lsMedicine1.setSelectionFromTop(lsMedicine1.getLastVisiblePosition()-20, 0);
You need to call swapcursor() before notifyDataSetChanged() on the adapter.
I'm trying to implement a fast scroller with AlphabetIndexer, but when the cursor changes, its not refreshing the index chache. In my CursorAdapter constructor I call setCursor(cursor) but nothing changes, and acording to the documentation:
Your adapter is responsible for updating the cursor by calling
setCursor(Cursor) if the cursor changes. getPositionForSection(int)
method does the binary search for the starting index of a given
section (alphabet).
But nothing is happening. I'm using this for a search filter, so when I search contacts, it updates the list with the contacts, so AlphabetIndexer should work for update the index of the new items in the list.
Example: My whole list starts with contacts that starts with 'A' and ends with contacts that starts with 'E'. So the AlphabetIndexer will have this indexes in its cache.
But, lets try to search contacts with 'C', and lets say I have 250 contacts that starts with 'C'. So, I have to fast scroll through this contacts, and the 'C' index must show, but instead of only 'C' it shows all indexes, that were shown when I had the entire list.
Here is my CursorAdapter constructor where I call setCursor(cursor) for every letter I type:
public MyCursorAdapter(Context context, Cursor cursor, ArrayList<Integer> ids)
{
super(context, cursor);
try
{
mAlphaIndexer = new AlphabetIndexer(cursor, cursor.getColumnIndexOrThrow("Name")," ABCDEFGHIJKLMNOPQRSTUVWXYZ");
notifyDataSetChanged();
mAlphaIndexer.setCursor(cursor);
this.mSelectedContacts = ids;
Log.e("MyCursorAdapter", "construtor: ");
}
catch(Exception ex)
{
Log.e("MyCursorAdapter", "Error: " + ex);
}
finally
{
mAlphaIndexer.setCursor(cursor);
}
}
I've solved this by calling this in sequence after I set the adapter:
listView.setFastScrollEnabled(false);
listView.setFastScrollEnabled(true);
That worked for me.
call setContentView(R.layout.whatever)and then re-populate the ListView with your new adapter / new data items. This will redraw the ListView with your new items and the FastScroll Overlay will appear in the correct place.
Trying to use the FilterQueryProvider function to update the contents of a ListView, as characters are entered into the filter, my runQuery function does get called, and a new cursor with filtered content is returned, but the ListView does not update to show the new contents. The docs state that after runQuery returns, changeCursor is called. Isn't this enough to update the ListView display? My code to set up the filter is:
mAdapter = new ItemAdapter(curs);
mAdapter.setFilterQueryProvider(new ItemFilter());
setListAdapter(mAdapter);
And my filter class is simply:
class ItemFilter implements FilterQueryProvider {
public Cursor runQuery(CharSequence filter) {
return getNewCursor(filter);
}
}
The cursor from getNewCursor does correctly fetch a subset of the rows. Have I missed something in getting the ListView to update?