Explore the Android threading problem _android

Source: Internet
Author: User
Tags message queue thread class

What is a thread?

Thread or thread execution is essentially a sequence of commands (also program code), and then we send it to the operating system for execution.

Multithreaded_process

In general, our CPU can only handle one thread at any one time. Multi-core processors (most Android devices are already multi-core), as the name suggests, can handle multithreading at the same time (in layman's terms, many things can be handled simultaneously).

The essence of multi-core processing and single-core multi-task processing

The above I said is the general situation, not all the description is certainly correct. Because a single core can also use multitasking to simulate multiple threads.

Each task that runs in a thread can be broken down into multiple instructions, and these instructions need not be executed at the same time. So, a single core device can first switch to thread 1 to execute instruction 1 A, then switch to thread 2 to execute instruction 2 A, then return to thread 1 to perform 1B, 1 C, 1D, then continue to switch to Thread 2, execute 2B, 2C, and so on.

The switch between this thread is so fast that it can happen in a single core device. Almost all threads perform task processing at the same time. In fact, this is due to the illusion of too fast, like the movie "Matrix" in the same agent Brown, can change a lot of head and hands.

Next we'll look at some code.

Threads in the Java core

In Java, if you want to do parallel task processing, you will execute your code inside the runnable. You can inherit the thread class, or implement the Runnable interface:

Version 1 Public
class Iamathread extends Thread {public
  iamathread () {
    super ("Iamathread");
  }
 
  @Override public
  Void Run () {
     
//Your code (sequence of instructions)
  }
//To execute this sequence of instructions in a separate thread.
New Iamathread (). Start ();
 
Version 2 Public
class Iamarunnable implements Runnable {
  @Override public
  void Run () {
     
//your COD E (sequence of instructions)
  }
//To execute this sequence of instructions in a separate thread.
Iamarunnable myrunnable = new iamarunnable ();
New Thread (myrunnable). Start ();
 

The two methods are basically the same. The first version is to create a thread class, the second version is to create a Runnable object, and then you need a thread class to invoke it.

The second version is the commonly recommended method. This is also a big theme, beyond the scope of this article, will be discussed later.

The Threads on Android

Whenever you start the app, all components run on a separate line thread (default)-called the main thread. This thread is used primarily for handling UI operations and distributing events for view components and widgets, so the main thread is also called the UI thread.

If you run a time-consuming operation in the UI thread, the UI is locked until the time-consuming operation is over. For the user experience, this is very bad! That's why we have to understand the threading mechanism on Android. Understanding these mechanisms can move some complex work to other threads to execute. If you run a time-consuming task in the UI thread, there is a good chance that ANR will occur (the application is unresponsive) so that the user will quickly end your app.

Like Android and Java, it supports a step-by-step task with the thread class in Java. So it's easy to use the android thread like the Java example above, but that seems to be a little difficult.

Why is it difficult to use standard Java threads on Android?

In fact, parallel task processing is not as simple as it might seem, and you have to guarantee concurrency in multiple threads, as the great Tim Bray says: Ordinary humans can ' t do concurrency at scale (or really at all) ...

Specifically for Android, the following features are slightly bloated:

Asynchrony is a major pita for the UI thread (if you need to update the interface to the main thread in the background thread, you will use it). If the screen direction or screen configuration changes, there will be some more strange phenomenon. Because changing the orientation of the screen causes the activity to be rebuilt (so the background thread needs to change the state of the destroyed activity, and if the background threads are not on the UI thread, the situation is more complicated, for example, condition 1). For a thread pool, there is no default processing method. Canceling a thread operation requires a custom code implementation.
So how do you do concurrent processing on Android?

You may have heard some of the most common terms on Android:

1, Handler

This is the detailed topic that we are going to discuss today.

2, Asynctask

Using Asynctask is the easiest way to manipulate threads on Android and is the easiest way to make mistakes.

3, Intentservice

This is a way to write more code, but it's a great way to move a time-consuming task back to the background and my favorite way to do it. With a framework for using a eventbus mechanism such as Otto, it is very easy to implement Intentservice.

4, Loader

There is much more to be done about dealing with asynchronous tasks, such as processing data from a database or a content provider.

5. Service

If you have ever used a service, you should know there is a misunderstanding here, and one common misconception is that the service is running in the background thread. Not really! appear to be running in the background because they are not associated with UI components, but they (default) are running on the UI thread ... So the default runs on the UI thread, even if there is no UI part on it.

If you want to run a service in a background thread, you must customize a thread and then run the operation code in that line thread (similar to the method mentioned above). In fact you should use Intentservice implementations, but this is not the subject of this article.

The handler on Android

The following is an excerpt from the Android developer documentation for handlers:

> A Handler allows to send and process message and Runnable objects associated with A thread ' s MessageQueue. Each Handler instance are associated with a single thread and the thread ' s message queue.  When you create a new Handler, it are bound to the Thread/message queue of the thread this is creating It-from On, it would deliver messages and Runnables to, and execute them as they out of the "message queue."

To better understand this concept, maybe you need to see what message queues is.

Message Queuing

There is basically something called Message Queuing in a thread that is responsible for communication between threads. This is a design pattern in which all control instructions or content are passed between threads.

Message Queuing, like its name, is a command queue for threads. And we can do something cooler here:

Timed messages and threads do not execute at a point in time. You need to add a queue action in another thread, not on this thread.
Note: The concept of "message" and runnable object, instruction queue is the same here.

Back on Android Handler ... If you read it carefully, you can see that the document says:

> A Handler allows to send and process message and Runnable objects associated with A thread ' s MessageQueue.

So handler can let you send messages to the thread queue:

> Each Handler instance are associated with a single thread and this thread ' s message queue.

A handler object can only be associated with one thread:

> When you create a new Handler, it are bound to the Thread/message queue of the thread this is creating it

So what thread is a handler associated with? Is the thread that created it.

>-from, it'll deliver messages and Runnables to, and execute them as they of the message queue.

After we understand this knowledge, please continue to see ...

Tip: Here are a few things you might not know. Each line Cheng Tu is bound to a handler class instance and can be run with other threads to communicate with each other.

There is also a small suggestion (if used asynctask), Asynctask internal is also handled using handler, but is not running on the UI thread, it will provide a channel to communicate with the UI thread, using the PostExecute method can be implemented.

It's pretty cool, so how do you create a handler?

There are two ways of doing this:

Use the default construction method: New Handler (). The parameter is a Runnable object or a callback object, using a constructor method with a parameter.
Is there any useful API in handler?

Please remember:

Handler is simply sending messages to message queues (or using post) they have a more convenient way to help communicate with the UI thread.
If you look at the handler API now, you can see these methods clearly:

Post postdelayed Postattime
code example

The code here is very basic, but you can take a good look at the annotations.

Example 1: Using the handler "post" method

The public class Testactivity extends activity {//. Standard stuff @Override public void onCreate (Bundle saved  Instancestate) {///...//all standard stuff//we ' re creating a new handler here//And we ' re in the
 
   
UI thread (default)//So this Handler is associated with the UI thread Handler Mhandler = new Handler ();
   
I want to start doing something really long//which means I should run the fella in another thread. I do this by sending a message-in the form of another Runnable object//But-I ' m going to create a Runna  Ble object or a message for this Runnable mrunnableonseparatethread = new Runnable () {@Override public void run
 
       
() {//Do some long operation Longoperation (); After Mrunnableonseparatethread are done with it's job,//I need to tell the user that I'm done//whic H means I need to send a message back to the UI thread//Who do we know tHat ' s associated with the UI thread?
           
Mhandler.post (New Runnable () {@Override public void run () {//Do some UI related thing
      Like update a progress bar or TextView//...}
 
 
    });
 
   
}
  }; Cool but I ' ve not executed the mrunnableonseparatethread yet//I ' ve only defined the message to be sent//whe
 
  n I execute it though, I want it to being in a different thread//that is the whole point.
New Thread (Mrunnableonseparatethread). Start ();
 }
 
}

If there is no handler object at all, the callback post method can be tricky.

Example 2: Using the Postdelayed method

Recently this site introduced a new feature, every time I have to simulate the automatic completion of the EditText function, each text changes will trigger an API call, retrieve data from the server.

I wanted to reduce the number of app call APIs, so I decided to use the handler postdelayed method to implement this feature.

This example is not for parallel processing, only about handler sending messages to message queues and arranging messages to be executed at some point in the future.

//The below code is inside a Textwatcher//which implements the OnTextChanged method/
 
/I ' ve simplified it to only highlight the parts we ' RE//interested in private long Lastchange = 0; @Override public void ontextchanged (final charsequence chars, int start, int before, int count) {//  The handler is spawned to the UI thread new handler (). postdelayed (//argument 1 for postdelated = message To is sent new Runnable () {@Override public void run () {if NOCHANGEINTEXT_INTHELASTF 
Ewseconds ()) {Searchandpopulatelistview (chars.tostring ());
 
    Logic}},//argument 2 for postdelated = delay before execution 300);
