Can we change the setOffscreenPageLimit() of ViewPager dynamically in Android? - android

I am using FragmentStatePagerAdapter along with ViewPager to hold my fragments. User will have one image by default and he can keep adding upto 10. When I add 10 pages, I am seeing lots of OutOfMemory issues at different places in my app code, most of them at while creating bitmaps. Also the background images are not getting loaded so I see balck bakground. I currently have setOffscreenPageLimit(10). Due to this all my fragments and it's views (I have many imageviews, textview etc in every fragments) are held in memory. It works fine even at this stage. But if I swipe through the pages few times or run any other feature which needs bitmaps to be created (which eventually need RAM) then it sucks. Sometimes it leads to ANR as it could not space to create even thread or crash due to OOM.
Could you give me an idea, if you've used already, that if I can randomly change the setOffscreenPageLimit to lower value so that ViewPager will clear the rest of the fragments?
-I am thinking of changing the screen limit in onTrimLowMemory() in my Activity.Thinking I can handle any memory level - TRIM_MEMORY_RUNNING_MODERATE, _LOW or _CRITICAL.
I also got an idea to decide the number of off screen pages based on the available which I get through getMemoryClass() of ActivityManager.
If I can change setOffscreenPageLimit value dynamically, how can I let ViewPager know that it is been modified.
I read in the articles that android:largeHeap is of not that useful if device offered RAM is already low.Though it is allowed, it is not a good idea at all.
Enabling these bits in ViewPageer would help ?
PERSISTENT_NO_CACHE - Used to indicate that no drawing cache should be kept in memory.
Or any other suggestion to avoid OOMs, especially in the context of ViewPager with FragmentStatePagerAdapter?
I could get these points triggered from this http://developer.android.com/training/articles/memory.html#Android and from other articales from stackoverflow related to memory.
Spare few minutes and throw some light.

Related

Is there an alternative to Fragments to build reuseable components in Android Studio

I am building an application using Android Studio for an android tablet. I am fairly new, have never published an application. I have several parts I use on more then one page so I implemented them as fragments. On the page I am working on uses 4 fragments and when it renders, I get the message, Skipped 36 frames. If I change the fragment body from the page xml file to a constraints layout the messages go away. I've cut each of the fragments down to bare bones to get then number of skipped frames down to 36. If I put the components back in, the skipped frames go to 96.
Is there an alternative to fragments to share code within android?
I have run systrace for the loading of the page and the measure took 1441.6ms while the layout took 8.31ms.
There are other problems of course, but sorting out how to get this down to something reasonable would be good.
Also, Could this just be that the tablet is slow? Is there a place to see benchmarks on specific devices? Then I could maybe just use a different device.
Edit
If I flatten the xml, replace the fragment and put the xml for the fragment inline using a surrounding <ConstraintLayout it is slightly worse?
Edit II
I have worked on this issue all morning. I went back to the fragment implementation, then I went through the process of removing some ConstraintLayout sections. I used ConstraintLayout to delineate areas on the display. So I figured I could increase performance if I could remove some of them. Well, not so fast, sometimes when I removed the ConstraintLayout it actually made the application skip more frames.
Then I did an experiment on where I used margins and borders. It turns out if you use margins on a ConstraintLayout is faster, depending on the content of the Constraintlayout, then adding padding to each of the elements.
Also, a bigger cost is asking the ConstraintLayout to fill all available space using height/width="0dp" All of these attributes are part of the measure phase so they impact the frames skipped.
My consensus is that the tablet doesn't have enough power to write an application that makes any good use of the screen. Think of the tablet as the screen real estate of 4 phones. If the cpu is not way bigger it will not be able to manage that size of a display, unless all you want to do is draw images on it.

Are too many views in XML bad?

