Threads

A Thread object, that is, an instance of the Thread class defined by Java, is a unit of execution with its own call stack. Applications can create additional threads easily, as shown in Listing 5–1. Of course, your application is free to create additional threads to perform some operations outside of the main thread; very often you will have to do exactly that to keep your application responsive.

Listing 5–1. Creating Two Threads

    // the run() method can simply be overridden…
    Thread thread1 = new Thread("cheese1") {
        @Override
        public void run() {
            Log.i(”thread1”, "I like Munster");
        }
    };

    // …or a Runnable object can be passed to the Thread constructor
    Thread thread2 = new Thread(new Runnable() {
        public void run() {
            Log.i(”thread2”, "I like Roquefort");
        }
    }, "cheese2");

    // remember to call start() or else the threads won't be spawned and nothing will
happen
    thread1.start();
    thread2.start();

Executing that code may actually give different results. Because each thread is a separate unit of execution, and both threads have the same default priority, there is no guarantee “I like Munster” will be displayed before “I like Roquefort,” even though thread1 is started first. The actual result depends on the scheduling, which is implementation-dependent.

NOTE: A typical mistake is to call the run() method instead of start(). This causes the run() method from the Thread object (and the Runnable object if applicable) to be called from the current thread. In other words, no new thread would be generated.

The two threads above were simply started, with no expectation of a result transmitted back to the thread that spawned them. While this is sometimes the desired effect, often you want to get some sort of result from what is being executed in different threads. For example, your application may want to compute a Fibonacci number in a separate thread, to keep the application responsive, but would want to update the user interface with the result of the computation. This scenario is shown in Listing 5–2, where mTextView is a reference to a TextView widget in your layout and onClick is the method called when the user clicks on a button, or a view in general (see the android:onClick attribute in XML layout).

Listing 5–2. Worker Thread to Compute Fibonacci Number

public void onClick (View v) {
    new Thread(new Runnable() {
        public void run() {
            // note the ‘final' keyword here (try removing it and see what happens)
            final BigInteger f = Fibonacci.recursiveFasterPrimitiveAndBigInteger(100000);
            mTextView.post(new Runnable() {
                public void run() {
                    mTextView.setText(f.toString());
                }
            });
        }
    }, “fibonacci”).start();
}

While this would work just fine, it is also quite convoluted and makes your code harder to read and maintain. You may be tempted to simplify the code from Listing 5–2 and replace it with the code shown in Listing 5–3. Unfortunately, this would be a bad idea as this would simply throw a CalledFromWrongThreadException exception, the reason being that the Android UI toolkit can be called only from the UI thread. The exception's description says “only the original thread that created a view hierarchy can touch its views.” It is therefore mandatory for the application to make sure TextView.setText() is called from the UI thread, for example by posting a Runnable object to the UI thread.

Listing 5–3. Invalid Call From Non-UI Thread

public void onClick (View v) {
    new Thread(new Runnable() {
        public void run() {
            BigInteger f = Fibonacci.recursiveFasterPrimitiveAndBigInteger(100000);
            mTextView.setText(f.toString()); // will throw an exception
        }
    }, “fibonacci”).start();
}

TIP: To facilitate debugging, it is good practice to name the threads you spawn. If no name is specified, a new name will be generated. You can get the name of a thread by calling Thread.getName().

Each thread, regardless of how it was created, has a priority. The scheduler uses the priority to decide which thread to schedule for execution, that is, which thread gets to use the CPU. You can change the priority of a thread by calling Thread.setPriority(), as shown in Listing 5–4.

Listing 5–4. Setting a Thread's Priority

    Thread thread = new Thread("thread name") {
        @Override
        public void run() {
            // do something here
        }
    };
    thread.setPriority(Thread.MAX_PRIORITY); // highest priority (higher than UI thread)
    thread.start();

If the priority is not specified, the default priority is used. The Thread class defines three constants:

  • MIN_PRIORITY (1)
  • NORM_PRIORITY (5) – the default priority
  • MAX_PRIORITY (10)

If your application attempts to set a thread's priority to some out-of-range value, that is, less than 1 or greater than 10, then an IllegalArgumentException exception will be thrown.

Android provides another way to set a thread's priority, based on Linux priorities, with the Process.setThreadPriority APIs in the android.os package. The following eight priorities are defined:

  • THREAD_PRIORITY_AUDIO (-16)
  • THREAD_PRIORITY_BACKGROUND (10)
  • THREAD_PRIORITY_DEFAULT (0)
  • THREAD_PRIORITY_DISPLAY (-4)
  • THREAD_PRIORITY_FOREGROUND (-2)
  • THREAD_PRIORITY_LOWEST (19)
  • THREAD_PRIORITY_URGENT_AUDIO (-19)
  • THREAD_PRIORITY_URGENT_DISPLAY (-8)

You can also use the Process.THREAD_PRIORITY_LESS_FAVORABLE (+1) and Process.THREAD_PRIORITY_MORE_FAVORABLE as increments (-1). For example to set a thread's priority to a slightly higher priority than default, you could set the priority to (THREAD_PRIORITY_DEFAULT + THREAD_PRIORITY_MORE_FAVORABLE).

TIP: Use THREAD_PRIORITY_LESS_FAVORABLE and THREAD_PRIORITY_MORE_FAVORABLE instead of +1 and -1 so you won't have to remember whether a higher number means lower of higher priority. Also, avoid mixing calls to Thread.setPriority and Process.setThreadPriority as this could make your code confusing. Note that Linux priorities go from -20 (highest) to 19 (lowest) whereas Thread priorities go from 1 (lowest) to 10 (highest).

Be very careful when you decide to change the priority of your threads. Increasing the priority of one thread may result in a faster execution of this particular thread but may negatively impact the other threads, which may not get access to the CPU resource as quickly as they should, therefore disrupting the user experience as a whole. Consider implementing a priority aging algorithm if it makes sense for your application.

Even though creating a thread to perform a background task is trivial in Android, as demonstrated in Listing 5–1, updating the user interface can be quite tedious: it requires posting the result back to the main thread because calling any View method must be done from the UI thread.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.221.182.150