Lastchange = System.currenttimemillis ();
Private Boolean nochangeintext_inthelastfewseconds () {return System.currenttimemillis ()-Lastchange >= 300} 

Finally, I put the "Postattime" this method as a link to the reader, master handler it? If so, you can use the thread as much as you like.

1. Android Process

Before you know about Android threads, you need to understand the Android process first. When a program is first started, Android starts a Linux process and a main thread. By default, all of the program's components will run in that process and thread. At the same time, Android assigns a single Linux user to each application. Android will try to keep a running process, only when the memory resources are low, Android will try to stop some processes to free up enough resources for other new processes to use, but also to ensure that the current process that the user is accessing has sufficient resources to respond to the user's events in a timely manner. Android determines the importance of the process based on the class of components running in the process and the status of the components, and Android stops those unimportant processes first. In terms of importance, from highest to lowest, there are five levels:

Foreground process

The

Foreground process is the process that the user is currently using. Only a few foreground processes can exist at any time. They are the last to be ended when the memory is low to the point where they can't even run. In general, in this case, the device will perform a memory dispatch, aborting some foreground process to maintain the response to the user interaction. Visible processes
Visible processes do not contain foreground components but display a visible process on the screen is very important, unless the foreground process needs to obtain its resources, otherwise it will not be aborted. The service process
runs a service that starts with the StartService () method, which is not part of the 2 higher importance mentioned above. While the process of service is not directly visible to users, they perform tasks that are of great concern to users (such as playing MP3, downloading data from the network). As long as the foreground process and the visible process have enough memory, they are not reclaimed by the system. The background process
runs an activity that is not visible to the user (called the OnStop () method). These processes have no direct impact on the user experience and can be reclaimed when the service process, the visible process, and the foreground process require memory. Typically, there are many invisible processes running in the system, and they are stored in the LRU (least recently used) list so that they are recycled at the first time when there is not enough memory. If an activity executes its lifecycle correctly, shutting down the process has little impact on the user experience. The empty process
does not run any program components. The only reason to run these processes is to shorten the startup time that the next program needs to reuse as a cache. These processes are often aborted by the system, which adjusts the balance between the program cache and the system cache.
When Android ratings the importance of the process, choose its highest level. In addition, the level of a process may increase when it is dependent on another process. A process that serves another process will never be less important than the process that is being serviced. Because the service process is more important than the background activity process, a task that takes time to work is best to start a service to do the job, rather than to open a subprocess-especially if the operation takes longer than the duration of the activity. For example, playing music in the background, uploading images to the web, and using service can make the process at least a critical level of the service process level, regardless of the current state of the activity. Broadcast receivers do time-consuming work, you should also enable a service rather than open a thread.

