Search icon
Arrow left icon
All Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Newsletters
Free Learning
Arrow right icon
Android Studio 4.2 Development Essentials - Java Edition

You're reading from  Android Studio 4.2 Development Essentials - Java Edition

Product type Book
Published in Aug 2021
Publisher Packt
ISBN-13 9781803238814
Pages 782 pages
Edition 1st Edition
Languages
Author (1):
Neil Smyth Neil Smyth
Profile icon Neil Smyth

Table of Contents (87) Chapters

1. Introduction 2. Setting up an Android Studio Development Environment 3. Creating an Example Android App in Android Studio 4. Creating an Android Virtual Device (AVD) in Android Studio 5. Using and Configuring the Android Studio AVD Emulator 6. A Tour of the Android Studio User Interface 7. Testing Android Studio Apps on a Physical Android Device 8. The Basics of the Android Studio Code Editor 9. An Overview of the Android Architecture 10. The Anatomy of an Android Application 11. An Overview of Android View Binding 12. Understanding Android Application and Activity Lifecycles 13. Handling Android Activity State Changes 14. Android Activity State Changes by Example 15. Saving and Restoring the State of an Android Activity 16. Understanding Android Views, View Groups and Layouts 17. A Guide to the Android Studio Layout Editor Tool 18. A Guide to the Android ConstraintLayout 19. A Guide to Using ConstraintLayout in Android Studio 20. Working with ConstraintLayout Chains and Ratios in Android Studio 21. An Android Studio Layout Editor ConstraintLayout Tutorial 22. Manual XML Layout Design in Android Studio 23. Managing Constraints using Constraint Sets 24. An Android ConstraintSet Tutorial 25. A Guide to using Apply Changes in Android Studio 26. An Overview and Example of Android Event Handling 27. Android Touch and Multi-touch Event Handling 28. Detecting Common Gestures Using the Android Gesture Detector Class 29. Implementing Custom Gesture and Pinch Recognition on Android 30. An Introduction to Android Fragments 31. Using Fragments in Android Studio - An Example 32. Modern Android App Architecture with Jetpack 33. An Android Jetpack ViewModel Tutorial 34. An Android Jetpack LiveData Tutorial 35. An Overview of Android Jetpack Data Binding 36. An Android Jetpack Data Binding Tutorial 37. An Android ViewModel Saved State Tutorial 38. Working with Android Lifecycle-Aware Components 39. An Android Jetpack Lifecycle Awareness Tutorial 40. An Overview of the Navigation Architecture Component 41. An Android Jetpack Navigation Component Tutorial 42. An Introduction to MotionLayout 43. An Android MotionLayout Editor Tutorial 44. A MotionLayout KeyCycle Tutorial 45. Working with the Floating Action Button and Snackbar 46. Creating a Tabbed Interface using the TabLayout Component 47. Working with the RecyclerView and CardView Widgets 48. An Android RecyclerView and CardView Tutorial 49. A Layout Editor Sample Data Tutorial 50. Working with the AppBar and Collapsing Toolbar Layouts 51. An Android Studio Primary/Detail Flow Tutorial 52. An Overview of Android Intents 53. Android Explicit Intents – A Worked Example 54. Android Implicit Intents – A Worked Example 55. Android Broadcast Intents and Broadcast Receivers 56. A Basic Overview of Java Threads, Handlers and Executors 57. An Overview of Android Services 58. Implementing an Android Started Service – A Worked Example 59. Android Local Bound Services – A Worked Example 60. Android Remote Bound Services – A Worked Example 61. An Android Notifications Tutorial 62. An Android Direct Reply Notification Tutorial 63. Foldable Devices and Multi-Window Support 64. An Overview of Android SQLite Databases 65. The Android Room Persistence Library 66. An Android TableLayout and TableRow Tutorial 67. An Android Room Database and Repository Tutorial 68. Accessing Cloud Storage using the Android Storage Access Framework 69. An Android Storage Access Framework Example 70. Video Playback on Android using the VideoView and MediaController Classes 71. Android Picture-in-Picture Mode 72. An Android Picture-in-Picture Tutorial 73. Making Runtime Permission Requests in Android 74. Android Audio Recording and Playback using MediaPlayer and MediaRecorder 75. Working with the Google Maps Android API in Android Studio 76. Printing with the Android Printing Framework 77. An Android HTML and Web Content Printing Example 78. A Guide to Android Custom Document Printing 79. An Introduction to Android App Links 80. An Android Studio App Links Tutorial 81. A Guide to the Android Studio Profiler 82. An Android Biometric Authentication Tutorial 83. Creating, Testing and Uploading an Android App Bundle 84. An Overview of Android Dynamic Feature Modules 85. An Android Studio Dynamic Feature Tutorial 86. An Overview of Gradle in Android Studio Index

56. A Basic Overview of Java Threads, Handlers and Executors