I have an XML file with about 150 views. Yes, I know it is a lot and I did get a message from Android Studio saying I can't exceed 80 views. But I can't drop views any lower than 150. I considered using list view but it works the way I wanted it to.
The question is, will this many views make the app crash/slow the device? I've tried it on my s7 and it works perfectly fine. My lowest API is 17 which is 4.2. Wouldn't 4.2 devices be able to handle this XML without any problem?
Thanks.
The problem with having an excessively large number of Views is that Android often needs to measure, layout, and draw them, and it will traverse the entire View hierarchy to do this. If the number of Views is so large that this traversal takes more time than the screen refresh rate, you will skip frames and your UI might appear to lag or be choppy.
If not all of those Views need to be on screen at once (for example, if you are using a ScrollView to hold a very large container that the user can scroll through), then you should probably switch to using RecyclerView.
If all of those views need to be on screen at once, then you might consider writing custom Views that can display your content all at once instead of having individual Views that draw individual things. This can drastically reduce the time and complexity of the measure/layout/draw traversals.
It's difficult to suggest an approach without knowing more specifics about your UI, but hopefully that explains the issue.

Creating a more responsive android notification

I am interested in what the current best practice for android API 16 is when it comes to changing a notification button.
Currently I set the bigContentView and use setOnClickPendingIntent() to make callbacks to the service but I'm finding the notification to be really slow at being updated as it has to change one of the button images between two different states (like toggling play/pause).
After logging ive traced it down to the code of swapping the drawable button.
setImageViewResource(viewId, srcId);
Takes anywhere from 1.0s - 0.3s which is a noticable delay for the user, surely there must be a better way? Or something I'm blatantly missing?
Any suggestions to avoid the update delay or any feedback on my current implementation would be greatly appreciated.
Load the two ImageViews above each other and switch the visibility between them. This way you will only need to load them once and you will avoid many Garbage Collection calls that could result in slow responsiveness in your app and you can also scale down your resources to a smaller size.

How is the number of views limited?

