android change UI from background thread - why it's working? - android

Will ever crash an application that changes text, background resource and inflate some views in it in a background thread, if the view's visibility is GONE ? I've done some tests with two buttons, one visible and one gone and if I changed text of the visible one in background thread, it crashed and when I've changed the text of the button with GONE visibility, it worked without a crash. Can someone explain this?

Ok, I have a something for you.
Event Handling and Threading
The basic cycle of a view is as follows:
An event comes in and is dispatched to the appropriate view. The
view handles the event and notifies any listeners.
If in the course of processing the event, the view's bounds may need
to be changed, the view will call requestLayout().
Similarly, if in the course of processing the event the view's
appearance may need to be changed, the view will call invalidate().
If either requestLayout() or invalidate() were called, the framework
will take care of measuring, laying out, and drawing the tree as
appropriate.
Note: The entire view tree is single threaded. You must always be on the UI thread when calling any method on any view. If you are doing work on other threads and want to update the state of a view from that thread, you should use a Handler.
You can find much more here http://developer.android.com/reference/android/view/View.html .
In your case Your View is already GONE so I think its not attached to View Tree.

You have to create an Handler!
In that handler put your code to update your UI and in the thread call the Handler!
You should never update the UI from an thread directly in none of langages! it's a big error in programming!
Example to create your handler:
static Handler updater1 = new Handler() {
#Override
public void handleMessage(Message msg) {
//your code to update the UI
}
};
Example to call your handler from the thread:
updater1.sendEmptyMessage(0);
The behaviors about to change the text from a thread can be different in all langages! but you should never do that it's a big error!Maybe when you tried to update a text on a button with visibility "GONE" it just not worked! but you can't see it!

Related

How to detect a moment when ListView item becomes ActiveView (going off-screen)

According to concept of recycling items mechanism in ListView.
I want to know, actually, how i can detect a moment when a View going off-screen.
I explain why.
In most cases ListView have a custom
Adapter(? extends ArrayAdapter / ? extends BaseAdapter, etc.).
getView(...) method allows to manipulate visibility and content of views (text,bitmaps,drawables,etc.)
And in some cases i need to launch a separate Thread which doing background work, and after that update UI. Actually - using AsyncTask.
When i have many items in ListView each call of getView will be produced start a new Thread. I need to cancel them if View is no more longer present on the screen. How to do this?
You can override onDetachedFromWindow for the view.This will let you know when the view is going off-screen.The docs says:
protected void onDetachedFromWindow ()
Added in API level 1 This is called when the view is detached from a
window. At this point it no longer has a surface for drawing.
See Also
onAttachedToWindow()

Android view's post method

I wanted to know if View.post(Runnable r) runnable's run() method is executed after View is drawn or after View (in case it is a ViewGroup) and all it's children are drawn?
It will be put into UI message queue, and it depends on internal Android workings when exactly will be executed. If rendering of child views is in one message then it might execute after rendering, if it is split by android into several messages then your message might possibly be executed in between of rendering.
If you want to make sure it will be executed after child redraw, maybe use View.postDelayed with some small delay?
What event is fired after all views are fully drawn?
here is explanation from Romain Guy that it is actuall executed after redraw - if nothing changed (its 4 year old SO), then you might trust this answer.

Why does setting a ListView's choice mode to CHOICE_MODE_NONE only work when posted as a Runnable()?