2. Single-threaded model

When a program starts for the first time, Android also initiates a corresponding main thread (main thread), which is primarily responsible for handling UI-related events, such as user key events, user contact screen events, and screen drawing events, and distributing related events to the corresponding components for processing. So the main thread is often called the UI thread. The principle of a single-threaded model must be followed when developing Android applications: Android UI operations are not thread-safe and must be performed in the UI thread.

2.1 Child Threads Update UI

The Android UI is single-threaded (single-threaded). To avoid dragging the GUI, some of the more time-consuming objects should be handed over to a separate thread to execute. If the thread behind the scenes executes the UI object, Android emits an error message calledfromwrongthreadexception. When you encounter such an exception, you should know what's going on!

2.2 Message Queue

In order to solve a similar problem in a single-threaded model, Android designed a message queue that allows information to be exchanged between threads through the messaging queue and with handler and Looper components. They are described separately in the following sections:

1. Message
Message messages, understood as the information exchanged between threads, processing data background threads need to update the UI, then sending the "message" containing some data to the UI thread.

2. Handler

The handler processor is the main processor of message, responsible for the sending of messages and the execution of message content. A background thread is SendMessage (message) by a handler object reference that is passed in. Using handler, you need to implement the Handlemessage (message) method of the class, which is the action that handles these, such as the update UI. Subclass handler is usually required to implement the Handlemessage method.

3. Message Queue

Message queue, which is used to store messages posted via handler, in advance of first out execution.
Each message queue will have a corresponding handler. Handler sends messages to the message queue in two ways: SendMessage or post. Both messages are inserted at the end of the message queue and executed in advance. However, messages sent through these two methods are executed in a slightly different way: A Message object sent via SendMessage is handled by the handler Handlemessage () function, and a Runnable object is sent through the post method. will do it yourself.