I want to figure out the main effectivity issues of the Android layouts and views. I'm doing a research now but maybe somebody has answers already.
I have a RelativeLayout that is populated with views dynamically. Basically, the application loads a forum thread in XML and then renders the discussion tree so each message is displayed in its own group of views. I've decided not to use WebView because I want to implement some client-side functions that should be easier to do on custom views than on HTML page.
However this approach has a major flaw: it's heavy.
The first problem (which I've solved) was nesting of views. This is not an issue now, my layout is almost flat so the maximum depth is 10-12 (counting from the very top PhoneWindow$DecorView, the actual depth depends on data).
Now I've reached the next limit that is somehow connected to (or caused by) resource consumption of the views. After loading the data, the application hangs for a while to build the layout (creates the views and populates them with the data), and the hang time seems to grow linear with the data size; and if the data is large enough, the view will never appear (eventually the system suggests closing the application because it isn't responding).
Now the questions:
Does memory consumption depend significantly on the view class? In other words, is there any major difference between a Button and a TextView, or an ImageView? I can attach a click handler to any view so they don't differ much in usage.
Do background images affect the performance? If the same image is set in N views, will it make the layout N times heavier? (I understand that this question may look silly but anyway.)
Are nine-patch images significantly heavier than regular ones? What is better: to create N views where each has some background images, or to make one view that is N times wider and has a repeating background?
Given some layouts, what should be optimized first: overall number of views, nesting levels, or something else?
The most interesting. Is that possible to measure or at least estimate the resources consumed by the activity and its views? If I make some change, how could I see that I'm going the right way?
UPDATE
Thanks to User117, some questions that I asked above are now answered. I've used the Hierarchy Viewer and optimized my layout: compared to what I had before, the overall number of views is now reduced almost twice, and the nesting is also reduced.
However the application still hangs on a large forum thread.
UPDATE 2
I've connected the debugger to my device and found that the application gets out of memory.
But what is very unexpected for me is that the error occurs after I populate the layout. The sequence is as follows:
All my views are added. I can see a slight slow down as they are being added.
Almost nothing happens for a couple of seconds. During that time, a few info messages are spawned in the log, they are identical: [global] Loaded time zone names for en_US in XXXXms, the only difference is number of milliseconds.
The out of memory error message is spawned: [dalvikvm-heap] Out of memory on a N-byte allocation (the actual size varies). The long error reporting starts.
What does this mean? Looks like the rendering have its own demands that may be considerable.
UPDATE 3
At last I've found the core issue. Here is a screenshot from my application, see an explanation below the image.
Each message consists of a round button that shows or hides the replies and a red content frame to the right of the button. This is very simple and requires only 6 views including the layouts.
The problem is the indentation with these connection lines that show which message is related to which.
In my current implementation, the indentation is built of small ImageView's, each containing a square image that shows either empty space, or a vertical line, or a T-like connector, or a L-like corner. All these views are aligned to each other within the large RelativeLayout that holds the whole discussion tree.
This works fine for small and medium trees (up to few hundreds of messages), but when I try to load a large tree (2K+ messages), I get the result explained in UPDATE 2 above.
Obviously, I have two problems here. I spawn large number of views that all consume memory, and these views are ImageView's that require more memory for rendering because they render a bitmap and therefore create graphics caches (according to explanation given by User117 in the comments).
I tried disabling loading the images into the indentation views but got no effect. It seems like adding that huge number of views is quite enough to eat all available memory.
My other idea was to create an indentation image for each message that would contain all pipes and corners, so each message would have the only indentation view instead of 10 or 20. But this is even more consuming: I've got out of memory in the middle of populating the layout. (I cached the images in a map so two bitmaps with identical sequence of images weren't created, that didn't help.)
So I'm coming to conclusion that I'm in a dead end. Is it ever possible to draw all these lines at once?
Different View's are different kinds of Object. Some only draw() light weight stuff, some can hold large Bitmap Objects, and handler Objects and so on. So, yes different View's will consume different amount of RAM.
If same Bitmap object is shared among views, There's only one Object in RAM, each View will have a reference variable pointing to that object. But, not so when View draws: Drawing same Bitmap n times at n places on screen will consume n times CPU and generate n different bitmap_cache for each View.
Each side of a 9-patch image is actually bigger by 2 pixels from the original image. They are not much different as a file. When they are drawn, both can be scaled and will take almost equal space. The only difference is that 9-Patch are scaled differently.
Setting the background of the larger, parent view is better when the child views are transparent, and background will show through.
You can save a small image and set a tiled background so that it can fill a large area.
Nesting is to be optimized first, because all of the views might not be visible at a given time, let's say only a few views are visible in scrolling layout. Then you can cut down on total number of views used. Take cues from ListView: Given that user will be only seeing a sub set of total data at a time, it re-cycles the views. and saves a lot of resources.
SDK provides Hierarchy Viewer tool for this purpose. It shows a full tree structure of a running Layout, also places red flags for the sluggish parts of the layout.
A good layout is that which:
Easy to be measured (avoid complex weighted widths, heights and alignments). For
example instead of doing layout_gravity="left" for each each child, parent can have gravity="left".
Has less depth, each overlapping view adds another layer to be composited while screen is drawn. Each nested View Structure, asks for a chained layout call.
Is smart and re-cycles Views rather than create all of them.
Reuses its parts: tags like <merge> and <include>.
Update:
Answers to this question, show many approaches for a tree view in android.

How to increase performance of ViewPager?

I want to know how to increase performance of ViewPager. I have ViewPager which has around 25 swipes with large images. I have done memory optimization to avoid OutOfMemoryError. Its working fine.But still there is a lag while swiping. I have set offscreen page limit to 2. If I increase offscreen page limit. It will load more pages in Memory and again I will end up with OOM. So any suggestion how to avoid lag while swiping?
Your ViewPager cannot cache more than 2 pages? It sounds like you need to tweak your fragments a bit more. For example, make sure you don't stretch the background image, and make sure that your layouts are as simple as possible (i.e. don't use unneeded layouts). If you can see how much memory your app is using for these two pages.
Once you verify that see if you can increase the offscreen page limit. Then check that you are properly destroying the fragments.
You can use FragmentStatePagerAdapter istead using FragmentPagerAdapter.
More detailed explanation given here.
Another Possible solution in case of images is that you can try putting them in drawable-hdpi folder, they will load faster. You can look at an answer here.

Categories

Resources