I have been battling with a ListView (in a ListFragment) whose choice mode I want to change between CHOICE_MODE_NONE and CHOICE_MODE_MULTIPLE. Switching between the modes is fine, but getting the selected items to be deselected is tricky.
Several approaches are discussed here, but the only one I could really get to work was by setting the choice mode (listView.setChoiceMode(ListView.CHOICE_MODE_NONE)) within a new Runnable() posted to the ListView.
That's great, but I don't understand why it works, and I am struggling to find more information. Could someone explain how and why this works? Many thanks.
You can touch Views (modifying it's background, changing their content, drawing objects on them etc etc...) in main UI Thread only...
If you want to touch outside the UI Thread, then you need a Runnable action and post it to the View Handler...
and here may be your changing ListView choice mode in non UI Thread which obviously need a Runnable action but if you are doing this in UI Thread, directly you can call ListView.setChoiceMode()...

Optimizing redraws of multiple View objects

I am creating an android app that is essentially a dashboard with many gauges and indicators on it. I have a Main View which is added in the Main Activity's onCreate() method. Each gauge is a custom View object which is added and initialized in the Main View and drawn in the Main View's onDraw() method. The gauge values are constantly updated by individual threads that are launched in the Main Activity's onCreate() method. When a thread detects the need to change a gauge value, it does so, and then sends a message to the Main View (via a message handler) telling it that the particular gauge needs to be updated (redrawn). I am using invalidate() in the Main View's message handler to refresh the screen. The app runs well, but I am wondering if I am handling the display updates as efficiently as I can. My question is:
When I call invalidate() in the Main View, I assume it is redrawing all the gauge Views, even the ones that have not changed. If so, would it be more efficient to just redraw the View of the gauge that has changed? What is the best way to do that? I have tried calling the individual View's invalidate() and postInvalidate() methods but neither works.
As requested, here is the current state of the onDraw method in the Main View. Eventually there will be a lot more gauges added. The Bezels are static and only change if the device switches configuration (landscape/portrait). The various gauges are instantiated from a Gauge class which extends View:
#Override
protected void onDraw(Canvas canvas) {
speedoBezel.draw(canvas);
tachBezel.draw(canvas);
oilPressBezel.draw(canvas);
oilTempBezel.draw(canvas);
speedoGauge.draw(canvas);
tachGauge.draw(canvas);
oilPressGauge.draw(canvas);
oilTempGauge.draw(canvas);
}
Ok, I have read so many ways to animate in Android I started to mix them up. I would like to rephrase the question:
If I am developing an app with many different objects in the main view that changed frequently but at different intervals, is it better performance wise to:
Add the objects to the main view and use the invalidate(rect) in the main view to update them individually as needed, or
Add each object to a Layout and use invalidate on each view when they require updating.
Important to note that none of the objects overlap

View.post(), and when Runnables are executed

My original problem was needing to know the height and width of my root View so that I could make programmatic layout changes. For my purposes, I don't necessarily need to determine this information during onCreate(); it's quite sufficient for me to programmatically add my child Views after layout of the root has completed, so therefore I'm happy to use onWindowFocusChanged() as a hook to determine when calling the root View's getWidth() and getHeight() will return valid results.
However, I see quite a few people have asked how to determine the root View's size during onCreate(). I'm guessing people want to do this for better user experience - perhaps so that users don't see the layout being built in stages (if anyone can clarify the reasons, I'd appreciate it). Now, the answer I have commonly seen given to this, such as the one here, is to post a Runnable to the root View within onCreate(). Inside that Runnable we perform the getWidth(), etc. The reason why this works is because, apparently, Runnable objects posted to a View are executed when the View has layout and / or is attached to the window.
This brings me to my question. In the API documentation for View, it doesn't seem to describe this behavior. So, can anyone tell me where it is defined and documented? Or, is it a matter of inspecting the source? Is it an absolutely and rigidly defined feature that Runnables will stay in a View's queue and only be handled at a certain point after the layout process?
Further clarification: On reading Kerry's answer and thinking it over a bit more, my basic question can be clarified as follows: In the answer given here and also in this CodeProject entry, I understand that we get around the problem of the root View's dimensions not being available during the onCreate() by posting a Runnable to the View. As Kerry points out, the guarantee is that this message Runnable cannot be executed until onCreate() has executed. I understand that layout occurs some point after onCreate, but I still can't grasp at the moment why this Runnable should execute when the View's dimensions are known.
I had a look at the View.post(Runnable) method and it seems to me that by calling that method you are just adding a message to the UI thread queue. The only thing that is going to be 'guaranteed' is that the Runnable will be executed sometime AFTER the method which has called post(Runnable) has completed. This assumes you are calling post(Runnable) from the UI thread but as the docs say:
This method can be invoked from outside of the UI thread only when this View is attached to a window.
I think to be sure that both your Root view and Child view both have size, you would need to call post(Runnable) from the child onSizeChanged() method because if the child has size I think it follows that the Parent i.e. Root view therefore must have size too.
Apologies if this is a bit of a rambling answer. I kind of understand what you're wanting to achieve but not 100% sure. Let me know if you want me to clarify anything.
Personally whenever I've needed the size of a View I do everything in onSizeChanged() which I do believe is the 'correct' way of doing it and it has always worked.

Categories

Resources