Using Multiple Surfaces Views For Optimization? - android

The Situation
I started developing for Android, and found that Android's way of handling layouts, animations etc. is not adequate for smooth touch feedback and real-time animations, especially before Android 4.0. So instead, I decided to use the game app approach: use a SurfaceView and define my own drawing code.
The Problem
After a few tests, I discovered that this method required too much CPU for a non-game app, which I believe is due to redrawing static elements 60 times per second.
The First Solution & Flaws
To solve this issue, I modified my code so that the app would redraw the screen (call postInvalidate) only if there were any changes to what should be drawn. This solution solved part of the issue, but the app still had to redraw static elements even if a small button moved a single pixel.
The Question: Possible Better Solution?
For a better solution, I considered how Android dealt with the problem; it had separate View's for every screen element. So I though, maybe I could have one SurfaceView for large, static, content elements and another for small, moving UI elements and achieve a similar effect. My question is, would this actually improve performance the way I described it above?
Thanks.

If you're using postInvalidate(), you should be using a custom View, not a SurfaceView. The whole point of using a SurfaceView is to have a separate layer that is independent of the View UI. If you're overriding onDraw(), you're drawing on the View part, not the Surface part, and just wasting the Surface.
All Views occupy a single layer, no matter how many you have. Each SurfaceView has a separate layer, so having a lot of them will become problematic. In practice you can have no more than three, because of Z-ordering limitations. (See the "multi-surface test" activity in Grafika for an example of three partially transparent SurfaceViews blended with the View UI.)
If you can't render fast enough to maintain 60 fps, you need to consider changing the way you render. Custom Views and OpenGL ES take advantage of hardware acceleration. Canvas rendering onto a SurfaceView Surface does not. On the plus side, you can down-size a SurfaceView's Surface and let the hardware scale it back up; this lets you limit the number of pixels you have to draw each frame, regardless of the display's resolution. (Blog, demo.) If you have a lot of static elements, the best approach may be to render to an off-screen Bitmap, and then just blit the Bitmap every frame.
One approach that will be very fast is to render all of the static elements onto the View part of the SurfaceView, taking care to keep the background transparent, and then render the animated parts on the Surface with GLES. You could use a second SurfaceView, but that adds an additional composition layer, which will degrade system performance if you exceed the number of overlay planes supported by the hardware.
For a deeper understanding of the way Android graphics work, take a look at the graphics architecture doc.

Related

SurfaceView hides other components on screen

I am creating a layout of type FrameLayout, in which I am adding two views. Two views are objects of GLSurfaceView and SurfaceView respectively. According to Android Developers Documentation regarding SurfaceView,
"The surface is Z ordered so that it is behind the window holding its SurfaceView; the SurfaceView punches a hole in its window to allow its surface to be displayed."
It works well for me and SurfaceView always stays behind my GLSurfaceView (used for opneGL drawings). But resuming after external event the behavior is odd for a following configuration,
Android Version: 4.3
Device Model Number : Nexus 7
Kernel Version 3.4.0.g1f57c39
Jun 13
Build Number: JWR66N
For this configuration, resuming after external event puts my GLSurfaceView behind SurfaceView. In other words, SurfaceView is placed at top in ZOrder and my OpenGL drawings are no more visible. On versions greater that Android 4.3, this behavior is not seen.
I can replicate this behavior on all versions by calling SurfaceView's following method with true as a parameter.
void setZOrderOnTop
Is this known issue. Anybody can help me on this?
Regards,
Sumedh
SurfaceViews have two parts, the Surface and the View. The Surface is a completely independent layer. The View is there so the UI layout code has something to work with. Generally the View is just transparent black, so you can see through to whatever is behind it.
GLSurfaceView is just SurfaceView with some code to manage EGL contexts and threading. Underneath it's just a SurfaceView. So if you have both a SurfaceView and a GLSurfaceView, and they have the same dimensions and Z-order, then one of them is going to "win" and the other is going to "lose" because they're trying to occupy the same space at the same time. There is no defined value for which one will "win", so inconsistent behavior is expected.
One way to avoid clashes is to leave one set to the default Z, and call setZOrderMediaOverlay() on the other. The "media overlay" is still behind the UI, but above the default Surface position. If you use setZOrderOnTop(), the Surface will be positioned above the UI as well.
The upper Surface will need to be rendered with transparent pixels if you want to see something behind it (the same way that the View needs to be transparent to see the Surface).
The most efficient way to avoid this issue is to not have this issue: use one SurfaceView for everything, rendering all of your non-UI-element content to it. This requires a bit more work (and probably a SurfaceTexture) if you're rendering video or showing a camera preview on one of the Surfaces.
You can find some examples in Grafika. The "multi-surface exerciser" demonstrates three overlapping SurfaceViews rendered in software, overlapping with UI elements. Other activities show ways to work with Surfaces, GLES, the camera, and video.
See also the Android System-Level Graphics Architecture doc, which explains all this in much greater detail.
Dont use "setZOrderOnTop" as true. That will get it over all the other layouts.
If you are using multiple surfaceviews. use this for each surfaceview
yourSurfaceView.setZOrderMediaOverlay(true);
then set this setZOrderOnTop as false for the surfaceview you initiated later and wanted it to get back to the other surfaceviews
secondSurfaceview.setZOrderOnTop(false);

