First time poster, new to Android, and I seem to have hit a roadblock on this problem:
I'm creating a dynamic layout, consisting of several identical "composite" objects (these are basically "floating" LinearLayouts, each containing an icon (ImageView) and a caption (TextView)). The (x,y) coordinates of each LinearLayout are subject to change, based on user actions, and require precise placement (ie: can't use RelativeLayout, etc), so I'm positioning them inside an AbsoluteLayout.
During onCreate(), I'm adding each of these objects as a child View inside an AbsoluteLayout object, then setting the (x,y) manually. No problems so far, works great, initial layout is perfect.
The problem:
After the initial onCreate(), I can't get the (x,y) positions of these objects to change on the screen. I can update their layoutParams, but the on-screen layout (inside the AbsoluteLayout) is never refreshed. I've tried forceLayout(), invalidate(), requestLayout(), none of them work.
Is there a problem with my basic approach here, or is there something I'm just missing?
I'm thinking of changing to a SurfaceView and just doing the rendering the hard way, but my code works 99% great right now and I don't want to change it if I don't have to. The only problem is that the layout manager simply refuses to register the position changes for my child objects.
Help, what am I doing wrong?
Did you try creating a handler for UI and then updating your UI from that..
UI will not be able update from different thread. So, create a thread handler for UI and update the changes to UI using that handler.
-vinay
Related
I have a LinearLayout that I would like to change the background color of when one of its child views (an ImageButton) is clicked. I am able to do this, but not immediately - the change doesn't occur on the screen until later (I think during an onResume call). I would like to find out how to force the layout to redraw after the background is set, before the next line of code executes. Here is the onClick method of my OnClickListener for the button:
public void onClick(View v) {
LinearLayout parentLayout = (LinearLayout) v.getParent();
parentLayout.setBackgroundResource(R.color.my_color);
SystemClock.sleep(1000); //ms
}
The sleep command is in there to test whether the redraw happens before or after it. The result: after. Most questions on this topic (like here and here) say to use invalidate() on the view. I have used the commands parentLayout.invalidate();, parentLayout.postInvalidate();, and parentLayout.refreshDrawableState(); in between the background and sleep lines, all to no avail. The redraw still happens after the sleep command. Can anyone tell me how to make it happen immediately?
Other possibly useful information: The LinearLayout is bound to the rows of a ListView, and the OnClickListener above is in a custom class that extends SimpleCursorAdapter, not in the activity itself. (This way I can set a listener for each of the rows in the ListView.)
You might try forceLayout() with a call to draw(canvas) immediately after. If you did not override onLayout(), onMeasure, draw() or onDraw(), then the default implementation will run. The only issue with this is that you have to either get the Canvas or create one manually.
It is strongly discouraged to pursue this approach as Android is specifically designed to avoid drawing outside of normal updates. While you are correct that invalidate() does not happen immediately, it is the safest and best way to encourage a redraw. If you want to handle drawing outside of updates, Android provides a way to do that with the SurfaceHolder class.
Okay, I finally found a solution to this issue, and it's simple. It seems that the problem was just that I was executing the drawable changes in an OnClickLIstener, when I should have been doing it in an OnTouchListener. If I set an OnTouchListener for my button that looks for ACTION_DOWN and then runs setBackgroundColor on its parent layout, the change occurs immediately.
An alternative, less robust solution comes from this post. You can assign a selector for the parent layout background in xml, then in the OnTouchListener mentioned above, run setPressed(true) on that layout. It's not a great solution because the selector gives you a lot less freedom than directly changing the view's properties in code. You couldn't set the layout background to a different color by pressing a different button, for example.
Thanks to those who helped out with suggestions on this!
make the changes and call listview.invalidate(); to reflect those changes on UI
My app i'm currently developing needs to refresh a Linear Layout that i'm dynamically adding Views too. I currently am adding all of the Views within the UI thread but have a separate Dialog class which upon a button click within the Dialog will need to refresh/Re draw the Linear Layout. Is there a way I can refresh the Linear Layout within a different class (trying to stay very object oriented in my program design) or a way to use a game loop for a Linear Layout to refresh the View every 3 seconds? Thanks!
I'm pretty sure you don't need to manually "redraw" anything. As soon as you change the contents of your layout (and as soon as android can get around to it (which will be a LOT faster than 3 seconds)) you'll see the updated screen. As to what thread you do this from, you can only change your layouts from the main thread, as far as I know, but you can call Runnable methods in that thread via a handler from anywhere.
I have 10 views that are being added to a LinearLayout with vertical orientation. This all occurs at runtime. However, each time the layout is redrawn, the user can see the choppy transition from a blank layout to one with all 10 views added. What's the recommended approach to reduce the choppiness?
My guess is that you must be using some custom View that does a lot of processing during onDraw(). Try doing all the processing you can in advance or in a separate thread.
Also, using a ListView as inazaruk proposes will let you separate data generation from View rendering.
If that is not the case, look in your code if you are creating several objects in onDraw(). If so, reformat your code so you reuse those objects. That will prevent the garbage collector for kicking in all the time to recover your unused memory.
You can add all 10 items before LinearLayout is rendered (for example in onCreate method).
Or you can use ListView instead. You can find more details in ListView tutorial.
I have many views in a linear layout to create. I have created a background thread that loops through all the data and creates an array list of views. At the end of the thread it calls runOnUIThread to loop through the array list and add each view to the linear layout.
Is this dangerous? The views aren't part of the hierarchy yet when I'm creating and manipulating them in the background thread. Initial testing hasn't yielded any problems.
(I am using a linear layout instead of list views, because my experience with list views is that they try to reuse some of their elements for multiple rows. For example, a checkbox that you check becomes unchecked again if it scrolls off the screen and back on. This seems simpler. Maybe I'm taking a performance hit, though. Still need to check this thoroughly.)
It shouldn't cause any problems. You are not doing any change to the UI until it's really necessary, which is a good thing.
BUT...
because my experience with list views is that they try to reuse some of their elements for multiple rows. For example, a checkbox that you check becomes unchecked again if it scrolls off the screen and back on
You should try to do it using ListViews which will increase the performance. IMO, if you don't know how to use a ListView and its recycling system, that's not a good excuse to not use it at all; so, just try to read about that and give it a try. How hard could it be? You don't have to be Einstein to get that to work :)
I want to get the size of a view that is in my activity but I am not able to get that information in any of the activity lifecycle callbacks (onCreate, onStart, onResume). I'm assuming this is because the views have not been drawn yet. At what point are views drawn and is there a callback I can put my code so I can get the size of the view?
findViewById(R.id.header).getHeight();
How are views drawn provides a good overview of the process of drawing views. Basically, there is a pass where the measure what everything wants to be, and then a second pass when things are layed out.
It sounds like for your problem though, you should be able to accomplish your goal with resorting to setting height values by hand. Have you played around with the stretchMode, gravity, layoutHeight, etc of your gridview? See GridView javadoc for some details of the param choices.
It should work in onCreate(), onStart(), and onResume() after you've instantiated your layouts. Try:
findViewById(R.id.header).getLayoutParams().height