4. Looper

Looper is the housekeeper of the message queue for each line Chengri. Android does not have the global message queue, and Android automatically creates a message queue for the main thread (UI thread), but Chengri does not establish a message queue on the Strand. Therefore, the looper of the main thread obtained by invoking Looper.getmainlooper () is not NULL, but it is possible to invoke Looper.mylooper () to get the looper of the current thread.
The correct way to use Looper,api doc is provided for child threads:

Class Looperthread extends Thread {public 
 Handler Mhandler; 
 
 public void Run () { 
  looper.prepare ()///create looper for this thread and create a messagequeue
 
  Mhandler = new Handler () { 
   public void Handlemessage (Message msg) { 
    //process incoming messages here 
   } 
  }; 
 
  Looper.loop (); Start running looper, listening for message Queue 
 } 
}

The approximate flow of this message mechanism:

1. After the start of the Looper.loop () method, loop out the Non-null message in the message queue in the order in which it was received.

2. The message in the first message queue is null. When Handler.sendmessage (message) to message Queue, this function sets the target property of that message object to be the current handler object. Then Looper takes out that message, and then calls the DispatchMessage function of the hander that the message's target points to to process it.

In the DispatchMessage method, how to handle the message is specified by the user, three judgements, and the priority is from high to Low:

1 message inside the callback, a implementation of the Runnable interface object, where the run function to do the processing work;

2) The Mcallback in the handler is directed to an object that implements the callback interface, which is processed by its handlemessage;

3 processing Message Handler the corresponding class inherits and implements the Handlemessage function, and processes the message through the Handlemessage function of this implementation.

This shows that our implementation of the Handlemessage method is the lowest priority!

3. When handler finishes processing the message (update UI), Looper sets it to NULL for recycling!

There are a lot of articles on the internet about how the main thread and other child threads interact, transmit information, and ultimately who performs the processing of information and so on, personal understanding is the simplest way--to determine which thread the Looper object in the handler object belongs to, then the thread to execute!
1. When the parameter of the constructor of the handler object is null, the looper of the current thread;
2.looper.getmainlooper () Gets the Looper object of the main thread, and Looper.mylooper () gets the Looper object of the current thread.
Now let's look at an example that simulates the process of getting data from a network and loading it into a ListView:

public class Listprogressdemo extends listactivity {@Override public void onCreate (Bundle savedinstancestate) { 
  Super.oncreate (savedinstancestate); 
 
