Best Way to Refresh Adapter/ListView on Android - android

My book, "Hello Android" gives this as a way of using a custom db helper, setting up a cursor, and then setting up an adapter as follows:
Cursor cursor
CustomDatabaseHelper test = new CustomDatabaseHelper(this);
try {
cursor = getData();
showData(cursor);
} finally {
test.close();
}
With this however, everytime I need to refresh the data set, I need to keep running this block of code (which gets a bit difficult inside an onClick() for a button due to "this" not being available.
Is this the best way to refresh the data set, or should I look towards removing the .close and issue an adapter.notifyDataSetChanged()? If I do this, sometimes I get a force close as (and I can't remember at the moment) but sometimes it cannot Delete properly - I think this may be because the database is currently open and it tries to open again.
Should we also be declaring the variables for the Cursors, DatabaseHelpers and Adapter in the Class (outside of the OnCreate) so that they are accessible to all the functions?
I realise this is just poor programming at this stage, but Im trying to get some pointers as to the best way of doing things.

You should use adapter.notifyDataSetChanged(). What does the logs says when you use that?

Simply add these code before setting Adapter it's working for me:
listView.destroyDrawingCache();
listView.setVisibility(ListView.INVISIBLE);
listView.setVisibility(ListView.VISIBLE);
Or Directly you can use below method after change Data resource.
adapter.notifyDataSetChanged()

Best Way to Refresh Adapter/ListView on Android
Not only calling notifyDataSetChanged() will refresh the ListView data, setAdapter() must be called before to load the information correctly:
listView.setAdapter(adapter);
adapter.notifyDataSetChanged();

Following code works perfect for me
EfficientAdapter adp = (EfficientAdapter) QuickList.getAdapter();
adp.UpdateDataList(EfficientAdapter.MY_DATA);
adp.notifyDataSetChanged();
QuickList.invalidateViews();
QuickList.scrollBy(0, 0);

adapter.notifyDataSetChanged();

If nothing works, just create the adapter instance again with the new set of results or the updated set of results. Then you can see the new view.
XYZAdapter adbXzy = new XYZAdapter(context, 0, listData);
xyzListView.setAdapter(adbXzy);
adbXzy.notifyDataSetChanged();

If you are using LoaderManager try with this statement:
getLoaderManager().restartLoader(0, null, this);

Perhaps their problem is the moment when the search is made in the database. In his Fragment Override cycles of its Fragment.java to figure out just: try testing with the methods:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_x, container, false); //Your query and ListView code probably will be here
Log.i("FragmentX", "Step OnCreateView");// Try with it
return rootView;
}
Try it similarly put Log.i ... "onStart" and "onResume".
Finally cut the code in "onCreate" e put it in "onStart" for example:
#Override
public void onStart(){
super.onStart();
Log.i("FragmentX","Step OnStart");
dbManager = new DBManager(getContext());
Cursor cursor = dbManager.getAllNames();
listView = (ListView)getView().findViewById(R.id.lvNames);
adapter = new CustomCursorAdapter(getContext(),cursor,0);// your adapter
adapter.notifyDataSetChanged();
listView.setAdapter(adapter);
}

Just write in your Custom ArrayAdaper this code:
private List<Cart_items> customListviewList ;
refreshEvents(carts);
public void refreshEvents(List<Cart_items> events)
{
this.customListviewList.clear();
this.customListviewList.addAll(events);
notifyDataSetChanged();
}

just write in your Custom ArrayAdaper this code:
public void swapItems(ArrayList<Item> arrayList) {
this.clear();
this.addAll(arrayList);
}

Related

Android SwipeRefreshLayout refresh listview with blinks

I have a listview wrapped in a SwipeRefreshLayout. The listview renders very smoothly in anytime I update it with new data. But whenever I pull down SwipeRefreshLayout to get new messages,the listview gives me a blink effect which is negative in terms of user experience. I found nothing useful to fix this issue after searching a lot on the internet.Can any one teach me how to resolve this problem.
Below is part of my code:
public void fetchMoreMsgs(){
sizeOfChatLV=chatLVArray.size();
if(lvPos==0){
toast = Toast.makeText(ma,"No more messages",Toast.LENGTH_SHORT);
toast.setGravity(Gravity.CENTER,0,0);
toast.show();
return;
}else {
if(lvPos-fetchStep>=0){
arrayList = chatLVArray.subList(lvPos-fetchStep, lvPos);
msgsList.addAll(0, arrayList);
chatLVArrayAdapter = new ChatLVArrayAdapter(ma, msgsList);
ma.chatListViewIMP2P.setAdapter(chatLVArrayAdapter);
ma.chatListViewIMP2P.setSelection(fetchStep);
lvPos-=fetchStep;
}else {
arrayList = chatLVArray.subList(0, lvPos);
msgsList.addAll(0, arrayList);
chatLVArrayAdapter = new ChatLVArrayAdapter(ma, msgsList);
ma.chatListViewIMP2P.setAdapter(chatLVArrayAdapter);
ma.chatListViewIMP2P.setSelection(lvPos);
lvPos=0;
}
}
}
The fetchMoreMsgs method is called when I pull down the listview(wrapped in a SwipeRefreshLayout).Any help is much appreciated!
Whenever you call setAdapter, it completely destroys every view in the ListView and then creates it anew. This is what causes your blinking effect.
Instead, your chatLVArrayAdapter should have a way to updating the underlying list and then you should call your adapter's notifyDataSetChanged() to tell ListView the data has changed.

