In my main activity i call setContentView in the onCreate. Then in onResume I start a service, if it is the first time into the service it creates an alarm and stops. I expected the layout to appear when setContentView is called but stepping through the debugger indicates that it isnt appearing until the service returns.
Should it display as soon as setContentView is called?
Edit
It seems that onWindowFocusChanged is not called at the start of the first Application (MAIN/LAUNCHER). By debugging it seems that the following happens:- MAIN onCreate - onStart - onResume (this where the service is started SERVICE class - onStart - service returns MAIN -onResume - onWindowsFocusChanged (the screen appears for the first time)
The diagrams I have seen say the activit开发者_如何转开发y is visbile from onStart onwards but that does not appear to be the case with the first activity. Is there any way to force the screen into view at the opening?
The content view is defined right after the call to setContentView()
, so you can start using findViewById()
and administrating the View
s of the user interface straight from here.
BUT:
the view is not displayed before
onResume()
returns. This is actually one of the purposes ofonResume()
: it is called each and every time theActivity
is going foreground, and thus just before its user interface is actually displayed.this doesn't mean the UI is visible at that time even though it is displayed. For example it can be hidden by the lockscreen.
onWindowFocusChanged(true)
is called when the user interface is actually visible (when it has just gained the focus).
So the instant at which the user interface is both displayed and visible is between onResume()
(which is called just before) and onWindowFocusChanged(true)
(which is called right after).
Use an AsyncTask and do an invalidate() with your Layout inside onPostExecute(). All UI drawing is done as soon as your return control to UI manager when you return from your code. There is no way to force a redraw without exiting your code, thats why people use AsyncTask or Handlers to do that.
My example:
// this goes inside your OnCreate don't use OnResume or you need to start
// your service each time apk resumes?? in that case put it inside
// OnStart()<-- start service OnStop()<-- stop service
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// do your initializing chores in here.....
setContenView(R.layout.mainlayout);
UIUpate ui = new UIUpdate();
ui.execute();
}
// define class somewhere in your code
private class UIUpdate extends AsyncTask<Void,Void,Void>{
@Override
protected Void doInBackground(Void... arg0) {
// fire your service here
StartMyService();
}
@Override
protected void onPostExecute(Void result) {
//assuming you put your view inside a LinearLayout
LinearLayout ll = (LinearLayout)findViewById(R.id.mylayout);
// check that your topmost LinearLayout has an ID, top most hasn't by default
ll.invalidate(); // program for update when this exit
}
If you analise programming pattern I've put above, you'll see is not complicated. Whenever you need to update UI, one needs to think that flow is like this -> mycode()--Ui manager-- mycodepart2(), you need to break up your code in two chunks, returning in first one to UI manager and the continuing in chunk two.
Problem is that you don't have control on how to execute chunk two once you exit to UI manager, thats why AsyncTask works good, PreExecute() do chunk1, PostExecute() do chunk 2. Both parts execute inside UI thread, you can update anything UI in those. doInBackground() its another different kind of animal, its executed in own thread and cannot update UI.
No in onCreate method the activity is only initialized. The real displaying of the activity is somewhere just before onWindowFocusChanged. From the docs
Keep in mind that onResume is not the best indicator that your activity is visible to the user; a system window such as the keyguard may be in front. Use onWindowFocusChanged(boolean) to know for certain that your activity is visible to the user (for example, to resume a game).
You can use the public void onAttachedToWindow ()
callback of Activity
. This callback is called when the main window associated with the activity has been attached to the window manager.
There is a View
's version of onAttachedToWindow()
that is called when the view is attached to a window. At this point it has a Surface and will start drawing. Note that this function is guaranteed to be called before onDraw(Canvas)
, however it may be called any time before the first onDraw
-- including before or after onMeasure(int, int)
.
Reference View.onAttachedToWindow()
first there is something called the activity life cycle. LINK according to this your activity will only come to view only after onResume returns.
so having an AsyncTask (LINK) as mojo suggested will help onResume return while the service is being called (in a separate thread).
so as for your question. if you grasp the Activity Lifecyle you will know what is happening.
so if you want the view to appear. then you can put the service call in the AsyncTask and let the setContent in the onCreate.
The layout is displayed immediately after onWindowFocusChanged()
is called. So you need to do something after onWindowFocusChanged()
. This is really simple.
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (!hasFocus) return;
Handler h = new Handler();
Runnable r = new Runnable() {
@Override
public void run() {
Log.v("[Testing]", "run() called");
//start your service here
}
};
h.post(r);
}
I'm not an expert, but the most straightforward way to see if a view is displayed is this:
if ( view.window )
{
...
}
Hope it helps!
精彩评论