I want to have a Button that when clicked, removes all the checked items in the ListView. I already have all the xml items set up, I just don't know how to write the java code.
The ListView displays data that comes from an Adapter. In order to remove items from the view the item needs to be removed from the Adapter and the view notified. In android the Adapter notifies the view by calling notifyDataSetChanged().
How to remove an item from the adapter depends on your particular adapter. The SimpleCursorAdapter gets its data from an underlying Cursor. To remove an item, the item should be removed from the underlying Cursor. For example using a SQLiteCursor a row in the database needs to be deleted.
If you use the ArrayAdapter just call remove(T object) on the adapter. It will automagically call notifyDataSetChanged() for you.
update:
I saw the code at git hub. Here are some pointers as how to get your app working as soon as possible.
Try refactoring your code in to smaller graspable parts. Start with extracting some methods to give parts of the large method understandable names.
The problem is that there might by hundreds of rows in the database and only enough views to fill the screen. Nowhere is it remebered what rows are checked, hence its not possible to remove them. You probably need to extend BaseAdapter or SimpleCursorAdapter to hold the state (checked or not) of the rows. Read up on the excellent android documentation.
My point here is there is a distinction between the view, your CheckBox, and the model containing the data to display. So check out Model-View-Controller. You can ignore the concept of controller for now.
Related
I need the functionality to update the data in the item in the recycler view. right now, If we notify the whole item it shows some fluctuation and we want to avoid refreshing the whole item on the UI.
I am using the ListAdapter with diff utils.
There are many ways to achieve your goal.
self-managing items. Adapter doesn't know anything about content of the items, it only puts items into RecyclerView. Content is managed by the item itself, so your problem is already solved.
custom adapter. Adapter has intricate knowledge about every item and can update selected ones accordingly.
AsyncListDiffer You can add differ to your adapter and it will take care of not updating parts that need no update.
Without seeing your code, we can't tell which way would be the most appropriate for you, but I guess adding differ is the simplest on already working code.
You need to create custom Adapter:
https://developer.android.com/develop/ui/views/layout/recyclerview
If you're talking about updating specific list items, and you're not using a DiffUtil (which will handle it for you) then you need to call the appropriate notify* method on your Adapter.
They fall into two categories, item change events (where the item list stays the same, but the displayed data for one or more of those items changes) and structural change events (where the actual list of items changes in some way, e.g. insertion/removal, or reordering).
I'm assuming you just want to update the displayed data for an item, so you should use one of the notifyItemChanged or notifyItemRangeChanged methods to inform the adapter that a certain item (or range of items) needs to update. If any of those items are currently being displayed in a ViewHolder, then onBindViewHolder will get called again for those items - which is where you set all your text, images etc depending on the item you're displaying. So you'll update them with the current data.
Both those methods have a version that takes a payload Object/Any, where you can pass in some data to be used in a partial bind - basically, onBindViewHolder can receive that data and be smarter about the update, which means you can avoid things like reloading images, etc. by passing in some stuff and checking for it during the binding process. More info about that here in the other version of onBindViewHolder you can implement, if you need to.
I'll try to be as specific as possible. I have a cursor-backed RecyclerView adapter. I'm using LoaderManager callbacks to get updates when the DB values change, which gives me a new cursor. I'm then comparing the new cursor with the one the adapter currently holds to figure out what's changed, switching out the old one with the new one in the adapter, and then calling the appropriate notifyItem(Range)Inserted/Changed/Removed() functions. This works great, but there are some places I'd like to use it that can have some pretty big cursors, so I'm hoping to optimize it by figuring out which items are visible using the layout manager and then only checking those items in the cursor for changes instead of checking every single row.
Now my question is, let's say I have a cursor with 1000 rows, and my RecyclerView is showing say rows 0-10. I can go through the cursors, checking the items at index 0-10 for changes/additions/deletions and call the appropriate notify() functions as I'm currently doing, but what about the non-visible items? Do I have to notify the adapter that there may be changes in those rows or can I safely just ignore them and it will just use the updated data when those rows get bound?
Edits for clarity, my code flow is like this:
My adapter holds a cursor, getItemCount just returns cursor.count() and the ViewHolder binding code is along the lines of cursor.moveToPosition(position) followed by some things like ViewHolder.setFoo(cursor.getString(BAR))
When something changes in the DB, the LoaderManager callbacks call onLoadFinished with an updated cursor, and then that calls adapter.changeCursor(newCursor)
changeCursor basically iterates over the old and new cursor to check what's changed. That works fine, but if the cursor is very large it might take some time to loop the whole thing, so I was hoping to be able to skip everything except the visible items. If I do that, changes work fine since onBindViewHolder will use the updated cursor, but if a (non-visible) row is added or deleted and I don't call notifyItemInserted/Removed, the adapter doesn't know about it and doesn't handle it properly, which leads me to believe that I can't do this optimization, I have to just loop the whole thing to find added/removed rows
Your intuition is correct.
You don't need to concern yourself with the non-visible items. When the LayoutManager eventually places them on-screen, you will get a call to bindViewHolder in the adapter. It is here where you'll reflect the current state of the adapter (which has your cursor) in your view.
When I render / update the list view after the service get's new data the order of the list items is changing every time.
The ArrayAdapter has an ArrayList member and all the items are in correct order until shown on the screen. I also have two ItemViewTypes, one for the header of the items and one for the items of course. This is rendered with the ViewHolder "pattern".
I guess I'm missing something silly.
What could cause such behavior?
My guess is that ArrayAdapter holds it's own shallow copy of the List you provide on instantiation of the ArrayAdapter. If this assumption holds true, the consequence is that modifications of list items are shown by the ListView while modifications of the list item order will not be reflected.
If your list items are comparable so that the required order can be recovered, you could call the ArrayAdapter.sort(Comparator comp) method and the ArrayAdapter.notifyDataSetChanged() method afterwards. In my case even the scroll position was preserved perfectly.
However, you could also try to use the add and remove methods of ArrayAdapter to update the adapter itself.
I'd like to display a few (5-ish) items from a Cursor in a list, and I'd like to keep it in sync with the content of the cursor (which in turn points to a database), but I don't want to use ListViews. Instead, I'd like to populate a plain old LinearLayout.
I seem to understand that I need to create a custom CursorAdapter and override the newView() and bindView() methods. What I don't understand is who is responsible for iterating over the cursor's items (does the CursorAdapter do it? Should my code do it?), how do the views for each item get parented to the LinearLayout and who is responsible for creating new views for new items in the cursor or removing views for items that are no longer available through the cursor?
Somehow I have a hunch that the CursorAdapter does already most of the work, but I can't quite put together all the pieces of the puzzle. Do I just inflate a row layout in newView() and add it to the LinearLayout directly? And how does a row gets removed if the cursor no longer has the associated data?
Thanks for your help!
Manu
Well, I would do the following:
Create a custom class, a subclass of LinearLayout, just to make it simple. Let's call it MyList
You pass the CursorAdapter instance to this class (eg. create a setAdapter method)
When receiving the adapter, MyList will register for data changes (CursorAdapter.registerDataSetObserver). When the data set changes, call a method "populate"
When receiving the adapter, also call "populate" directly, to get the initial contents
Implement MyList.populate:
** call removeAllViews
** for each item (iterate through the cursor) call addView(CursorAdapter.newView(getContext(), cursor, this))
That's it in short. Of course later on you might want to optimize it, and keep the old views and use CursorAdapter.bindView instead, so you wouldn't need to create new heavy java objects.
The CursorAdapter allows you to navigate a large list without having to have all the items loaded into memory. If you are just going to have a small handful of items then I would just iterate over them in your activity and update your view accordingly (adding views, setting text values, showing/hiding, etc.)
Use a CursorLoader. When ever there is a change in your content it will update automatically.
I am building an Inventory application. The items are shown in a grid view and each cell of the grid view also has a TextView in the upper right corner that displays the available quantity of the item. The user can single click on the gridview cell to increase the quantity or long click to decrease it.
I am currently using a class derived from SimpleCursorAdapter to display the data, but I am not sure about how to update the quantity in the DB. I am afraid that if I write directly to the DB and then create a new cursor and change cursor that the application might become bogged down if the user clicks repeatedly (say to add 10 items)
I have considered copying the data from the query cursor to an array in the Activity and then using an ArrayAdapter but this seems kludgy.
I have also thought about creating an array in my SimpleCursorAdapter which would cache items that have been modified and then save those items when pausing...
Is there a better way? A more Android way?
I guess this comes down to: what is the best way to make rapid changes in the DB and UI?
I don't know much about Cursors in this regard, but I would create a custom ArrayAdapter based on a model object rather than a Cursor. That's just a personal preference, but by doing this I don't have to make any assumptions about the Cursor implementation or know it inside and out.
Let's say you're displaying a collection of type Item in your grid. I would create a class called ItemsList that derives from ArrayList<Item> and my adapter would derive from ArrayAdapter<Item>. The reason you create a wrapper around the ArrayList is that you can allow the user to interact with it freely and mark it as "dirty" and allow it to update the database asynchronously. This way, you just call notifyDataSetChanged() on your adapter and you don't have to think about the overhead of updating the db...you've separated interacting with the collection being displayed and the process of updating the persistent storage.
Btw...this video is a must when working with ListViews and Adapters if you haven't already seen it:
http://www.youtube.com/watch?v=wDBM6wVEO70
You could use a regular listView and a regular Adapter with a list (arraylist) of items in it. Every time user clicks or long clicks you can edit the list in your adapter and notifyDataChanged() which will reflect the list changes on your listView. If you want to keep your list after user quits your application you can use either database(for bigger amount of data) or preferences (for smaller data amount).