I have a ListView that I am calling smoothScrollBy() on. 95% of the time, the smoothScrollTo() behaves as intended. However there are times that it does not end up in the intended spot! I have verified that I am giving it the same value. I notice that the smooth scrolling is not so smooth when the errors are made, however there are no other tasks that my application is performing that I would have control over.
I am not quite sure what is going on in the background but a likely culprit is garbage collection.
95% accuracy is not good enough in this situation. I am going to have to implement some sort of a correction mechanism to make sure the ListView lands on the correct spot in these instances.
Is there a better way to use smoothScrollBy() other than simply calling view.smoothScrollBy(distance, time);?
sometimes it will be because of the timing issue. When the views are added to your listview and the time you do
view.smoothScrollBy(distance, time);
the listview or the ui still need not get refreshed. So do this in the views post thread with a specific delay. Eg.
view.postDelayed(new Runnable{
view.smoothScrollBy(distance, time);
},1000);
Try some of these:
Listview has its own scrolling mechanism. It scrolls when the content is added.
Assign listview height (android:layout_height) to match_parent or fill_parent.
If your assigning a adapter in a working thread. Do not perform any UI actions in the thread.
If these do not solve the issue. Please post the code where you assign the adapter to the list view if any. Or the relevant code.
Also the xml layout code.
Hope this helps.
Related
I am having nested scrollview with 100 layouts. All layouts are initially will be empty. When user scrolls and stops the scroll I will send request to the server and update the layout. I am facing issue doing both parallel. When request sent to server and receive response I am updating the layout using following code:
((Activity) ctContext)
.runOnUiThread(new Runnable() {
public void run() {
reDesignLayout(layoutID);
}
});
But the problem is I am not able to scroll the scrollview while updating. I tried with Handler and runOnUiThread. But both not able to scroll. Please help me on this.
I think the using of the Scrollview isn't suitable for your case.
Try to switch to RecyclerView with an adapter.
Benefits:
low memory usage
handling appear/disappear states of each item (the layout in your terms), you can start/stop/resume network call to reduce a workload on your server and etc..
flex the layout setup of each item.
If you want to update data in that process, you would need to create an id, find the view, and assign them each and every time. That would mean you would need to write code to assign 100 different ids to 100 different containers containing your views.
And assigning values to all of them would be a real pain, if not unreal. And it's not at all advised for this case.
Instead, I would recommend using a recycler view. Which is the best that is available. It decreases the amount of code you write and the memory space needed as it is based on the concept of reuse and helps populate data efficiently.
You could visit the link below, to learn more about recycler views. Hope it helps.Happy coding!
https://guides.codepath.com/android/using-the-recyclerview
I searched for hours but didn't find a suitable solution for me.
What I want to do: in my ListFragment I use the onListItemClick(...) method to handle the click events. Here, I change the background of the row item. But unfortunately every time the onListItemClick(...) is called, also the getView() from the adapter is called and updates all 8 visible row items. That takes to much time: 0.5 seconds. Because the row layout is pretty complex (2 Images, 8 TextViews).
So I want to update only the row which is clicked. I want to use this solution but that has no effect, when the other 7 row items are updated anyways.
I already followed these advices to speed the list up, but it's still to slow.
Any help, ideas and thoughts are appreciated. :)
Thank you!
[EDIT]
Thanks to CommensWare for giving me some new ideas. What I did now was to check what traceview says. And the result is, that the delay is devided in two parts. The first 300ms of the delay takes the "FastXMLSerialzier.escapeAndAppendString()" with over 22.000 calls. That seems a lot! In the second half, many, maybe all, onMeasure()-methods of the views and layouts are called.
What I tried:
I filled every textview with static dummy values in the adapter and excluded the part with loading the images. It changes nothing, traceview shows the same picture.
In the second try, I looked at the LinearLayout of my list item and replaced every "wrap_content" I found with "match_parent" - nothing. Still the same.
I am still open for your thoughts and hints. :)
You have no control over when and how frequently getView() is called.
If it really takes 500ms for you to generate 8 row Views, then there is something wrong with your code. You can use Traceview to determine specifically where you are taking the time, so you can attempt to do something to improve performance (e.g., caching).
I need to manipulate a ListView's children when it is done loading, but I can't seem to find a way to find out when this happens. When I set the adapter of my ListView, the method returns immediately, but the population of it's children views happens asynchronously. Is there a way to handle the event when my list is full of views?
You can either do a periodic polling to see if the list has been populated: write a while() loop to check once in a while. Or you could wait for a fixed amount of time (say 30 ms) before doing your next operation. These are not recommended methods, but should solve your problem.
Use getChildCount() to retrieve the shown views and also use a counter to keep track of how many views have been loaded asynchronously. I think I understand your question right.
I have a ListView with custom Adapter. To be honest, I have many of them at the same time on screen, and my Tegra 3 device started to lag, what made me really confused... I found than in each ListView's Adapter the getView() method is called for all visible rows every time any animations runs on screen. That gives me like few hundreds of calls per second! Digging more, most of these calls are due to measure() and onMeasure() calls of ListViews' parents, and - this is tke key - they are useless, because all the layouts of my ListViews
have const size.
So my question is: how to eliminate these calls? Of course I want to leave proper calls alone (caused by adding items to Adapter and notifyDataSetChanged() ).
I've tried almost anything, but either the whole list doesn't draw itself (when I overriden it's onMeasure() and forced to returned const size without calling super.onMeasure()) or stops updating at some time.
How you implemented the getView() method? If you implement it in the correct way there should be nearly no lagging.
Check out this really really good video:
http://www.youtube.com/watch?v=wDBM6wVEO70
Slides: http://dl.google.com/googleio/2010/android-world-of-listview-android.pdf
As Romain said, work with it not against it. Best is to leave measure() alone and focus on your adapter.
Thats how ListView is implemented.. I don't think that will cause a performance Overhead.. Provided you do things properly there..
For example..
Don't instanciate LayoutInflator inside GetView Method, Do it at class level..
And Inflate View Only if the convertView==null or else just return convertView.. Inflating view is a costly process....
Well like you said these calls are due to measure() and onMeasure() calls of ListViews parents and I'm sure you are using height=wrap_content also with wrap_content on height your ListView will check without stop if your height has changed.
So the solution is to put the height=fill_parent.
I hope this helped you.
The underlying reason for this is that ListView.onMeasure() calls AbsListView.obtainView(), which will request a view from your list adapter. So if your view is being remeasured through animations, your performance will be very poor.
I have a ListView with custom rows. When any of these rows is
clicked, the ListView's data is regenerated. I'd like the list to
scroll back to the top when this happens.
I initially tried using setSelection(0) in each row's OnClickListener
to achieve this but was unsuccessful (I believe because the ListView
loses its scroll position when its data is invalidated - so my call to
setSelection is undone. I still don't understand how the ListView
decides where to scroll to after invalidation, though).
The only working solution I know of was given by Romain Guy here:
http://groups.google.com/group/android-developers/browse_thread/thread/127ca57414035301
It involves (View.post)ing the call to _listView.setSelection(0). I
found this to perform quite poorly.
The newly generated list shows up with its scroll location unchanged
and there is a considerable delay before it scrolls back to the top.
Is there any better way to achieve this functionality?
Any help would be much appreciated.
Thanks!
call listView.setSelectionAfterHeaderView(); to scroll to top
I have tried lot but this one worked for me
list.smoothScrollToPosition(0);
I simply use listview.setSelection(0);
Works fine for me.
If you need instant scroll just after ListView adapter's data was changed, pay attention that it might not be yet populated. In this case you should post() your setSelection() or setSelectionAfterHeaderView() via Handler so it will be called later in the queue.
listView.Handler.post(new Runnable() {
#Override
public void run() {
listView.setSelectionAfterHeaderView();
}
});
This worked for me.
Personally, I recommend you find a different UI pattern. It is possible that users will find your current "click, and the list changes in situ" approach intuitive, but I am skeptical.
You could try subclassing ListView and overriding layoutChildren() to chain to the superclass, then call setSelection(0) in the case where that is needed. If the "considerable delay" is due to just the post() call, this should clear it up.
as a workaround, you can create a new adapter containing the new regenerated data, then call ListView.setAdapter. after that call ListView.setSelection(n).
btw, the solution provided by commonsware is worked.
On some different requirement.
If you want to scroll up just like while chatting.
mListView.smoothScrollToPosition(mAdapter.getCount());
This one worked fine when you want to focus the edittext from listview header
listview.setSelectionFromTop(0,0);
If you want to select the particular index view from listview then
listview.setSelection(index); // o for top