I'm wondering why the post() method is a specific to a View and not just a static method. It doesn't seem like the Runnable argument is closely tied to a specific view anyway.
I did find this other question which explains that (as of 4 years ago) the runnable will be run after the view has been drawn, but that doesn't quite answer my question.
What event is fired after all views are fully drawn?
Because it decides which handler to post the event to based on a few different criteria. Check the code at the AOSP. If the view is attached to a window, it uses the one in the attach info. If not, it uses the ViewRoot.getRunQueue and posts it there. So there's a possibility of it posting to different handlers if, for example, you had a view in a different window like a Toast you were calling post on. Thus the need for a non-static function.
Related
I've got a BaseQuestion super class which extends a fragment. I've got several subclasses of this question, including DropDownQuestion and EditTextQuestion. I would like to do some pre-population and validation upon when a particular question has lost focus.
Originally, I had the onFocusChangeListener implemented by my BaseQuestion class, but it never got called, so I added setFocusable and setFocusableInTouchMode to a bunch of stuff in it, including the question's LinearLayout, and the actual view itself. But it still never got called. Then I realised, I can't add the logic in their, since it has no knowledge of the other questions. So I need to do it in my FragmentActivity.
So my actual question is: How do I know when the focus has been lost on a particular View in the Fragment whilst in the FragmentActivity and then act upon it?
Thanks!
UPDATE
Also, this is for a dynamic number of questions. So there may be quite a lot of questions.
EDIT
Bump
EDIT2
One more bump!
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.
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.
I'm writing a library for mobile devices. This library notifies the users when certain things happen (login, actions, etc). The way it works in iOS is modeled after GameCenter. A window animates down from the top of the screen, notifying the user, and then animates off.
In iOS, I can easily get the current view in the UIWindow and add my view to it. I'm fairly new to Android, and I can't figure out how this is possible. It seems like unless you have knowledge of the current Activity and its layout, you can't add a view to it.
Is what I want to accomplish even possible? Is this even the correct solution for Android or would an Android user expect something different?
You can get the root view of an activity by calling getWindow().getDecorView() on the activity object or inside of the activity. If this is a ViewGroup you can add a view using addView(View viewToAdd), if this is not an instance of ViewGroup you cannot add a view to it unless you wrap it in a ViewGroup.
If these are your first applications in Android, use XML layours put in resourses. In this case you always must know what Activity are you in. Whithout it you can't read resources.
If you use pure code for views, you alweys can get your activity, because every your activity is a class. Put all operations in the class base for all your activities and use this.class in them for obtaining the current activity name.
You can also pass the current activity as a parameter into the library functions. So you have access not only to its root view, but to the context, to, and that will allow you to show toast messages about problems and have access to resources. (Passing context is a very common practice in Android coding.)
All you need to do is call addView() on the ViewGroup.
I have a view in android in which I need to sequentially highlight and unhighlight buttons when a particular control is pressed. This is a usability feature -- as each button is highlighted, it is read aloud to the user. I use the AlphaAnimation class to accomplish the highlighting. However, now matter how many invalidate calls or callback threads I put in, only the last animation is actually presented to the user. The others are still called but overridden by the last animation so only one is shown. I have also tried simply setting the opacity/alpha properties of the buttons, but all of these modifications end up being batched and performed all at once. I need these animations to occur in a sequence. I have not yet found a good way to update the main view before control flow is returned to it (i.e. update it multiple times before the method it calls returns). Does anyone have any ideas?
For everyone else who runs into this problem, I finally found a solution.
The documentation:
http://developer.android.com/reference/android/os/AsyncTask.html
http://www.anddev.org/tut_updating_ui_from_a_thread-t11125.html
My solution: create an AsyncTask that takes in an array of buttons. In its doInBackground method, it highlights/dims and then pushes an update of the effected buttons to the onProgressUpdate method during each iteration in the button highlighting scheme. The onProgressUpdate method calls invalidate() on all the buttons passed in. Then for easy access to the highlighting functionality, I created a static highlight(buttons...) method that creates a new instance of the AsyncTask and calls execute on it.