The next chapter will be the first in a series of chapters intended to introduce the use of Android Services to perform application tasks in the background. It is impossible, however, to understand the steps involved in implementing services without first gaining a basic understanding of the concept of threading in Android applications. Threads, thread handlers and execution services are, therefore, the topic of this chapter.

56.1 An Overview of Threads

Threads are the cornerstone of any multitasking operating system and can be thought of as mini-processes running within a main process, the purpose of which is to enable at least the appearance of parallel execution paths within applications.

56.2 The Application Main Thread

When an Android application is first started, the runtime system creates a single thread in which all application components will run by default. This thread is generally referred to as the main thread. The primary role of the main thread is to handle the user interface in terms of event handling and interaction with views in the user interface. Any additional components that are started within the application will, by default, also run on the main thread.

Any component within an application that performs a time consuming task using the main thread will cause the entire application to appear to lock up until the task is completed. This will typically result in the operating system displaying an “Application is not responding” warning to the user. Clearly, this is far from the desired behavior for any application. This can be avoided simply by launching the task to be performed in a separate thread, allowing the main thread to continue...

56.3 Thread Handlers

Clearly, one of the key rules of Android development is to never perform time-consuming operations on the main thread of an application. The second, equally important, rule is that the code within a separate thread must never, under any circumstances, directly update any aspect of the user interface.

Any changes to the user interface must always be performed from within the main thread. The reason for this is that the Android UI toolkit is not thread-safe. Attempts to work with non-thread-safe code from within multiple threads will typically result in intermittent problems and unpredictable application behavior.

In the event that the code executing in a thread needs to interact with the user interface, it must do so by synchronizing with the main UI thread. This is achieved by creating a handler within the main thread, which, in turn, receives messages from another thread and updates the user interface accordingly.

56.4 A Threading Example

The remainder of this chapter will work through some simple examples intended to provide a basic introduction to threads. The first step will be to highlight the importance of performing time-consuming tasks in a separate thread from the main thread.

Launch Android Studio, select the Create New Project quick start option from the Android Studio welcome screen and, within the resulting new project dialog, choose the Empty Activity template before clicking on the Next button.

Enter ThreadExample into the Name field and specify com.ebookfrenzy.threadexample as the package name. Before clicking on the Finish button, change the Minimum API level setting to API 26: Android 8.0 (Oreo) and the Language menu to Java. Convert the project to use view binding by following the steps in section 11.8 Migrating a Project to View Binding.

56.5 Building the App

Load the activity_main.xml file for the project into the Layout Editor tool. Select the default TextView component and change the ID for the view to myTextView in the Properties tool window.

Add a Button view to the user interface positioned directly beneath the existing TextView object as illustrated in Figure 56-1. Once the button has been added, click on the Infer Constraints button in the toolbar to add the missing constraints.

Change the text to “Press Me” and extract the string to a resource named press_me. With the button view still selected in the layout, locate the onClick property and enter buttonClick as the method name.

Figure 56-1

Next, load the MainActivity.java file into an editing panel and add code for the buttonClick() method which will be called when the Button view is tapped by the user. Since the goal here is to demonstrate the problem of performing lengthy tasks on the main thread, the code will simply pause...

56.6 Creating a New Thread

In order to create a new thread, the code to be executed in that thread needs to be placed within the run() method of a Runnable instance. A new Thread object then needs to be created, passing through a reference to the Runnable instance to the constructor. Finally, the start() method of the thread object needs to be called to start the thread running. To perform the task within the buttonClick() method, therefore, the following changes need to be made:

public void buttonClick(View view) {

 

    Runnable runnable = new Runnable() {

        public void run() {

            long endTime = System.currentTimeMillis() + 20 * 1000;

            while (System.currentTimeMillis() < endTime) {

           &...

56.7 Implementing a Thread Handler

Thread handlers are implemented in the main thread of an application and are primarily used to make updates to the user interface in response to messages sent by other threads running within the application’s process.

Handlers are subclassed from the Android Handler class and can be used either by specifying a Runnable to be executed when required by the thread, or by overriding the handleMessage() callback method within the Handler subclass which will be called when messages are sent to the handler by a thread.

For the purposes of this example, a handler will be implemented to update the user interface from within the previously created thread. Load the MainActivity.java file into the Android Studio editor and modify the code to add a Handler instance to the activity:

.

.

import android.os.Handler;

import android.os.Message;

import android.os.Looper;

public class MainActivity extends AppCompatActivity {

.

.

...

56.8 Passing a Message to the Handler

While the previous example triggered a call to the handleMessage() handler callback, it did not take advantage of the message object to send data to the handler. In this phase of the tutorial, the example will be further modified to pass data between the thread and the handler. First, the updated thread in the buttonClick() method will obtain the date and time from the system in string format and store that information in a Bundle object. A call will then be made to the obtainMessage() method of the handler object to get a message object from the message pool. Finally, the bundle will be added to the message object before being sent via a call to the sendMessage() method of the handler object:

public void buttonClick(View view) {

  Runnable runnable = () -> {

       long endTime = System.currentTimeMillis() + 20 * 1000;

       while (System.currentTimeMillis...

56.9 Java Executor Concurrency

So far in this chapter we have looked exclusively at directly creating and managing Java threads. While acceptable for simple multi-threading tasks, this can prove to be inadequate when working with complex situations involving large number of threads. There is, for example, a system overhead involved in starting and stopping threads. An app that creates and destroys large number of threads is, therefore, at risk of exhibiting degraded performance. The basic threading API also does not provide pre-built options for scheduling or repeating task execution, or for returning results from a task.

The shortcomings of working directly with threads can be overcome by making use of the Executor classes of the Java Concurrent framework (part of the java.util.concurrent package). This framework allows for a pool of active threads to be created and manages how tasks are assigned to those threads. This allows existing threads to be reused for other tasks without...

56.10 Working with Runnable Tasks

The first step in exploring this framework is to modify the buttonClicked() method to use a concurrency framework Executor to run the task in a separate thread:

.

.

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

.

.

    public void buttonClick(View view) {

        ExecutorService executor = Executors.newSingleThreadExecutor();

        executor.submit(new Runnable(){

            public void run(){

                long endTime = System.currentTimeMillis() + 10 * 1000;

                while (System.currentTimeMillis() < endTime) {

     ...

56.11 Shutting down an Executor Service

ExecutorService provides a few techniques for initiating a shutdown. To notify the service that it should shutdown automatically after the currently running tasks have reached completion, a call to the shutdown() method should be made as follows:

executor.shutdown();

A call to the shutdownNow() method, on the other hand, stops all tasks running on the service and, cancels the processing of pending tasks:

executor.shutdownNow();

56.12 Working with Callable Tasks and Futures

As previously mentioned, the ExecutorService supports so called “Callable” tasks which are able to return a result after the task is completed. Tasks running on separate thread are typically expected to take some time to complete (otherwise they probably would not need to run on a separate thread in the first place). This raises the question of how the result is returned to the code in the thread from which the task was launched. This is achieved using the Future value type which represents a value which will be provided at some point in the future.

When a callable task is executed it returns a Future instance which may then be used by the app to obtain the result when the task completes. To see this in action, begin by editing the activity_main.xml file to add an additional button labeled “Status” with the onClick property configured to call method named statusClick:

Figure 56-3

Next, modify the...

56.13 Handling a Future Result

The buttonClick() method is now configured to launch a Callable task with the return value assigned to the Future variable. The app now needs to know when the task is complete and the result available. One option is to call the get() method of the Future variable. Since this method is able to throw exceptions in the event that the execution fails or is interrupted, this must be performed in a try/catch statement as follows:

String result = null;

try {

    result = future.get();

} catch (ExecutionException | InterruptedException e) {

    e.printStackTrace();

}

Unfortunately, the get() method will block the current thread until the task running in the thread completes, thereby defeating the purpose of running the task in a separate thread in the first place. Another option is to provide the get() method call with a timeout after which it will return control to the current thread. The following...

56.14 Scheduling Tasks

The final area to be covered involves the use of ExecutorService to schedule task execution. This involves use of a ScheduledExecutorService instance on which the schedule() method needs to be called passing through the Runnable task to be executed together with a time delay. The schedule() call will return a ScheduledFuture instance which may be used to identify the remaining time before the task is due to start.

The following code, for example, schedules a task to run after a 30 second delay and accesses the remaining delay time:

ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);

Runnable task = () -> {

// Code to perform task here

};

ScheduledFuture<?> future = executor.schedule(task, 30, TimeUnit.SECONDS);

long delayRemaining = future.getDelay(TimeUnit.SECONDS);

Similarly, the ScheduledExecutorService may be used to execute a task repeatedly at regular intervals starting after an optional initial delay...

56.15 Summary

The goal of this chapter was to provide an overview of threading within Android applications. When an application is first launched in a process, the runtime system creates a main thread in which all subsequently launched application components run by default. The primary role of the main thread is to handle the user interface, so any time consuming tasks performed in that thread will give the appearance that the application has locked up. It is essential, therefore, that tasks likely to take time to complete be started in a separate thread.

Because the Android user interface toolkit is not thread-safe, changes to the user interface should not be made in any thread other than the main thread. User interface changes can be implemented by creating a handler in the main thread to which messages may be sent from within other, non-main threads.

Threads can be created either directly, or using the executor services of the Java Concurrent framework. For more complex threading...

lock icon The rest of the chapter is locked
You have been reading a chapter from
Android Studio 4.2 Development Essentials - Java Edition
Published in: Aug 2021 Publisher: Packt ISBN-13: 9781803238814
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at £13.99/month. Cancel anytime}