How to restore to the previous state in RecyclerView after loading more data

I have been working with RecyclerView for a while. I am following lazy loading, so I am showing 10 data on the view each time. If user scroll to the bottom, the page re-load from the TOP! however, I want to stay where it was previously! So, I have tried to use
recyclerView.scrollToPosition(position);
However, this breaks the UI flow!
My second try is using onSaveInstanceState() and onRestoreInstanceState(Bundle state); However, that does not work! My page is re-loads to the top!
Parcelable state = layoutManager.onSaveInstanceState();
layoutManager.onRestoreInstanceState(state);
I have tried every other methods, apparently none is working for me!
Any help would be highly appreciated! Thanks in advance!
Note : Make sure that you are not initialising or calling setAdapter() method each time after updating your dataset. If not, then
You have to update your data list and call notifyDataSetChanged() which will update your adapter from existing position.
Let's say you have stored your data into ArrayList mData;
Your getItemCount() would be
#Override
public int getItemCount() {
if (mData != null && mData.length() > 0)
return mData.size();
return 0;
}
Now create one more method in your adapter which you will called each time whenever you will get new data from server. This method will simply override your dataset and will update your adapter
private void updateDataSet(ArrayList<String> mData){
this.mData = mData;
notifyDataSetChanged();
}
I have done this functionality before 2 days ago
I share my idea with you
Make
Listview lv; //Assume Find view by Id
List<Model> models = new ArrayList();
Now Make an Adapter and assign blank models
CustomAdapter adapter = new CustomeAdapter(context,models);
lv.setAdapter(adapter);
Now when you have new data to load with lazylodaing
do this
models.addAll(newModels); //new ModelList
adapter.notifyDataSetChanged();
Thats it.
This is the default behaviour Recycler View to recycle/resuse views. As in official docs:
https://developer.android.com/reference/android/support/v7/widget/RecyclerView.html
If you are having any view related issues then save your view state in your List<Object> like setting visible item or not per position. And in your onBindViewHolder method as per position show/hide your view.

How to refresh two listview at one moment in Android?

I have two listview, like listview_1 and listview_2. I wanna refresh the listview_2 while listview_1 is refreshed.
My code like this:
public void updateTwoListView() {
listview_1.getAdapter().notifyDataSetChanged();
listview_2.getAdapter().notifyDataSetChanged();
}
But it don't work, listview_1 can refresh but the listview_2 can't.
And at that moment what I found is that listview_1 was on focus.
And then I tried to set focus to other views before ran the method, both of them didn't refresh. It likes to refresh a listview only if the listview has focus.
What's more I found that when I called the method to refresh, listview_2 didn't, and then I set focus to listview_2, refreshed itself!
So, What all I want to ask is:
How to refresh two listview at one moment in Android?
What's more code:
//init two listview there
public void init() {
listview_1 = (ListView)findViewById(R.id.listView1);
listview_2 = (ListView)findViewById(R.id.listView2);
adapter1 = new MyListViewAdapter(mContext);
adapter2 = new MyListViewAdapter(mContext); //I have tried use different adapter, that also didn't work.
listview_1.setAdapter(adapter1);
listView_2.setAdapter(adapter2);
}
the real code of upside snippet is:
public void updateTwoListView(int currentPosition) {
adapter1.updateCurPos(currentPosition);
adapter2.updateCurPos(currentPosition);
}
and in MyListViewAdapter.java:
public void updateCurPos(int currentPosition) {
mCurrentPos = currentPosition;
notifyDataSetChanged();
}
And I will call method like listViewManager.updateTwoListView(1) outside to refresh.
Any reply is appreciated.
You have called listview_1 twice. Just change one of them to listview_2 as below:
public void updateTwoListView() {
listview_1.getAdapter().notifyDataSetChanged();
listview_2.getAdapter().notifyDataSetChanged();
}
It seems the problem of your code is that you call getAdapter().
Sets the data behind this ListView. The adapter passed to this method may be wrapped by a WrapperListAdapter, depending on the ListView features currently in use. For instance, adding headers and/or footers will cause the adapter to be wrapped.
Source: http://developer.android.com/reference/android/widget/ListView.html#setAdapter(android.widget.ListAdapter)
The solution is save your Adapter as member variable in your activity and call the notifyDataSetChanged()from there.
See more on this question's answer: https://stackoverflow.com/a/31893525/2742759

