0 Bewertungen0% fanden dieses Dokument nützlich (0 Abstimmungen)
7 Ansichten7 Seiten
Android devices increasingly contain multiple computing cores. This means that multiple programs, or execution threads, can be running on your device all at the same time. In this lesson, we're going to talk about writing multi-threaded programs for Android. And we'll also discuss some of the classes that Android provides to support this.
Android devices increasingly contain multiple computing cores. This means that multiple programs, or execution threads, can be running on your device all at the same time. In this lesson, we're going to talk about writing multi-threaded programs for Android. And we'll also discuss some of the classes that Android provides to support this.
Android devices increasingly contain multiple computing cores. This means that multiple programs, or execution threads, can be running on your device all at the same time. In this lesson, we're going to talk about writing multi-threaded programs for Android. And we'll also discuss some of the classes that Android provides to support this.
Android Handheld Systems. Handheld systems, like all computing devices today, increasingly contain multiple computing cores. And one thing this means is that multiple programs, or execution threads, can be running on your device all at the same time. And that's a powerful thing, because it lets you do more work in a shorter amount of time. But it can also make your programs much more complex, leading to errors and performance problems if you're not careful. So in this lesson, we're going to talk about writing multi-threaded programs for Android. And we're also going to discuss some of the classes that Android provides to support this. In particular, in this lesson I'll start with a brief discussion of threading itself. Next, I'll talk about Android's user interface thread, the main thread in which Android applications perform most of their work. And I'll also discuss how this impacts the design of your application software. After that, I'll talk about the AsyncTask class, which helps to simplify threading in Android. And finally, I'll wrap up with a discussion of the handler class, another Android threading mechanism. So, I keep using the term thread, but what is a thread? Well, essentially, a thread is one of possibly many computations running at the same time within a operating system process. In terms of implementation, each thread has its own program counter and run time stack, but shares the heap and static memory areas with other threads running within an operating system process. Now this graphic depicts these concepts, and here I'm showing a hypothetical computing device. Now, this device has two CPUs. CPU 1. And CPU two. Each of these CPUs can carry out the instructions that make up the applications running on your device. Now, on CPU two, I'm showing two processes running, p3 and p4. Now, one way to think about processes is that they're self contained execution environments. They have resources such as memory, open files, network connections, and other things that they manage and keep separate from other processes on your device. And within one of these processes, P4, I'm showing two running threads, T7 and T8. Now each of these threads is a sequentially executing stream of instructions with its own call stack. But since they're within the same process, they can each access shared process resources, including heap memory and static variables. In Java, threads are represented by an object of type thread in the Java.Lang package. Java threads implement the runnable interface, which means that they must have a public method, called a run, that takes no arguments, and that has no return value. Now, for this course, I'm assuming that you've already learned about Java threads, and that you know how to use them. However, if you need a refresher please take a look at the concurrency tutorial at the following URL. [BLANK_AUDIO] Now some of the thread methods that we'll see in this lesson include the start method for starting a thread, and the sleep method for temporarily suspending a thread. Some object methods that you may need when you're using, when you're using threads include the wait method, which allows the current thread to give up a lock that it holds and to wait until another thread invokes a corresponding method such as notify or notify all. And when this happens, the waiting thread can reacquire the lock that it gave up when it called wait, and can continue executing. The notify method wakes up a single thread that is waiting on this object. Now to use a thread, you normally do the following things. First, you create the thread. For example, by using the new thread command. Now, threads don't automatically start when you create them. To start the thread, you need to invoke the thread's start method. Doing this eventually leads to the thread's run method being called, and the thread continues executing until that run method terminates. This graphic helps to show this behavior. First, a running application issues a new command to create a new thread object. When this call finishes, the application continues. And some time later, invokes the thread's start method. And this call returns back to the application, but also causes the code in the thread's run method to run as well. And as the program continues, there are now two threads executing. And of course, you can do this multiple times, creating and executing as many threads as you want. So, lets look at an application in which threading would be helpful. The first application that we'll discuss in this lesson is called Threading No Threading. And as you'll see in a second, the application displays a simple user interface with two buttons. The first button is labeled LoadIcon. When the user clicks on this button, the application opens and reads a file containing a bitmap. And once that's done, it shows the just loaded bitmap on the display. The idea here is that this operation takes a noticeable amount of time. Now, in the code I use throughout this lesson, I'm actually going to exaggerate how long this takes, okay? But don't let that distract you, the point is still the same. Some operations take a relatively long amount of time. And you, as a developer, have to understand and deal with that. The second button is labeled OtherButton, when the user clicks on this button a toast message pops up displaying some text. And the idea here is that if you see the text, then you know that the button's working. Now, if you can't click the button, or you don't see the text, then something's wrong. In particular, the user should be able to click either of the buttons, at any time, and the system should just work. So, let's run a version of this application that does not use any threading. Now what do you think is going to happen? Will I be able to press both buttons whenever I want? Let's see. Here, I'll start up the ThreadingNoThreading application. As you can see, there are, there are the two buttons that we talked about. I'll first press the Other Button, and as you can see, I can click on it and the promised message appears on the display. Now I'm going to do two things. I will first press the Load Icon button, which will start the time consuming operation of reading in the bitmap from a file and then displaying it. And right after I press the Load Icon button, I'm going to press the Other Button again. Here we go. Now, I'll press the Load Icon button, and now I'll press the other button. Okay. So, so what's going on here? The Other Button seems to be stuck. Why is that? Well, the answer is that when I was trying to press the Other Button, Android was still loading the icon for back when I pressed the Load Icon button. And that first operation was preventing the second operation from taking place. Okay, so one seemingly obvious, but ultimately incorrect solution to this problem, would be to go to the listener that's attached to the Load Icon button and simply create a new thread that loads the bitmap and then displays it. So I've implemented that approach in an application called Threadingsimple. Lets take a look at that application and talk about why it doesn't actually work. [BLANK_AUDIO] So, here's the code for the Threadingsimple application. Here's the button listener for the Load Icon button. It calls the LoadIcon method, which is listed just below. This code creates a new thread, which takes awhile loading the bitmap and then tries to set the bitmap on an image view that's part of the layout. So let's run this code. Now, I'll start-up the application. And now I'll press the Load Icon button. And now, I'll press the Other Button. Well first off, I pressed the Other Button and saw that it responded. So loading the icon doesn't appear to block pressing the Other Button. So that's good, we've made some progress. However, you can see that we've got a bigger problem now. We've crashed the application. If we investigate the log cat output, we see that there's a message telling us that only the original thread that created a view hierarchy can touch its views. So, Android simply won't allow threads to start messing around with views that were created by other threads. So that means while the new thread that we created to load the bitmap can do that work, it can't actually take the last step and add the resulting bitmap to the display. So which thread actually created this application's view hierarchy? Well, all Android applications have a main thread, which is also called the UI thread. Application components that run in the same process, which they all do by default, use the same UI thread. In all those life cycle methods that we've been talking about, OnCreate, OnStart, etc, they're all handled in the UI thread. And in addition, the UI toolkit itself is not thread safe. And what all this means is that if you block the UI thread with some long running operation, then you're going to prevent your application from responding to other things that the user is doing. In fact, we saw that in the ThreadingNoThreading application. So, long-running operations need to be put in background threads. At the same time however, we can't access the UI toolkit from a non-UI thread. And that's what got us into trouble with the ThreadingSimple application. [BLANK_AUDIO] So, we need to do work in a background thread, but when that work is done we need to do the UI updates, back in the UI thread. And Android, in fact, gives us a bunch of ways to do just that. In particular, Android provides several methods that are guaranteed to run on the UI thread. Two of those methods are the view class's post method, and the activity class's runOnUiThread. Both of these methods take a runnable parameter. This runnable would, for example, contain the code that updates the display in our recent examples. So, if we're using these methods, we would load the bitmap in a background thread and when that operation completes, we would use one of these methods to execute a runnable that then sets the bitmap on the display. Let's see that in action. So, here's my device. And I'll start up the threading viewpost application. And there are the two buttons. And again, I'm going to do two things now. I'll press the Load Icon button. And then right after that, I'll press the Other Button. And I expect to see that the Other Button operation is not blocked by the Load Icon operation. And, I expect to see that the icon actually loads without crashing the application. So, here it goes. Now, I'll press the Load Icon button, and now I'll press the Other Button. There's the text from the Other Button, and finally, there's the bitmap. Let's take a look at the source code as well. So here's my application, open in the IDE. I'll open up the main activity for this application, and I'll go straight to the LoadIcon method, which gets called when the user presses the Load Icon button. As before, this code creates a new thread and then loads the bitmap. But after the bitmap loads, you see that we now have a call to view.post, passing in a runnable, whose code actually calls the setImageBitmap method to set the just loaded bitmap on that image view. [BLANK_AUDIO]