Android Canvas Off Screen Drawing Performance

I'm developing an Android game using Canvas element. I have many graphic elements (sprites) drawn on a large game map. These elements are drawn by standard graphics functions like drawLine, drawPath, drawArc etc.
It's not hard to test if they are in screen or not. So, if they are out of the screen, i may skip their drawing routines completely. But even this has a CPU cost. I wonder if Android Graphics Library can do this faster than I can?
In short, should I try to draw everything even if they are completely out of the screen coordinates believing Android Graphics Library would take care of them and not spend much CPU trying to draw them or should I check their drawing area rectangle myself and if they are completely out of screen, skip the drawing routines? Which is the proper way? Which one is supposed to be faster?
p.s: I'm targeting Android v2.1 and above.
From a not-entirely-scientific test I did drawing Bitmaps tiled across a greater area than the screen, I found that checking beforehand if the Bitmap was onscreen doesn't seem to make a considerable different.
In one test I set a Rect to the screen size and set another Rect to the position of the Bitmap and checked Rect.intersects() before drawing. In the other test I just drew the Bitmap. After 300-ish draws there wasn't a visible trend - some went one way, others went another. I tried the 300-draw test every frame, and the variation from frame to frame was much greater than difference between checked and unchecked drawing.
From that I think it's safe to say Android checks bounds in its native code, or you'd expect a considerable difference. I'd share the code of my test, but I think it makes sense for you to do your own test in the context of your situation. It's possible points behave differently than Bitmaps, or some other feature of your paint or canvas changes things.
Hope that help you (or another to stumble across this thread as I did with the same question).

How to use SurfaceView to draw a single complex image

I am creating an Android App that produces random images based on complex mathematical expressions. The color of a pixel depends on its location and the expression chosen. (I have seen many iPhone apps that produce "random art" but relatively few Android apps.)
It takes 5 to 15 seconds for the image to be drawn on a Nexus S dev phone.
To keep the UI thread responsive this seems like the purpose of the SurfaceView class. Almost all the examples of SurfaceView deal with animation, not a single complex image. Once the image is done being drawn / rendered I won't change it until the user
So, is SurfaceView the right component to use? If so, can I get a callback from the SurfaceView or its internal thread when it is done drawing when it is done rendering the image? The callback is so I know it is okay to switch the low resolution and blocky version of the image art with the high resolution one?
Is there an alternative to SurfaceView that is better for complex rendering of single images. (Not animation.)
Cheers!
If all you want to do is render a single complex image on another thread to keep the UI responsive, then after it's done rendering actually draw it, you might consider just doing this in the standard keep-work-off-the-UI-thread way by using something like an AsyncTask. It's not like you're doing compositing or anything that really is GPU-specific (unless as others have suggested you can offload the actual rendering calculations to the GPU).
I would at least experiment with simply building an array representing your pixels in an AsyncTask then when you're done, create a bitmap with it using setPixels and set the source of an ImageView to that bitmap.
If on the other hand you want your image to appear pixel by pixel, then maybe SurfaceView might be a reasonable choice, in which case it'll basically be an animation so you can follow other tutorials. There's some other setup, but the main thing would be to override onDraw and then you'll probably have to use Canvas.drawPoint to draw each pixel.

android view or surfaceView, which should i use?

Ive been trying to make a scrollable/zoomable app and everything has gone great except for drawing bitmaps. It is a very large image (6656 by 4096) that i have split into tiles. There is a rectangle array that the bitmaps are drawn to, and it detects what rectangle is in the top left corner so it can draw the bitmaps that will cover the user's viewable screen. My problem is this all lags when the app has to load the bitmaps into memory; Once they are loaded it isnt an issue. I started with 512 by 512 tiles, then went down to 128 by 128. although it helped, there still is some noticeable lag. I have been looking into surfaceView and wanted your opinions if i should stick with View, or use surfaceView to solve my lag.
If you derive your own SurfaceView you have several advantages.
Mainly because you can have all drawing logic in a seperate thread. This means that the ui won't wait for you (I'm assuming the lag is because the ui-thread is being blocked?).
SurfaceView's are also faster in nature.
I also find this overview on developer.android.com to be a good reference to choose drawing method.

