1. Android Process
Before learning about the android thread, you must first understand the android process. When a program is started for the first time, Android starts a Linux Process and a main thread. By default, all components of the program will run in the process and thread.
In addition, Android assigns a Linux User to each application. Android will try to keep a running process. When the memory resources are insufficient, Android will try to stop some processes and release enough resources for other new processes to use, it can also ensure that the current process being accessed by the user has enough resources to respond to the user's events in a timely manner. Android judges the importance of a process based on the component category and component Status in the process. Android first stops unimportant processes. There are five levels of importance from high to low:
Foreground Process
The foreground process is the process currently in use by the user. Only some foreground processes can exist at any time. They are the last one ended, when the memory is low to the root of them can not run. In general, in this case, the device will perform memory scheduling and stop some foreground processes to maintain a response to user interaction.
Visible Process
The visible process does not contain foreground components, but displays a visible process on the screen. It is very important, unless the foreground process needs to obtain its resources, it will not be aborted.
Service Process
A service started using the startservice () method is running. This service is not of the two higher importance mentioned above. Although the process where the service is located is not directly visible to users, they execute tasks that users are very concerned about (such as playing MP3 and downloading data from the network ). As long as the foreground and visible processes have enough memory, the system will not recycle them.
Background Process
An activity that is invisible to users is running (the onstop () method has been called ). these processes have no direct impact on the user experience. They can be recycled when the service process, visible process, and frontend process require memory. Generally, many invisible processes are running in the system. They are stored in the LRU (least recently used) list so that they can be recycled immediately when the memory is insufficient. If an activity executes its lifecycle, closing the process has no significant impact on user experience.
Empty Process
No program components are running. The only reason for running these processes is to use them as a cache to shorten the restart time required by the next program. The system often terminates these processes, which can regulate the balance between the program cache and the system cache.
When Android rates the importance of processes, it selects the highest level. In addition, when another process is dependent, the level of a process may increase. A process serving other processes is never more important than the process being served. Because the service process is more important than the background activity process, it is best to start a service for a time-consuming activity to do this work, instead of starting a sub-process, this operation takes longer time than the activity. For example, playing music in the background and uploading images captured by cameras to the Internet. Using the service, processes can obtain at least the important level of the service process, you do not need to consider the current status of the activity. Broadcast receivers should also enable a service rather than opening a thread when it is time-consuming.
2. Single-threaded Model
When a program is started for the first time, Android starts a corresponding main thread at the same time. The main thread is mainly responsible for processing UI-related events, such as user key events, the user contacts screen events and Screen Drawing events, and distributes related events to corresponding components for processing. SoThe main thread is often called a UI thread.. When developing Android applications, you must follow the single-thread model principle: Android UI operations are not thread-safe and must be executed in the UI thread.
2.1 The Sub-thread updates the UI
The android UI is single-threaded. To avoid dragging the GUI, some time-consuming objects should be handed over to independent threads for execution. If the background thread executes the UI object, Android will send an error message.
Calledfromwrongthreadexception. When such an exception is thrown in the future, you must know what is going on!
2.2 Message Queue
In the single-thread model, Android designs a message queue to solve similar problems. The message queue can be used between threads to exchange information with handler and logoff components. They are described as follows:
1. Message
Message message, which is understood as information exchanged between threads. When the background thread for data processing needs to update the UI, the message contains some data to the UI thread.
2. Handler
Handler is the main handler of the message, responsible for sending the message and executing the message content. The background thread uses the passed handler object reference to sendmessage ). When handler is used, handlemessage (Message) of implement class is required)
Method, such as update UI. It is usually necessary to subclass handler to implement the handlemessage method.
3. Message Queue
Message Queue is a message queue used to store messages published by handler and run first-in-first-out.
Each message queue has a corresponding handler. Handler sends a message to the message queue in two ways: sendmessage or post. Both messages are inserted at the end of the message queue and executed first-in-first-out. However, messages sent using the two methods are executed in a slightly different way: a message object is sent using sendmessage, which will be processed by the handlemessage () function of handler; the post method sends a runnable object, which is executed by itself.
4. Logoff
Logoff is the manager of the message queue in each line. Android does not have a global message queue, while Android automatically creates a message queue for the main thread (ui thread), but no message queue is created in the Child thread. Therefore, the logoff value of the main thread obtained by calling logoff. getmainlogoff () is not null, but the logoff value of the current thread may be null by calling logoff. mylogoff.
The API Doc provides the correct method for using logoff for sub-threads:
The general process of this message mechanism:
1. After the logoff. Loop () method starts running, the non-null message in the message queue is retrieved cyclically in the receiving order.
2. At the beginning, all messages in the message queue are null. When handler. sendmessage (Message) is sent to message queue, this function sets the target attribute of the message object to the current handler object. Then logoff retrieves the message, and calls the dispatchmessage function of the hander to which the target of the message points to process the message.
In the dispatchmessage method, the user determines how to process the message. The priority ranges from high to low:
1) callback in the message, an object that implements the runnable interface, where the run function is used for processing;
2) The mcallback in handler points to an object that implements the callback interface, which is processed by the handlemessage;
3) the classes corresponding to the handler object for processing messages inherit and implement the handlemessage function. The handlemessage function is used to process messages.
We can see that the handlemessage method we implemented has the lowest priority!
3. After handler processes the message (update UI), logoff sets the message to NULL for recycling!
There are many articles on the Internet about how the main thread interacts with other sub-threads, how information is transmitted, and who finally processes information, my personal understanding is the simplest method-this thread is used to determine which thread the logoff object in the handler object belongs!
1. When the constructor parameter of the handler object is null, It is the Logoff of the current thread;
2. logoff. getmainlogoff () obtains the logoff object of the main thread, and logoff. mylogoff () obtains the logoff object of the current thread.
Let's take an example to simulate the process of retrieving data from the network and loading data to listview:
In this example, I thought it was a bit messy after writing it. I had to sort it out to understand the process of interaction between threads and the changes before and after data. Then I learned about the asynctask class. After modification, I can easily understand it!
2.3 asynctask
Asynctask:
(Button) findviewbyid (R. id. load_asynctask )). setonclicklistener (new view. onclicklistener () {@ override public void onclick (view) {DATA = NULL; Data = new arraylist (); adapter = NULL; // display progressdialog to asynctask. onpreexecute () // showdialog (progress_dialog); New progresstask(.exe cute (data) ;}}); private class progresstask extends asynctask, void, integer> {/* This method will be called by the UI thread before the actual background operation is executed. You can make some preparations in this method, such as displaying a progress bar on the interface. * // @ Override protected void onpreexecute () {// progressdialog showdialog (progress_dialog);}/* executes time-consuming background computing tasks. You can call publishprogress to update the real-time task progress. * // @ Override protected integer doinbackground (arraylist... datas) {arraylist DATA = datas [0]; for (INT I = 0; I <8; I ++) {data. add ("listitem");} return state_finish;}/* after doinbackground is executed, the onpostexecute method will be called by the UI thread, * The background computing result is passed to the UI thread through this method. * // @ override protected void onpostexecute (integer result) {int state = result. intvalue (); Switch (state) {Case state_finish: dismissdialog (Progress _ DIALOG); toast. maketext (getapplicationcontext (), "Loading completed! ", Toast. length_long ). show (); adapter = new arrayadapter (getapplicationcontext (), android. r. layout. simple_list_item_1, data); setlistadapter (adapter); break; Case state_error: dismissdialog (progress_dialog); toast. maketext (getapplicationcontext (), "An error occurred during the processing! ", Toast. length_long ). show (); adapter = new arrayadapter (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 the UI thread very simple. It makes it easier to create long-running tasks that need to interact with the user interface, without the need to use threads and handler.
1) subclass asynctask
2) implement one or more of the following methods defined in asynctask
Onpreexecute () preparation before execution;
Doinbackground (Params...) starts to execute background processing. You can call the publishprogress method to update the real-time task progress;
Onprogressupdate (Progress...) after the publishprogress method is called, the UI thread calls this method to display the progress of the task on the interface, for example, through a progress bar.
Onpostexecute (result) after the operation is completed, the result is sent to the UI thread.
None of the four methods can be called manually. Besides the doinbackground (Params...) method, the other three methods are called by the UI thread. Therefore, the following requirements are required:
1) The asynctask instance must be created in the UI thread;
2) The asynctask.exe cute method must be called in the UI thread;
Note: This task can only be executed once. Otherwise, exceptions may occur during multiple calls. In addition, you cannot manually stop it. Pay attention to this to see if it meets your needs!
During usage, we found that the parameter settings of the asynctask constructor should be clear:Asynctask
Params corresponds to the doinbackground (Params...) parameter type. New asynctask(cmd.exe cute (Params... params), that is, the incoming Params data. You can execute (data) to transmit one data, or execute (data1, data2, data3) data.
Progress corresponds to the parameter type of onprogressupdate (Progress;
Result corresponds to the parameter type of onpostexecute (result.
If none of the preceding parameter types need to be specified, use void. Note that it is not void. For more information, see the example above or the example in the API Doc.
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 onclick (view) {DATA = NULL; Data = new arraylist (); adapter = NULL; showdialog (progress_dialog); New progressthread (handler, data ). start () ;}}) ;}@ override protected dited oncreatedialog (int id) {Switch (ID) {Case progress_dialog: Return progressdialog. show (this, "", "loading. please wait... ", true); default: return NULL;} private class progressthread extends thread {private handler; private arraylist data; Public progressthread (handler, arraylist data) {This. handle R = handler; this. data = data ;}@ override public void run () {for (INT I = 0; I <8; I ++) {data. add ("listitem"); // try {thread for background data processing. 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) ;}// you do not even need to set logoff here, because handler uses the logoff private final handler of the current thread by default. getmainlooper () {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 (), "Loading completed! ", Toast. length_long ). show (); adapter = new arrayadapter (getapplicationcontext (), android. r. layout. simple_list_item_1, data); setlistadapter (adapter); break; Case state_error: dismissdialog (progress_dialog); toast. maketext (getapplicationcontext (), "An error occurred during the processing! ", Toast. length_long ). show (); adapter = new arrayadapter (getapplicationcontext (), android. r. layout. simple_list_item_1, data); setlistadapter (adapter); break; default :}}; private arrayadapter adapter; private arraylist data; Private Static final int progress_dialog = 1; private Static final int state_finish = 1; Private Static final int state_error =-1 ;}
View the code class looperthread extends thread {public handler mhandler; Public void run () {loler. prepare (); // create the Logoff of this thread and create a messagequeue mhandler = new handler () {public void handlemessage (Message MSG) {// process incoming messages here }}; logoff. loop (); // start logoff and listen to message queue }}