Search code examples
androidmultithreadinguser-interfaceandroid-activitylifecycle

Is the Android UI-thread working similar to the Swing UI thread?


EDIT: I modified the question a bit. I did now actually implement my example. Before I transferred my actual code to a simpler example which actually did some thing different in the end.

I am wondering if it is save to assume that the Android UI thread is working similar to the Swing UI thread with respect to that future UI events are only scheduled at the end of the execution queue when calling e.g. Activity.startActivity. I remember that when I learning Swing many years ago, you actually scheduled a Runable for execution on the end of the queue. I imagine this is similar for Android, where the Activity scheduled by e.g. Activity.startActivity only will get rendered after:

  1. The yet to complete stack of activity life cycle method calls (onStart, onPause, onStop, etc) returned.
  2. Any other scheduled event on the UI thread is completed (other Activities that were previously set to become active by calls to e.g. Activity.startActivity).

However, this is only partially what I observed:

MainActivity:

public void onCreate(Bundle b) {
 for(int i = 0; i < 3; i++) {
  Log.d(TAG, "Schedule OtherActivity " + i);
  startActivity(new Intent(this, OtherActivity.class).putExtra("instance", i));
  Log.d(TAG, "Done scheduling OtherActivity " + i);
 }
}
public void onResume() {
 Log.d(TAG, "Resumed MainActivity");
}

OtherActivity:

public void onCreate(Bundle b) {
 int instance = getIntent().getIntExtra("instance", -1);
 Log.d(TAG, "Created OtherActivity " + instance);
 startActivity(new Intent(this, YetAnotherActivity.class).putExtra("instance", instance);
}
public void onStart() {
 Log.d(TAG, "Started OtherActivity " + getIntent().getIntExtra("instance", -1));
 finish();
}
public void onStop() {
 Log.d(TAG, "Stopped OtherActivity " + getIntent().getIntExtra("instance", -1));
}

YetAnotherActivity:

public void onCreate(Bundle b) {
 Log.d(TAG, "Created YetAnotherActivity " + getIntent().getIntExtra("instance", -1));
}
public void onStart() {
 Log.d(TAG, "Started YetAnotherActivity " + getIntent().getIntExtra("instance", -1));
 finish();
}
public void onStop() {
 Log.d(TAG, "Stopped YetAnotherActivity " + getIntent().getIntExtra("instance", -1));
}     

would result in:

Schedule OtherActivity 0
Done scheduling OtherActivity 0
Schedule OtherActivity 1
Done scheduling OtherActivity 1
Schedule OtherActivity 2
Done scheduling OtherActivity 2
Created OtherActivity 2
Started OtherActivity 2
Created YetAnotherActivity 2
Started YetAnotherActivity 2
Created OtherActivity 1
Started OtherActivity 1
Created YetAnotherActivity 1
Started YetAnotherActivity 1
Created OtherActivity 0
Started OtherActivity 0
Created YetAnotherActivity 0
Started YetAnotherActivity 0
Resumed MainActivity
Stopped OtherActivity 2
Stopped YetAnotherActivity 2
Stopped OtherActivity 1
Stopped YetAnotherActivity 1
Stopped OtherActivity 0
Stopped YetAnotherActivity 0

Will this always be the turn out or can Android execute this example in another order than this? I was assuming that UI events are inherently synchronized since they are scheduled in a particular order as I observed it. However, I cannot figure out how the actual scheduling works.

I did for example not expect that some UI events (i.e. Constuctor/onCreate/onStart/onResume/onPause) are always scheduled to the front of the execution queue whilst some events are scheduled to its end (i.e. onStop/onDestroy). But according to this theory, why is the OtherActivity destroyed before YetAnotherActivity? And how does onResume end up at the beginning of the execution queue all of a sudden?

Can somebody explain how UI scheduling works in general? Thanks for any feedback on my thoughts!


Solution

  • Here's the "algorithm" I could decode from the output sequence obtained from your simulation example. This algorithm would be executed by the main UI thread.

    > To start with, the scheduler initializes queue Q with MainActivity's onCreate()
    > while (Q is not empty) {
    >   worker thread retrieves one element E from head of Q
    >   if (E is "A.onCreate()")  // A is any activity
    >       insert "A.onStop()" into tail of Q
    >   process E (while processing, a "startActivity(A)" will immediately cause A.onCreate() to be pushed into head of Q, so activity invocations follow "stack" order)
    > }
    

    So while there has to be a queue for the sequence of events, it's an "unconventional" queue. during processing by main UI thread, the events in the queue cause it to grow on the rear and/or front depending on the event (this decision is taken on the fly).