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.
Related
Should I use NestedVerticalScrollview Android with 1000 child view?
Generating views in Android is generally fast, but if doing it a lot, it can get expensive. Depending on the complexity of your itemView, this could get very expensive when scrolling in your case. Unless you use a RecyclerView, whenever a view goes off screen that View will be destroyed, and each new item revealed by scrolling would have to be created anew. RecyclerView performs a recycling process on these views, so if each itemView has the same layout, it can reuse past views to present new information, thereby saving the time required for creating the view.
In your case, it sounds like all 1000 views would be created upon creation, which would probably take a fair amount of time to create the activity/fragment, and is a waste of resources, since only about a dozen could likely be displayed at any one time.
I suggest two things:
Use a RecyclerView in place of the NestedVerticalScrollView. Here is the official android codelab for RecyclerView in java. I'm sure you can find a kotlin version by search, if you're coding in kotlin.
If your itemView (in recyclerView terminology this is a ViewHolder) is complex (aka nesting), use a constraintLayout within your ViewHolder. If it is a simple layout, you may use a LinearLayout, or if that does not provide the layout you desire, RelativeLayout. Even if you are just creating one TextView, you should use the ViewHolder pattern required by RecyclerView.
You could test out the performance of your scrolling behavior manually to see if you experience lag when scrolling in a ScrollView with a 1000 child views. I suspect you would, even with the most basic itemView.
Also, do not use a RecyclerView within a ScrollView, this will not work well (as explained in the RecyclerView docs I linked in the first link above.)
I am trying to achive this:
First I tried by putting all my recyclerviews (with WRAP_CONTENT) inside a nestedscrollview. That worked, but the performance was awful. Then I tried to set a height for my recyclerviews, that was a lot better (especially the first gridlayout and the horizontal linearlayout loaded very fast), but still had the problem with the dynamic "category" part.
Now I am trying to put all my recyclerviews inside a single recyclerview with different viewtypes. Since that is a pretty big deal (I need to refactor a lot of code because I have diveded every area from the screenshot inside a single fragment and now I need to put all that code inside an adapter) I wanted to ask if I can actually expect any gain from this, because in the end its again a "nestedscrollview" (made by myself, but...). Or if there is some other "best practice" way to achive this layout.
Thank you
Edit:
As expected this didnt do the trick neither. When just the two first recyclerviews are added as viewtype it scrolls and loads smoothly. But as as soon as I try to add the category items (below the category), I notice a lag and especially when selecting multiple categories and scrolling fast up, there is noticable lag. I guess I will have to change my layout and move the category selection part inside a separate view, just need to come up with a user friendly solution. But its acutally quite dissapointing that, in my opinion such trivial task, laying out multiple tables, is such a pain in the ass on android.
I didn't manage to get it working with standard android stuff.
Now I am using epoxy from airbnb ,and I have converted all my views from nestedscrollview to the epoxy recyclerview. Its a great library, and airbnb use it too for all their views.
Nevertheless it's sad that the android dev team doesn't address this problem and provide a solution besides the info "don't nest multiple scrollviews(recyclerviews) that scroll into the same direction".
You can use Recyclerview in recyclerview.
https://irpdevelop.wordpress.com/2016/02/10/horizontal-recyclerview-inside-a-vertical-recyclerview/
And make sure to use multiple view types.
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.
Do we get any benefits of implementing a ListView for which every item would have different layout? Would it be a better idea to put those items into ScrollView with LinearLayout instead?
Intuitively, it seems like using a ListView may still give better performance, though it might be negligible depending on the size of your content. Because the ListView inflates the views as it needs them, it seems like you might save some time by not parsing/rendering views that a user might never see. A long ScrollView with a bunch of views inside seems like it would take additional time when first launched, since the view hierarchy is more complex.
I do think Michael is mostly correct though, that the main advantage of a ListView is that views are reused, which saves on memory/processing. Unless you have a ton of content in the ScrollView, I suspect the performance difference is not significant, and will almost definitely be more complex -- in particular, having to create an adapter that knows how to create each view type for each row.
I don't understand why you may use ListView for this. Listview is a list of common data using the same layout if you click on it. Users depend on same/similar GUI patterns.
How about Sliding Tabs or the newer navigation drawer, link NavigationDrawer.
If you like sliding tabs, then I can give you more details.
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.