The top level layout in my activity is a framelayout. I have completed, debugged and tested this app and it works exactly like it should in all respects on my g1 and on various emulators. But on 3.7-inch displays running 2.1+, some imageviews packed in a linearlayout
are periodically not visible. I know that they are there because you can touch and drag them with effect in the app. So I assume somehow
they have gotten under the SurfaceView that is the main component of the app. This is apparently so even though the SurfaceView is declared in the xml prior to the LinearLayout. However, the ImageViews IN the LinearLayout are added programmatically towards the end of onCreate().
Framelayout stacks everything that is added to it, one on top of the other--the only way you will see more than one child of a frame layout is if they are smaller than the screen and are placed apart from eachother.
Oddly, sometimes the imageviews ARE visible--it is random. Anyway, I've been trying to combat this with framelayout.bringChildToFront(View v) on the linearlayout without success.
I wonder if anyone has any insight into how the behavior could be random like that, and how I should code these imageviews
to keep this from happening, and why the problem appears only to occur on 3.7 vs 3.2 inch screens (as it happens, the two 3.2-inch screens were both htc, so vendor might be factor too).
[edit] Actually, I've determined that this is a 2.2 issue, not a screen size (or even vendor) issue. Can't ensure that ImageViews added to a framelayout with a SurfaceView
in it will appear on top of the surfaceview. I ran some tests in the respective onDraw() methods and the imageviews are 'visible' (0), and nothing does anything to the alpha of the drawables, which are there as well at ondraw(). [/edit]
Any insight would be welcomed.
Ken T.
I had to draw the drawables in SurfaceView's doDraw() method, and I had to change the file names of the drawables. I think this was a case of malicious code somewhere. I had to scrap the ImageViews and transfer my touch-handling code elsewhere.
Related
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.
So, I've been developing on Android since about Feb 2011. One thing I've always been acutely aware of is that Nesting Linear Layouts with weight and weight sums is 'bad for performance' and the compiler (well at least eclipse did) thew a warning fit when ever you dd so.
However, it's been my experience that doing this has no noticeable impact on the user experience, or speed when switching screens. As an experiment I created the following screen which deliberately features nothing other than a mega O.T.T. use of weights and nested linear layouts. I've used contrasting colors to show all the linear layouts used. The benefits is that it looks the same on large and small screens.
I've tried it on a Galaxy S4, Galaxy Note 10.0, Galaxy note 3 7", and very small low powered Galaxy Neo. I've tried it on Gingerbread, Cream Sandwich, Kitkat and Lollupop and do not see any perceptible speed difference between this screen an a simple one with 4 buttons on a relative layout.
So what makes this such a bad idea? What is going on under the hood that makes this a less than idea solution? Will all this change the moment I add drawables or images into the mix?
The main issue here has to do with how Android positions your views on screen. Any time that a position changes with respect to a view, then a "layout" pass cascade through the view hierarchy, touching each view and performing some calculations (similar for changing "sizes" kicks off a "measure" pass).
Some layout containers, like RelativeLayout, have to force a 2nd "layout" pass to kick off; Once all the views have calculated their desired position, ReltativeLayout needs to then re-position everything again based on it's layout properties.
This causes a Double Layout Taxation trough the view hierarchy; which isn't free.
Now, if you have a shallow hierarchy, the overhead of this action is insignificant. Where this starts to run into a problem is when you've got a deep hierarchy, with multiple double-layout containers in it. For example, having a RelativeLayout at the root, which contains LinearLayouts that have "measure with largest child" set on it. The result is that the leaf-node views will have "layout" called on them ~8x times.
The performance impact of this is directly correlated to how complex your layout/measure passes are in your scene. If nothing is problematic, maybe a 12x-per-view layout pass isn't a big deal on high-end devices. However if one of the leaf nodes has a complex layout pass, well, then you're just wasting cycles.
The main topic here is to profile for things that are a problem, but keep in mind that setting things up the wrong way is just wasting performance that could be used elsewhere.
So what makes this such a bad idea?
It's not a bad idea. It is not free, either.
In particular, your scenario is fairly simple, despite your protestations to the contrary. While your layout is rather complex, it is rendered once. Hence, while you may drop a few frames while rendering it, that price is paid one time (or, more accurately, one time per activity/fragment that is using this layout).
Where per-layout expense becomes a much bigger problem is when it is magnified by having several of them that get animated around, such as rows in a ListView/RecyclerView, or pages in a ViewPager. Now, we are going through lots and lots of rendering passes, as the user swipes and causes us to redraw our content. Each individual row in the list might be significantly simpler than your layout, but we're also going to be trying to draw those many times per second. And, while a couple of dropped frames may not be noticeable in your case, dropped frames during animation is pretty much the definition of "jank" for an Android UI.
So long as you have no jank -- IOW, you are not dropping any frames, as reported by Choreographer in LogCat or as seen in the gfxinfo overlay through Developer Options -- then your layout is fine, at least as far as I and probably most users are concerned. Conversely, if you are dropping frames, trying to figure out more efficient layouts, perhaps even custom ViewGroups rather than general-purpose ones, may help alleviate that jank.
I would like to make a simple Android game where a large background image is displayed and some other images are displayed in specific locations over it, where the other images may be clickable.
Here's a quick sample image of what I'm talking about:
The user should be able to tap the soccer player or the moose (ah, the classic "soccer player moose problem"!)
How should I render this screen (which layouts and views?) so the user can interact with it and it will scale properly on different devices?
I would use a RelativeLayout.
You can set the you background image to the layout (fill_parent for height and width).
You can then put your ImageViews, containing your moose and soccer player down on the layout relative to the top or sides of the sceen, or relative to each other (making sure to specify "dp" units for everything). Set the backgrounds of your ImageViews to be transparent, and there won't be a bounding box problem (and/or you can also set your ImageViews alignment to be relative to each other, ensuring they don't overlap).
I think this is the simplest way to do this - it is then super easy to attach onClickListener to your ImageViews in your Activity, and you are done.
This type of layout will work the same on all devices and screen sizes.
There are some small gotcha's with RelativeLayouts, but they are pretty simple once you get into them, and provide fast rendering (since the view hierarchy is usually shallow). Good Luck.
ImageView for the clickable elements seems like a fine choice to me. For the background I would just set your image as the background of the parent layout i.e. RelativeLayout
SurfaceView for the whole thing (with your field as a background) and regular *ImageView*s for added elements. You can easily recover the click coordinates from the SurfaceView and thus know what element has been touched.
SurfaceView might offer you additional possibilities anyway.
For most images, I'd use an ImageView for each one, like FoamyGuy said.
If they're close enough for overlapping bounding boxes to be an issue, you can still use an ImageView for each, but with a variation of this answer, testing alpha for each ImageView in range.
I would agree with both FoamyGuy and Booger that if your only goal is to place static images onto the screen that do something when you click them, RelativeLayout and ImageViews all the way.
But...
If you are looking to randomly spawn multiple images onto the screen in intervals and have them move around for the player to interact with while explosions are going off and maidens are being kidnapped, you should look into SurfaceView, Canvas, Drawable, TouchEvents, and FrameBuffers.
In an app I'm developing, I need to layout 2 to 5 buttons as if on the edge of a circle. The app starts with 5 buttons, but buttons gradually disappear (based on user input) until there are 2 of them.
I thought I would use an AbsoluteLayout control, and set the position of each button in code (taking into account the screen size). However, it says more or less everywhere that AbsoluteLayout should not be used. Since I'm targeting this app to Android 2.2 and up, I can't use the fancier layouts introduced with ICS.
I know I can use a RelativeLayout and play with the margins, but this seems less intuitive, and just as error prone, as using AbsoluteLayout.
Do I have any reasonable alternative?
I think, you dont have many alternatives. Except relative layout you mentioned, you could of course use FrameLayout and set left and bottom margin to position your buttons correctly.
This might be a "duh" question but I'm going to go ahead and ask it anyway.
I have an oversized (bigger than the screen) RelativeLayout, and I'm using swipes to start a TranslateAnimation from viewing one part of the layout to another. Say for instance the layout is two screen wide and two screens tall. After the nice animation to shift the screen, I was using View.scrollTo() to set the new position. This works fine going from the first screen (top left at 0,0) to one of the others. When I swipe to animate back to the first screen though, because the View.scrollTo() invalidated that part of the layout (I assume), that part of the layout is all black as I animate through it. I tried a couple things to get it to redraw itself after the scrollTo() but haven't had any luck, so I figured I'd ask here.
thanks!
joe d
I can't help with your specific problem since I've never tried working with a layout bigger than the screen, but there might be another way to achieve what you're trying to do. If you simply want to be able to finger-swipe from one View to another, without ever displaying part of one screen and part of another (i.e. you aren't smoothly panning around a large View but rather just jumping from one distinct section of the layout to another), then these tutorials might help, here and here. They show you how to use touch events and the ViewFlipper widget to change between Views using animations.