Updating adapter with AsyncTaskLoader in a regular (support) Fragment not updating ListView

I'm having trouble using the AsyncTaskLoader callbacks to update an adapter in a regular Fragment. I'm using the fragment support library, version 19.1.0.
In my onLoadFinished() callback I simply do an mAdapter.addAll(data). I used the debugger to verify that the callback is called and that all of the data is added to the adapter. The problem is that the list view simply won't update.
I've already tried notifyDataSetChanged() and invalidateViews() - no effect.
All examples or tutorials I've seen so far use a ListFragment or ListActivity without a custom layout; I've tried this and it works fine. In particular, I've tried the sample program from Android Design Patterns loader tutorial. Unfortunately, I can't use ListFragment because I'm using the StickyListHeaders library (but even trying this with a regular ListView doesn't work).
I get the same results when modifying the above sample program to use a Fragment instead of ListFragment by removing the ListFragment-specific method calls and inflating a custom view. The relevant code boils down to this:
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mAdapter = new AppListAdapter(getActivity());
getLoaderManager().initLoader(LOADER_ID, null, this);
}
#Override
public View onCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View v = inflater.inflate(R.layout.list_layout, container, false);
ListView listView = (ListView) v.findViewById(android.R.id.list);
listView.setAdapter(mAdapter);
return v;
}
#Override
public void onLoadFinished(Loader<List<AppEntry>> loader, List<AppEntry> data) {
mAdapter.setData(data);
}
As I said before, the adapter gets updated but the list view simply won't redraw, even if you add in notifyDataSetChanged and call invalidateViews on the listView. I'm finding it hard to figure out what's going wrong here.
Turns out that the problem was initializing the adapter in onActivityCreated, as it's called after onCreateView - so setAdapter was being passed a null value (and it doesn't complain about that). This wasn't a problem in the ListFragment and ListActivity implementations I'd looked at as you can use their setListAdapter method to associate the adapter with the list view, without keeping your own explicit reference to it. A silly mistake :\
I've run into similar problems before. The root of mine seemed to be not calling notifyDataSetChanged from the ui thread. Your problem may be similar, try:
yourContext.runOnUiThread(new Runnable() {
public void run() {
mAdapter.notifyDataSetChanged();
}
});
And let me know if it works for you.

ListView freaks out when I try to update the ArrayAdapter, is the header?

I have this ListView that is using an array adapter:
//global
ArrayList<Location> locations=new ArrayList<Location>(); //array list of location objects
ArrayAdapter<Location> theLocations;
ListView listView;
then in onCreateView of my Fragment:
theLocations = new ArrayAdapter<Location>(mContext,
R.layout.location_row, locations);
listView.setAdapter(theLocations);
This works pretty well I think, though if I try to update this adapter it freaks out...
//in my fragment, another dialog makes this call here to update the list.
public void onUIUpdate(Location l) { //listener call back when dialog "ok" clicked
locations.add(l); //it is okay with this.
theLocations.notifyDataSetChanged(); //dies
}
It dies with the error:
07-23 08:03:28.655: ERROR/AndroidRuntime(509): java.lang.IllegalStateException: ArrayAdapter requires the resource ID to be a TextView
does that mean it doesn't like the Location in the ArrayAdapter ??? does this mean I have to make my own custom listadapter? If I don't call theLocations.notifyDataSetChanged() everything is okay but then nothing updates... :(
I should note that the toString() in the Location class is override to return a String name;
after a comment I tried this:
public void onUIUpdate(Location l) {
locations.add(l);
//theLocations.notifyDataSetChanged();
WrapperListAdapter wr = (WrapperListAdapter)listView.getAdapter();
ArrayAdapter aa=(ArrayAdapter)wr.getWrappedAdapter();
aa.notifyDataSetChanged();
}
LOL no luck here, was a stab in the dark. Also wandering if its the addHeaderView I used on the ListView? I am not sure if it makes it immutable in the future using addHeaderView?
I won't comment about ListView design, it is very ugly, but I do listView.getAdapter().getWrappedAdapter().notifyDataSetChabged(); and it works.

Categories

Resources