  Setcontentview (r.layout.listprogress); (Button) Findviewbyid (R.id.load_handler). Setonclicklistener (New View.onclicklistener () {@Override public void O 
    Nclick (view view) {data = null; 
 
    data = new arraylist<string> (); 
 
    adapter = null; 
    ShowDialog (Progress_dialog); 
   New Progressthread (handler, data). Start (); 
 } 
  }); @Override protected Dialog oncreatedialog (int id) {switch (ID) {Case progress_dialog:return PROGRESSD Ialog.show (This, "", "Loading.) 
 
  Please wait ... ", true); 
  Default:return null; 
  } private class Progressthread extends Thread {private Handler Handler; 
 
  Private arraylist<string> data; 
   Public Progressthread (Handler Handler, arraylist<string> data) {This.handler = Handler; 
  This.data = data; } 
 
  @Override public void Run () {for (int i=0; i<8; i++) {data.add ("ListItem");//Background data processing try { 
    Thread.Sleep (100); 
     }catch (interruptedexception e) {Message msg = Handler.obtainmessage (); 
     Bundle B = new Bundle (); 
     B.putint ("state", state_error); 
     Msg.setdata (b); 
      
    Handler.sendmessage (msg); 
   } Message msg = Handler.obtainmessage (); 
   Bundle B = new Bundle (); 
   B.putint ("state", state_finish); 
   Msg.setdata (b); 
  Handler.sendmessage (msg); }//Here you may not even need to set looper, because Handler defaults to use the current thread's looper private final Handler Handler = new Handler (Looper.getmainlo Oper ()) {public void Handlemessage (message msg) {//Process message, update listview int state = Msg.getdata (). GetInt (' state ' 
   ); 
     Switch (state) {case State_finish:dismissdialog (progress_dialog); 
 
     Toast.maketext (Getapplicationcontext (), "Load complete!", Toast.length_long). Show (); adapter = new ArrayaDapter<string> (Getapplicationcontext (), Android. 
        
     R.layout.simple_list_item_1, data); 
 
     Setlistadapter (adapter); 
 
    Break 
     Case State_error:dismissdialog (Progress_dialog); 
 
     Toast.maketext (Getapplicationcontext (), "Process Error!", Toast.length_long). Show (); adapter = new Arrayadapter<string> (Getapplicationcontext (), Android. 
        
      R.layout.simple_list_item_1, data); 
 
      Setlistadapter (adapter); 
 
    Break 
 
 
 Default:}}; 
 Private arrayadapter<string> adapter; 
 
 Private arraylist<string> data; 
 private static final int progress_dialog = 1; 
 private static final int state_finish = 1; 
private static final int state_error =-1; 
 }

In this case, I feel a bit messy when I finish writing myself, and I want to do a bit of sorting to see how the process of interaction between threads and the data changes. Then understand the Asynctask class, the corresponding changes will be easy to understand!

2.3 Asynctask

Asynctask version:

(Button) Findviewbyid (r.id.load_asynctask). Setonclicklistener (New View.onclicklistener () {@Override public void on 
  Click (view view) {data = null; 
 
  data = new arraylist<string> (); 
 
  adapter = null; 
  Display ProgressDialog into Asynctask.onpreexecute ()//showdialog (Progress_dialog); 
 New Progresstask (). Execute (data); 
 
} 
}); Private class Progresstask extends Asynctask, Void, integer> {/* This method will be invoked by the UI thread before performing the actual background operation. You can do some preparation work in this method, such as displaying a progress bar on the interface. 
* * @Override protected void OnPreExecute () {//First display ProgressDialog ShowDialog (progress_dialog); /* * Perform those time-consuming background computations. You can call the Publishprogress method to update the real-time task progress. * * @Override protected Integer doinbackground (ARRAYLIST&LT;STRING&GT;. datas) {arraylist<string> data = Datas[0 
 ]; 
 for (int i=0; i<8; i++) {data.add ("ListItem"); 
return state_finish; 
 }/* The OnPostExecute method will be invoked by UI thread after Doinbackground execution, * The results of the background calculation will be passed to UI thread by this method. 
* * @Override protected void OnPostExecute (Integer result) { int state = Result.intvalue (); 
  Switch (state) {case State_finish:dismissdialog (progress_dialog); 
 
  Toast.maketext (Getapplicationcontext (), "Load complete!", Toast.length_long). Show (); adapter = new Arrayadapter<string> (Getapplicationcontext (), Android. 
     
  R.layout.simple_list_item_1, data); 
 
  Setlistadapter (adapter); 
   
 Break 
  Case State_error:dismissdialog (Progress_dialog);
 
  Toast.maketext (Getapplicationcontext (), "Process Error!", Toast.length_long). Show (); adapter = new Arrayadapter<string> (Getapplicationcontext (), Android.
 
   R.layout.simple_list_item_1, data);
 
   Setlistadapter (adapter);
 
 Break
 Default:}}

Android also provides a tool class: Asynctask. It makes the use of UI thread extremely simple. It makes it easier to create long-running tasks that need to interact with the user interface without the need for threading and handler.

1) Sub-class of Asynctask
2 Implement the following one or several methods defined in Asynctask
OnPreExecute () preparatory work before the commencement of implementation;
Doinbackground (Params ...) starts to perform background processing and can invoke the Publishprogress method to update the real-time task progress;
Onprogressupdate (Progress ...) after the Publishprogress method is invoked, UI thread calls this method to show the progress of the task in the interface, for example, through a progress bar.
OnPostExecute (Result) performs the completed operation and transmits the results to the UI thread.

None of these 4 methods can be invoked manually. And besides Doinbackground (Params ...) Method, the remaining 3 methods are invoked by the UI thread, so the requirement is:
1 The instance of Asynctask must be created in UI thread;
2) The Asynctask.execute method must be invoked in UI thread;

Also note that the task can only be executed once, otherwise the exception will occur when multiple calls are made. And can not manually stop, this point to pay attention to see if it meets your needs!

During use, it is found that the parameter settings of the Asynctask constructor need to be read clearly: Asynctask
Params corresponds to Doinbackground (Params ...) The parameter type. and the new Asynctask (). Execute (Params ... Params), which is the Params data that comes in, you can execute (data) to transmit one, or execute (data1, data2, data3) Such multiple data.
Progress corresponds to Onprogressupdate (Progress ...) The parameter type of the
result corresponds to the parameter type of OnPostExecute (result).
When none of the above parameter types need to be specified, void is used and note is not void. Do not understand can refer to the above example, or API doc inside the example.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.