Difference between SurfaceView and View?

When is it necessary, or better to use a SurfaceView instead of a View?
Views are all drawn on the same GUI thread which is also used for all user interaction.
So if you need to update GUI rapidly or if the rendering takes too much time and affects user experience then use SurfaceView.
A few things I've noted:
SurfaceViews contain a nice rendering mechanism that allows threads to update the surface's content without using a handler (good for animation).
Surfaceviews cannot be transparent, they can only appear behind other elements in the view hierarchy.
I've found that they are much faster for animation than rendering onto a View.
For more information (and a great usage example) refer to the LunarLander project in the SDK
's examples section.
updated 05/09/2014
OK. We have official document now. It talked all I have mentioned, in a better way.
Read more detailed here.
Yes, the main difference is surfaceView can be updated on the background thread. However, there are more you might care.
surfaceView has dedicate surface buffer while all the view shares one surface buffer that is allocated by ViewRoot. In another word, surfaceView cost more resources.
surfaceView cannot be hardware accelerated (as of JB4.2) while 95% operations on normal View are HW accelerated using openGL ES.
More work should be done to create your customized surfaceView. You need to listener to the surfaceCreated/Destroy Event, create an render thread, more importantly, synchronized the render thread and main thread. However, to customize the View, all you need to do is override onDraw method.
The timing to update is different. Normal view update mechanism is constraint or controlled by the framework:You call view.invalidate in the UI thread or view.postInvalid in other thread to indicate to the framework that the view should be updated. However, the view won't be updated immediately but wait until next VSYNC event arrived. The easy approach to understand VSYNC is to consider it is as a timer that fire up every 16ms for a 60fps screen. In Android, all the normal view update (and display actually but I won't talk it today), is synchronized with VSYNC to achieve better smoothness. Now,back to the surfaceView, you can render it anytime as you wish. However, I can hardly tell if it is an advantage, since the display is also synchronized with VSYNC, as stated previously.
The main difference is that SurfaceView can be drawn on by background theads but Views can't.
SurfaceViews use more resources though so you don't want to use them unless you have to.
A SurfaceView is a custom view in Android that can be used to drawn inside it.
The main difference between a View and a SurfaceView is that a View is drawn in the
UI Thread, which is used for all the user interaction.
If you want to update the UI rapidly enough and render a good amount of information in
it, a SurfaceView is a better choice.
But there are a few technical insides to the SurfaceView:
1. They are not hardware accelerated.
2. Normal views are rendered when you call the methods invalidate or postInvalidate(), but this does not mean the view will be
immediately updated (A VSYNC will be sent, and the OS decides when
it gets updated. The SurfaceView can be immediately updated.
3. A SurfaceView has an allocated surface buffer, so it is more costly
One of the main differences between surfaceview and view is that to refresh the screen for a normal view we have to call invalidate method from the same thread where the view is defined. But even if we call invalidate, the refreshing does not happen immediately. It occurs only after the next arrival of the VSYNC signal. VSYNC signal is a kernel generated signal which happens every 16.6 ms or this is also known as 60 frame per second. So if we want more control over the refreshing of the screen (for example for very fast moving animation), we should not use normal view class.
On the other hand in case of surfaceview, we can refresh the screen as fast as we want and we can do it from a background thread. So refreshing of the surfaceview really does not depend upon VSYNC, and this is very useful if we want to do high speed animation. I have few training videos and example application which explain all these things nicely. Please have a look at the following training videos.
https://youtu.be/kRqsoApOr9U
https://youtu.be/Ji84HJ85FIQ
https://youtu.be/U8igPoyrUf8
Why use SurfaceView and not the classic View class...
One main reason is that SurfaceView can rapidly render the screen.
In simple words a SV is more capable of managing the timing and render animations.
To have a better understanding what is a SurfaceView we must compare it with the View class.
What is the difference... check this simple explanation in the video
https://m.youtube.com/watch?feature=youtu.be&v=eltlqsHSG30
Well with the View we have one major problem....the timing of rendering animations.
Normally the onDraw() is called from the Android run-time system.
So, when Android run-time system calls onDraw() then the application cant control
the timing of display, and this is important for animation. We have a gap of timing
between the application (our game) and the Android run-time system.
The SV it can call the onDraw() by a dedicated Thread.
Thus: the application controls the timing. So we can display the next bitmap image of the animation.

Categories

Resources