I am populating a linear layout dynamically. Depending upon response, I have to clear the past child views and create new views. I have read the document, but still be confused with the couple methods, they all look the same function. Which function I should use.
As Scott Biggs points out, the difference is not a big one. The only difference is that removeAllViews() calls requestLayout() and invalidate() afterwards. The key to why this difference is here is to understand the naming of removeAllViewInLayout(). Confusingly, its meaning isn't "remove all views within this view layout."
If we look at the similar method, removeViewInLayout(), we can understand what it's supposed to mean:
Removes a view during layout. This is useful if in your onLayout() method, you need to remove more views.
So removeAllViewsInLayout() actually means "remove all views, and we're calling this method during a layout pass (i.e. onLayout())". That's why removeAllViewsInLayout() doesn't call through to requestLayout(), as it's assumed that you're already currently inside a layout pass, so requesting another layout pass is unneeded.
If you use removeAllViewsInLayout(), then it's your responsibility to ensure that you're calling this during a layout pass, or to properly call requestLayout() and invalidate() as needed.
removeAllViews() : Call this method to remove all child views from the ViewGroup.
removeAllViewsInLayout() : Called by a ViewGroup subclass to remove child views from itself, when it must first know its size on screen before it can calculate how many child views it will render.
Well, looking at the source, there isn't much difference:
public void removeAllViews() {
removeAllViewsInLayout(); // Details implemented here
requestLayout();
invalidate(true);
}
So unless you want to call invalidate() at a time of your choosing, you might as well use removeAllViews() and save yourself a bit of typing.
EDIT
For a more detailed explanation, see David Lui's answer. To sum it up, use removeAllViews() unless you're in the process of constructing a View--in which case you'd call removeAllViewsInLayout().
Related
I'm not sure about the usage of onAttachedToWindow.
My question is basically about the documentation.
Which mentions:
[...] it may be called any time before the first onDraw --
including before or after onMeasure(int, int)
I what to know:
when it is called before onMeasure and when is it called after.
The Story behind:
I am adding OnGlobalLayoutListener in onAttachedToWindow and remove it in onDetachedFromWindow. Because is somehow logic to me to handle the layouting when the view is added to the window.
But I am concerned that the first onGlobalLayout calls get lost, if the Listener is not added yet. (because onMeasure usually happens during the layouting)
If someone got a better approach for my problem, feel free to give me a hint.
Docs are correct, and you should not rely on onWindowAttach/Detach being in sync with onMeasure or onLayout pass.
If your View class is interested in parent hierarchy changes, I'd advice against such a design. The Parent UI should notify sub-views of hierarchy changes. So, OnGlobalLayoutListener better be used by an enclosing UI class.
Also, View class has onSizeChanged() that you can override to detect when it has been measured up.
In Android documentation, it says the following for addView (and a few other methods):
Note: do not invoke this method from draw(android.graphics.Canvas),
onDraw(android.graphics.Canvas), dispatchDraw(android.graphics.Canvas)
or any related method.
What's the reason for this restriction? Also, what are the "related methods"? For instance, is surfaceChanged such method?
It's because when rendering Views, the ViewGroup containing the Views goes through certain steps when mapping out where each view will appear on the screen. The steps a ViewGroup takes are:
Measure (the ViewGroup measures all of its child views)
Layout (the ViewGroup positions the measured children at their locations on the screen according to their measurements and ViewGroup.LayoutParams)
Draw (the views are drawn on screen).
Since the draw step is the last step when rendering Views on the screen, adding additional Views at this step of the process could potentially change (invalidate) the entire layout. If you take a look at the source code for ViewGroup you'll see that making a call to addView(View v) starts the entire layout process over again:
public void addView(View child, int index, LayoutParams params) {
if (DBG) {
System.out.println(this + " addView");
}
// addViewInner() will call child.requestLayout() when setting the new LayoutParams
// therefore, we call requestLayout() on ourselves before, so that the child's request
// will be blocked at our level
requestLayout();
invalidate(true);
addViewInner(child, index, params, false);
}
Also, when the ViewGroup draws it's child Views on the screen, it normally iterates through all of the Views currently added to the ViewGroup. So, if this type of event were to be dispatched during a draw method, it could potentially cause the ViewGroup to attempt drawing a View that hasn't gone through the necessary steps for rendering yet.
As for related methods, these would essentially be methods that would invalidate the ViewGroup's the current drawing operation.
Edit:
The SurfaceHolder.Callback methods are just Interface methods for tracking the state of your drawing surface or SurfaceView/GLSurfaceView. Since the state of the layout should remain constant until the Draw step has finished, there shouldn't really be a need to call this method at that point in the process. However, since these methods are basically Interface methods that YOU implement (they're empty by default in the source), there shouldn't really be a reason why calling one of these methods should cause an error, even though I'm not sure that it would be appropriate to do so. One case that would case an issue would be if your underlying implementation leads to issues like the one I explained above...
The problem:
I have a class, inherited from LinearLayout.
This class creates some buttons in the constructor and puts them into itself using addChild().
I've overloaded method onSizeCHanged and I want to add some childs in this method.
But changes have no effect until one of the other buttons clicked.
So, I need to press some of existing buttons and after that views which I've added appear.
(by the way, only buttons with ontouchlistener do it. buttons without listener cannot make new views appeared).
How to add views in onSizeChange method to do them appeared immediately?
ADDITION:
Methods forceLayout() and requestLayout() cannot work.
I have not extended LinearLayout myself but I read up on the class a bit and I think you need to override onLayout() and add your child views in it. Check the docs and see if it helps
http://developer.android.com/reference/android/widget/LinearLayout.html#onLayout(boolean,%20int,%20int,%20int,%20int)
The solution was: making a simple boolean flag, setting it "true" im onSizeChanged and calling "invalidate".
In method "onDraw" checking if flag is true and if it is so, calling requestLayout. Then setting flag to false.
I have a ListView with custom Adapter. To be honest, I have many of them at the same time on screen, and my Tegra 3 device started to lag, what made me really confused... I found than in each ListView's Adapter the getView() method is called for all visible rows every time any animations runs on screen. That gives me like few hundreds of calls per second! Digging more, most of these calls are due to measure() and onMeasure() calls of ListViews' parents, and - this is tke key - they are useless, because all the layouts of my ListViews
have const size.
So my question is: how to eliminate these calls? Of course I want to leave proper calls alone (caused by adding items to Adapter and notifyDataSetChanged() ).
I've tried almost anything, but either the whole list doesn't draw itself (when I overriden it's onMeasure() and forced to returned const size without calling super.onMeasure()) or stops updating at some time.
How you implemented the getView() method? If you implement it in the correct way there should be nearly no lagging.
Check out this really really good video:
http://www.youtube.com/watch?v=wDBM6wVEO70
Slides: http://dl.google.com/googleio/2010/android-world-of-listview-android.pdf
As Romain said, work with it not against it. Best is to leave measure() alone and focus on your adapter.
Thats how ListView is implemented.. I don't think that will cause a performance Overhead.. Provided you do things properly there..
For example..
Don't instanciate LayoutInflator inside GetView Method, Do it at class level..
And Inflate View Only if the convertView==null or else just return convertView.. Inflating view is a costly process....
Well like you said these calls are due to measure() and onMeasure() calls of ListViews parents and I'm sure you are using height=wrap_content also with wrap_content on height your ListView will check without stop if your height has changed.
So the solution is to put the height=fill_parent.
I hope this helped you.
The underlying reason for this is that ListView.onMeasure() calls AbsListView.obtainView(), which will request a view from your list adapter. So if your view is being remeasured through animations, your performance will be very poor.
Can i call setcontentview multiple times if my layout is same but the resource changes.for instance if images get exchanged in 2 imageview widgets??(this is infact all that is happening in my app)
You can switch the setContentView several times. However, I have learned in practice, that UI elements don't cross over. In other words each time you set the view, you have to re-findViewById for your UI elements.
You should go for ViewFlipper. Follow this link,it may help you.
Calling setContentView() multiple times
You can "refresh" the ImageViews by calling
myImageView.invalidate();
This will make the view be redrawn. If you're using an AdapterView (such as a ListView) call
myListView.notifyDataSetChanged();