Behy Behy - 15 days ago 6
Android Question

why UI processes before a heavy process are not executed first

Considering a simple code like this:

public class MainActivity extends Activity {
@Override
public void onCreate(Bundle savedInastanceState){
super.onCreate(savedInastanceState);
setContentView(R.layout.main);
final ProgressDialog pdUpdate = new ProgressDialog(this);
final Button btn = (Button)findViewById(R.id.btnUpdate);
btn.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View view){
btn.setText(Calendar.getInstance().getTime().toString());
int i=0;
while (i<100){
i++;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.i("test","i = " + i);
}
}
});

}
}


By click on
btn
two things should happen: changing the text of the button and counting
i
to 100 with delays of 100 msec (it is just an example to simulate a heavy process like reading file, downloading etc).

I know the correct way of implementing such codes is to use
AsyncTask
but my question is about how this code is compiled. It is a single thread app. So the compiler reads
btn.setText(Calendar.getInstance().getTime().toString());
first and goes to the next lines of code only after this line is executed (please correct me if I am wrong), but it does not happen. Why?
In
C#
there is a
Refresh()
method which solves this problem (just call it after UI changes and changes are applied). Is there any similar method in java?
I appreciate any help.

EDIT 1

there question is about the order of the following processes:
Process 1:


btn.setText(Calendar.getInstance().getTime().toString());


Process 2:

i++;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.i("test","i = " + i);
}


No matter which one comes first ( I mean either
btn.onClick(){process1;process2;}
or
btn.onClick(){process2;process1;}
), always the second process is executed first. I mean first I see the counting of
i
in Logcat and then see the changing of the button text.

Answer

You do not need to call any equivalent of refresh() in this case. However Button.setText() do not redraw the view hierarchy automatically. Instead it passes up the view hierarchy the information that the text changed and that it needs to be redrawn. Ultimately this information reaches the root of the view hierarchy which in turn informs the Choreographer. The Choreographer schedules the drawing for the next frame. This in turn gets stored in your UI thread's message queue.

So when you put your UI thread to sleep, the layout is not redrawn, but is scheduled to be redrawn. As soon as your thread becomes idle, a messages from message queue start being executed. At some point the Choreographer is called with the redraw message and orders the view hierarchy to redraw itself.

Also consider that methods like Handler.post(Runnable), View.post(Runnable) and their postDelayed counterparts can serve as an alternative to AsyncTask if do not need to do a heavy computation, but instead schedule some operation (for example a view update) for later. These use the same mechanism as described above - put a Runnable into the thread's message queue, which in turn gets picked up and executed when the thread is idle.