This app executes an infinite
for
loop.
But the UI (main) thread is not allowed to go into an infinite loop.
For example, if the
onCreate
method went into an infinite loop,
we would never finish executing
onCreate
and we would never execute the other
lifecycle
methods.
We therefore create a second thread to execute the infinite loop.
The second thread is not allowed to write on the screen
(only the UI thread can do that),
so it performs its output with
Log.d
.
The code to be executed by a second thread is packaged in a method named
run
.
The
run
method is packaged in a subclass of class
Runnable
.
See
Specifying
the Code to Run on a Thread.
MainActivity.java
.
The
runnable
variable refers to an object that belongs to an anonymous subclass of class
Runnable
.
activity_main.xml
strings.xml
AndroidManifest.xml
build.gradle
(Module: app)
A few seconds after launching the app,
press the Android back button
to destroy the
Activity
.
Observe that the second thread keeps on running.
One way to kill the thread is to
go to the Settings app and Force Stop or Uninstall the app.
Another way is with the
kill
command below.
08-25 18:41:37.590 6291-6291/? D/myTag: App Process ID: 6291 08-25 18:41:37.590 6291-6291/? D/myTag: Name of UI thread: main 08-25 18:41:37.590 6291-6291/? D/myTag: ID of UI thread: 1 08-25 18:41:37.590 6291-6304/? D/myTag: Name of second thread: Thread-348 08-25 18:41:37.590 6291-6304/? D/myTag: ID of second thread: 348 08-25 18:41:37.590 6291-6304/? D/myTag: 0 08-25 18:41:38.590 6291-6304/? D/myTag: 1 08-25 18:41:39.594 6291-6304/? D/myTag: 2 08-25 18:41:40.594 6291-6304/? D/myTag: 3 08-25 18:41:41.594 6291-6304/? D/myTag: 4 08-25 18:41:42.594 6291-6304/? D/myTag: 5 08-25 18:41:43.594 6291-6304/? D/myTag: 6 08-25 18:41:44.594 6291-6304/? D/myTag: 7 08-25 18:41:45.594 6291-6304/? D/myTag: 8 08-25 18:41:46.594 6291-6304/? D/myTag: 9 08-25 18:41:47.594 6291-6304/? D/myTag: 10 08-25 18:41:47.981 6291-6291/? D/myTag: onDestroy 08-25 18:41:48.598 6291-6304/? D/myTag: 11 etc.
adb devices adb -s 192.168.57.101:5555 shell ps USER PID PPID VSIZE RSS WCHAN PC NAME u0_a56 6291 149 587548 39004 ffffffff b76a207b S edu.nyu.scps.thread ps -t 6291 USER PID PPID VSIZE RSS WCHAN PC NAME u0_a56 6291 149 587548 39004 ffffffff b76a207b S edu.nyu.scps.thread u0_a56 6294 6291 587548 39004 c0183a45 b76a2399 S GC u0_a56 6296 6291 587548 39004 c014bfe7 b76a17cb S Signal Catcher u0_a56 6297 6291 587548 39004 c021a64f b76a0770 S JDWP u0_a56 6298 6291 587548 39004 c0183a45 b76a2399 S Compiler u0_a56 6299 6291 587548 39004 c0183a45 b76a2399 S ReferenceQueueD u0_a56 6300 6291 587548 39004 c0183a45 b76a2399 S FinalizerDaemon u0_a56 6301 6291 587548 39004 c0183a45 b76a2399 S FinalizerWatchd u0_a56 6302 6291 587548 39004 c05963ba b76a0586 S Binder_1 u0_a56 6303 6291 587548 39004 c05963ba b76a0586 S Binder_2 u0_a56 6304 6291 587548 39004 c0183a45 b76a2399 S Thread-348 kill -9 6291 ps -t 6291 USER PID PPID VSIZE RSS WCHAN PC NAME
In Android Studio, pull down
Tools → Android → Android Device Monitor
On the Devices tab, select your device and your app.
On the toolbar, press the Update Threads icon (three parael arrows).
Runnable
object be an anonymous temporary.
Thread thread = new Thread(new Runnable() { @Override public void run() { Thread currentThread = Thread.currentThread(); Log.d("myTag", "Name of second thread: " + currentThread.getName()); Log.d("myTag", "ID of second thread: " + currentThread.getId()); for (int i = 0;; ++i) { Log.d("myTag", String.valueOf(i)); try { Thread.sleep(1000L); //milliseconds } catch (InterruptedException interruptedException) { } } } }); thread.start();
Thread
be an anonymous temporary too.
new Thread(new Runnable() { @Override public void run() { Thread currentThread = Thread.currentThread(); Log.d("myTag", "Name of second thread: " + currentThread.getName()); Log.d("myTag", "ID of second thread: " + currentThread.getId()); for (int i = 0;; ++i) { Log.d("myTag", String.valueOf(i)); try { Thread.sleep(1000L); //milliseconds } catch (InterruptedException interruptedException) { } } } }).start();
android.os.Process.setThreadPriority
rather than
Thread.setPriority
,
but it doesn’t say why.
android.os.Process.setPriority
goes from –20 (highest scheduling priority)
to 19 (lowest scheduling priority) inclusive.
Thread.setPriority
goes from 10 (highest scheduling priority)
to 1 (lowest scheduling priority) inclusive.
Incidentally,
android.os.Process.myTid
returns a different number than
Thread.getId
.
//In the onCreate method. int myTid = android.os.Process.myTid(); Log.d("myTag", "priority of UI thread: " + android.os.Process.getThreadPriority(myTid));
//In the run method, before the infinite loop. android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND); int myTid = android.os.Process.myTid(); Log.d("myTag", "priority of second thread: " + android.os.Process.getThreadPriority(myTid));
priority of UI thread: 0 (this is equal to android.os.Process.THREAD_PRIORITY_DEFAULT) priority of second thread: 10 (this is equal to android.os.Process.THREAD_PRIORITY_BACKGROUND)
//at the start of onCreate Thread.State state = currentThread.getState(); Log.d("myTag", "state of UI thread = " + state);
//at the end of onCreate Log.d("myTag", "state of second thread = " + thread.getState()); thread.start(); Log.d("myTag", "state of second thread = " + thread.getState());
state of UI thread = RUNNABLE state of second thread = NEW state of second thread = WAITING
Activity
.
Observe that you now have two threads running simultaneously.
Things get messy if an
Activity
creates a thread that can run forever and does not destroy it.
Let’s keep the thread alive only while the
Activity
is in the resumed state.
Add three fields to
MainActivity
.
Thread thread; int i = 0; boolean shouldContinue = true;Create the
thread
object in the
onCreate
method of the
MainActivity
,
as we are currently doing,
but do not call its
start
method there.
Add the following methods to class
MainActivity
.
@Override protected void onResume() { super.onResume(); shouldContinue = true; thread.start(); //Create the thread. } @Override protected void onPause() { shouldContinue = false; //Destroy the thread. super.onPause(); }Change the
for
loop to
for (; shouldContinue; ++i) {