control when listView removes nonvisible views? - android

I find listView recycles its views too fast.
When my listView scrolls, views falls off the screen gets removed right away.
Each cell(row) has image loaded using universal-image-loader.
Views which fell off the screen has to reload the image when they comes back into visible area. (it shows the stub image for short time period and loads the correct image).
I definately need to keep the view recycling behavior, but can I modify the list view's behavior so that user won't notice constant reloading of images?(maybe I keep 2-3 times of # of views in a cache than a regular list view would)

Unfortunately the code for ListView and friends is horribly complicated by the fact that it's designed to scroll unevenly-sized items without knowing the height ahead of time. That makes it brutally difficult to run with anything but the default behavior. In addition, most of the methods you'd need access to, to easily customize the behavior are hidden or private. It would be a massive job to try and roll your own (across multiple platforms, subtleties of scrolling, flinging, dragging, scrolling, keyboard focus &c).
The best solution is probably to maintain an image cache that fills in lazily around the view positions that are active. Not neccesarily easy. But way easier that trying to mess with ListView.
A very useful API for this is ListView.setRecyclerListener(AbsListView.RecyclerListener listener), which gives you a hook to track which images are actively displayed.

I can suggest you to use a ScrollView instead of the list view. The ListView is designed to display a lot of data efficiently, that's why your off screen items are destroyed. In which concerns the scroll view, once loaded, you will be able to scroll up and down without recreating the off screen objects (because they ill not be destroyed).
See: http://developer.android.com/reference/android/widget/ScrollView.html
EDIT:
If it is mandatory for you to use the listView, you cluld take a look here: How do i prevent recycled ListView items from showing old content?
There is a posibility to override the listView getView method and keep more items not to be destroyed that the number the listView is keeping.

Related

Reusing Android views in a LinearLayout

I'm making sort of a news feed, that is displayed below a static menu. To avoid the news feed from being scrolled in the tiny bit of space that's left after the menu, I wanted to scroll both the menu and the newsfeed at the same time.
Now I'm realizing this with a LinearLayout, so it doesn't scroll itself like the listview. But my question is, is using a LinearLayout, which from what I know doesn't reuse views like a listView, bad practice? How likely am I to get into memory issues, since the news feed can have A LOT of views, and they all contain images.
Many thanks!
Apparently there is a pretty good chance for you to get an OutOfmemmoryexception in no time with this approach,If you want to go with re-using the views
I suggest you should go with the new RecyclerViews in Android,
Go here for a tutorial on recycler views
I don't know if this qualifies to be an answer. But if you are using a LinearLayout with a header view and a ListView inside it, then there are no issues. Since the main worry you have is the news feed which would be recycled by the ListView. Neglecting to use view recycling is asking for trouble, and will likely break after 50 or so (Android hates images).
As for the header that must disappear. I would avoid putting it as the first item in a ListView as suggested in the comments, and rather have it static in the LinearLayout. And use a view translation and/or transparency to hide it. This keeps the option availible to display the header at any point, regardless of the list's scroll.

android: Recyclerview for Fragments?

I have successfully followed the tutorial on RecyclerView here.
but I was wondering if I could build more complex behaviour using Fragments inside the RecyclerView instead of plain old Views.
using fragments can help make a reusable item with complex behaviour that can be placed in other places and can be much more flexible.
Is it possible and if so , how ?
RecyclerView is for a view that repeats a lot with different data, it's designed for use in long scrolly lists because inflating (constructing) the View Object takes some effort, so recycling takes the View you just scrolled off the top of the screen, quickly fills it with new data and puts it at the bottom.
I wouldn't have thought using a Fragment like that would work well, whenever you scroll the list it'll need to be re-created and run its various setup methods which will be quite expensive. And if you make it so it doesn't have to do that (setRetainInstance()) then you're not getting anything from it that you wouldn't get from a view.
If that's what you're getting at then yes you could create a Fragment, set it up, mark it as retained and keep a reference to it so it hangs around in memory for you to re-attach to some other parent at some other time. But if you have to change its contents and re-build it then you're not gaining much.

Alternative to ListView that avoids EditText focus issues?

Situation
Need to present text files as a list of editable sentences or phrases as shown in the example below, for the purpose of a speech therapy tool. This was relatively easy.
The colored flags can be added, removed, or dragged to new positions as needed, and can be set to snap-to-character or snap-to-word (they will also eventually display data).
This was achieved by sub-classing EditText, to take advantage of all the in-built features like word-wrapping, spell-checking, text-selection etc.
Problem
The number of phrases or sentences in a document can be large, so using a simple LinearLayout in a ScrollView to display them is no good in this case.
To efficiently display my FlaggedEditText widgets the solution needs to take advantage of view recycling, so ListView is an obvious consideration. But as shown by the number of S.O. questions out there, ListView and EditText don't play nice together.
The requirements of the list are that:
FlaggedEditText widgets get focused when touched (the item containing the FlaggedEditText also gets selected).
Notification when an item in the list has been edited (including which item).
Standard gestures such as fling.
I've tried out numerous approaches suggested in the many S.O. questions over the past few days, to try and bend ListView to my requirements, but all seem to have their own short comings and result in hacky, messy code.
Questions
Does anyone know of any existing alternatives to the standard Android ListView out there, that are more EditText friendly?
Alternatively, does anyone have a clean, efficient, definitive approach to getting EditText working as desired in the standard ListView?
Finally, I'm considering sub-classing AdapterView to make my own FlaggedEditText specific ListView alternative. But if the issues stem from AdapterView of which ListView is also an indirect subclass, then I'd be wasting my time. Has anyone already been down this path?
Edit
Jim's excellent response below, and a recent viewing of Romain Guy and Adam Powell's old Google I/O 2010 presentation The world of ListView have suggested a possible solution.
In the I/O talk I was reminded that they convert views to bitmaps for some of their optimizations. Since only one EditText at a time can ever be focused for editing, I'm thinking I can sub-class ListView to provide an interface which, if ChoiceMode is single, will give the Rect of the selected Item and bitmaps of the ListView regions above and below the selected item. This could then be used to temporarily overlay the ListView with a vertical LinearLayout containing the "above" bitmap, an active FlaggedEditText and the "below" bitmap.
In this way, the FlaggedEditText widgets can effectively act as non-focusable EditText's in the ListView, but when an Item is selected, interaction is with the temporary overlay.
The "above" and "below" bitmaps could also easily be tinted to suggest inactivity.
Additional
In fact, I've just realized I probably don't even need the Rect of the selected Item from the interface. The "above" and "below" bitmaps and a FlaggedEditText using the same LayoutParams as per the ListView should be enough.
Many of the answers out there do not seem to describe the core issues surrounding this "problem" and why it is not "solved." The "problem" you face is that an EditText can expand and/or scroll, along with your ListView. Also, the expanding soft keyboard forces the ListView to redraw causing problems with keeping track of the focused item. And when an item is focused and has dynamic content, UX confusion can occur with touch gestures (e.g. if you touch an item in an EditText like the cursor and then swipe, did you want the cursor to move? Or the entire list?) It can lead to a lot of user frustration.
I'm sure you've seen this post:
Issues focusing EditTexts in a ListView (Android)
This creates problems in correctly displaying the elements within the ListView, problems with recycling properly (the redraw) and problems with gaining focus correctly. It is possible that creating a custom class that extends AdapterView will work, but it will probably still feel like a hack, and probably will not work as you want it to or it will be a large effort.
You will need to do a lot of backend measuring of the fonts, images and "visible" (or partially visible) items in the custom object that also account for the keyboard animation and dual scrolling (the ListView can scroll and so can the EditText - or the EditText will change in size, forcing the parent custom AdapterView to determine if it should also scroll and whether views have become visible or invisible as a result of adding or removing text/images from the focused object).
If you make assumptions like "the EditText will never be larger than X height" then you may get it to work, but obviously that is a very customized solution, which is why it is not easily implemented and isn't supported generically.
Also, you will need to make UX decisions about how to handle a focused item that has scrolled off the screen (you can track it easily, but if it scrolls back onto the screen, but it can interrupt user expectations about how swipe and touch gestures are handled - for example, does the cursor in the EditText move or does the entire list? if an image is touched, does a swipe move the image or does it scroll the list? You can assume it is not focused, but then a "redraw" event can make it lose focus unexpectedly, like the current ListView implementation.) In other words, you are likely to end up with many unanticipated odd UX issues...
Your best solution will probably be to use a dialog pop-up as mentioned in the post I referenced above. Or, when an item is tapped to be edited, you could have a layout appear above or below the ListView. You may possibly get the ListView to scroll and lock to it - to have it appear as if it were in the ListView - but again, that would be hard with the soft keyboard changing the usable portion of the screen - you can expect "drag" or a slow feel to the "snap" effect. And you will need a "done" button...
To get your custom EditText to work with this suggestion, in the ListView you could disable it and make it non-focusable, then place an empty layout over the entire EditText that captures and processes the touch/fling/swipe events. This "invisible" layout may be the only option you really have.
In other words, you should probably plan to change your UI/UX rather than try to force Android to figure out how to handle several dynamic, and possibly conflicting or unpredictable, aspects of the UX interaction of these layouts.

Center aligned selection with animation in ListView (?)

I need a component that works like the picture below but I'm having trouble coming up with some kind of decent solution that works.
I want the list to have a center locked selection but being scrollable with the d-pad. This is for an application running on a TV so no need for touch scroll. So when pressing down on the remote d-pad the list will scroll and a new item will size up and the current selected one will size down and the new selection will still be in the middle.
I've tried doing this using a ListView that I extended and programmatically scrolling when pressing down or up. On scroll finished I called notifyDatasetChanged() on the ListView for re-inflating of the childs and in the ListViews adapters getView() I made the animation of the view located at the current selected position.
This is not optimal since I need to call notifyDatasetChanged(), which re-inflates all visible views, for the animation to apply. The UI becomes laggy when doing this and scrolling fast. It's also not possible to make som kind of compress animation when current selected item goes out of selection. There is also some trouble with the end items (read views) such the first or last in the list when doing animation of them, the may sometimes go out of screen.
I think that his must have been done before and maybe I'm missing it when searching for an answer.
Have anyone done something similar or do you have some suggestions of how this can be achieved? Maybe I'm just starting of with the wrong component here..
Regards,
Kristoffer

How to create UI only for the visible part of screen in a scrollView?

I am creating layouts at run time using heavy data, and adding these layouts to a scroll view. After the view get created, its working fine. The problem here is, the data is very heavy and it takes more than a minute to create the screen, which is not so good user experience. I want to create layouts only for the part of screen that are visible, and rest I can create on scrolling the scroll view. Pls suggest how is that possible? Also, If someone has a better approach, Pls suggest.
You can start by creating only a set number of views each time[1], but always add a dummy 'loading' view at the end of the list if there are more views 'pending'. As soon as the user scrolls the ScrollView at the end of the list, start loading the next part of views on a background thread, and as soon as they are built, remove the dummy loading view, and add the new views into your container.
An other approach would be to start loading the next group of views, as soon as the previous group is done finish, but that might be a waste of resources.
An even better approach, is to combine those two methods described, and always have the next group of views being created, if the user is halfway done scrolling to the end
You can check how to know when the scrollview scrolls to the bottom here: Android: Detecting When ScrollView Hits Bottom
[1] Since you care about UX I would suggest that the number of rows should depending on the row's height and device max height. I.e. 4 views on a small device, 6 on a medium, 10 on a large.

Categories

Resources