The program requires user operations, which must be within 200 ms (0.2 s). If no response is received within 5 seconds, activitymanager will kill the activity without prompting. However, the activity may really take time to process, which usually uses the background thread-Background thread. The background thread canSecurityInteracts with the UI thread, where the background thread cannot modify the UI. I don't know exactly how much I can't modify the UI. For example, in the following example, modifying the progress bar status is allowed. In a complicated example, problems may occur, for example, if both background threads need to process the same widget, unexpected situations may occur. However, in programming, it is really not necessary to process the widget. background processes should avoid UI-related processing, UI, processing rules. This is a good programming style or a programming principle.
By creating a handler subclass object, each acviver requires only one handler object. The background process can communicate with handler in two ways: the message and runnable objects. The result is essentially to put the content in the handler queue, the message is to put information, and some parameters can be passed, handler obtains the information and determines how to handle it, while runnable directly provides a method for processing. The queue is executed in sequence. Handler processes a message or executes a processing task in the next step, so that there is no confusion caused by simultaneous UI processing by multiple threads.
The content in these queues (whether message or runnable) can be executed immediately, with a certain delay or a specified time. If they are placed in the queue header, the queue has a maximum limit, run now. These functions include sendmessage (), sendmessageatfrontofqueue (), sendmessageattime (), sendmessagedelayed (), post (), postatfrontofqueue (), postattime (), postdelay ().
Generally, the messge method is recommended, so that the program design can be more flexible, while runnable is used in some simple and clear methods. We will compile a small example in three ways to learn. This example shows a progress bar. Every 1 second, the progress bar goes 5. If the acsag stops, the progress bar returns to zero.
Android XML:
<? XML version = "1.0" encoding = "UTF-8"?>
<Linearlayout.../>
<Progressbar Android: Id = "@ + ID/c15_progress"
Style = "? Android: ATTR/progressbarstylehorizontal"<! -- This indicates that the traditional horizontal progress bar is used -->
Android: layout_width = "fill_parent"
Android: layout_height = "wrap_content"/>
</Linearlayout>
Example 1: When the thread is enabled, message is used to transmit information between the background thread and the UI main thread.
Public class chapter15test1 extends activity {
Private progressbar bar = NULL;
Private Boolean isrunning = false;
/* We create a handler for this acivity to communicate with the background program. Simply, as soon as the message is received, the progress of progressbar is increased by 5. */
/* Step 1: Create a handler and use handlemessage () to show how the UI processes the received message. In this example, the content of MSG is not analyzed */
Handler handler = new handler (){
Public voidHandlemessage(Message MSG ){
Bar. incrementprogressby (5 );
}
};
Protected void oncreate (bundle savedinstancestate ){
Super. oncreate (savedinstancestate );
Setcontentview (R. layout. chapter_15_test1 );
Bar = (progressbar) findviewbyid (R. Id. c15_progress );
}
/* On Start is called when the UI is initialized and displayed */
Protected void onstart (){
Super. onstart ();
Bar. setprogress (0 );
/* Step 2: Create a background thread for processing. Use thread. The content of run () is the content processed by the thread in parallel, and the thread is the implements of runnable */
Thread background = new thread (New runnable (){
Public voidRun(){
Try {
For (INT I = 0; I <20 & isrunning; I ++ ){
Thread. Sleep (1000 );
/* Step 2.1: send the message to the queue. The obtainmessage () parameter is used to give a new message. In this example, there is no parameter. When handler receives the message in the queue, then, handlemessage () is used for processing */
Handler.Sendmessage(Handler.Obtainmessage());
}
} Catch (throwable t ){
// Jest end the thread
}
}
});
Isrunning = true;
/* Step 3: Start the thread */
Background. Start ();
}
/* Onstop is called when the UI stops displaying. For example, if we press the return key */
Protected void onstop (){
Super. onstop ();
Isrunning = false;
}
}
Example 2: Use runnable
We can make modifications based on the above example, as shown below:
/* Step 1: handlemessage ()*/
Handler handler = new handler ();
/* Step 1.1: Define the processing action. Use runnable instances and use implements run () to customize the processing. Here, the progress bar is simply stepped into Step 5. Because we will use this instance in thread, we should consider using final */
Final runnable r =New runnable (){
Public void run (){
Bar. incrementprogressby (5 );
}
};
/*... In onstart (), Step 2: process the thread. Unlike the message, the runnable method uses post */
Thread background = new thread (New runnable (){
Public void run (){
Try {
For (INT I = 0; I <20 & isrunning; I ++ ){
Thread. Sleep (1000 );
Handler. Post (R );
}
} Catch (throwable t ){
// Jest end the thread
}
}
});
Background. Start ();
Example 3: You can use latency processing to implement timed triggering, making the program simpler.
In this example, we implement scheduled processing. We can use the handler queue to set an extended processing method. We do not need to create a backend running thread or implement it.
Handler handler = new handler ();
... In onstart ()......
// Use handler. postdelayed (R, 1000), requires R processing after 1 second delay in the queue, while in R processing, finally, add a Processing request with a delay of 1 second to the handler queue. If so, regular processing can be performed every 1 second.
Handler. postdelayed (New runnable (){
Public void run (){
If (isrunning & chapter15test2. Step <20 ){
Step ++;
Bar. incrementprogressby (5 );
Handler. postdelayed (this, 1000 );
}
}
},1000);
In this example, we automatically stop adding processing to the queue based on a certain degree of determination. In some cases, if we need to clear the messages or messages in the queue, we can use removmessages () or removecallbacks () for processing. This is very useful for processing latency, regular handling can be interrupted. Of course, in general, we want to get a certain degree of determination so that regular processing can end elegantly, rather than simply deleting messages or processing from the queue.
Example 4: The main UI thread or background thread is unknown.
Sometimes, we do not know whether the code will run in the UI thread or background thread. For example, the Code is encapsulated as a jar and provided to others for calling. We do not know how others use the code. To solve this problem, Android provides runonuithread () in the activity. If it is in the UI thread, it will be executed immediately. If it is in the background thread, then, the runnable execution content is added to the queue of the background thread, so that the code can be safely executed in both the UI thread and background thread.
We will conduct an experiment on the basis of Example 1:
1. Create a runnable so that we can experiment in the UI and background thread.
Runnable runaction = new runnable (){
Public void run (){
// Note that we cannot use toast. maketext (this,...), because we cannot determine the specific running context of runnable.
Toast. maketext (Getapplicationcontext(), "Hello! ", Toast. length_short). Show ();
// Log. D ("wei", "runaction... is called ");
}
};
It takes some time to display and hide toast, but the interval of 1 second is obviously not enough. We will change the interval of 1 to 1000 ms, which will be clearer. Of course, log can be used. d.
2. Execute this operation in the UI thread and add this operation to the background thread. This operation can be correctly executed either in the ui or in the background thread.
Protected void onstart (){
......
Thread background = new thread (New runnable (){
Public void run (){
Try {
For (INT I = 0; I <20 & isrunning; I ++ ){
Thread. Sleep (5000 );
Handler. sendmessage (handler. obtainmessage ());
Runonuithread(Runaction );
}
} Catch (throwable t ){
// Jest end the thread
}
}
});
Isrunning = true;
Background. Start ();
Runonuithread(Runaction );
}
Example 5: handlerthread
In the preceding example, whether or not the background thread is used (Example 1-2), handler actually processes the UI main thread, the general method is to execute some operations through the background thread. If UI interaction is required, the message or processing method is sent to the handler queue, and then processed in the UI main thread. This is a general situation.
We have previously discussed why the UI is UI-based and processing. However, there may be such a requirement. For example, in some cases, handler may have sleep () during processing when receiving a message, which leads the main thread to enter the sleep status, which is not what we expect. Therefore, we want to use a thread to process the hanlder messages. This thread also obtains information from the handler queue in sequence and processes the messages one by one to ensure security and avoid exceptions caused by chaos.
Handlerthread for Android. The method is as follows:
// Step 1: innovate an object of handlerthread and enable this thread. handlerthread processes messages in the handler pair through logoff, that is, if there is a message in the handler, it will be processed in the handlerthread thread.
Handlerthread ht = new handlerthread ("hander_thread ");
// Step 2: Start the handerhandler thread;
Ht. Start ();
// Step 3: Create a handler with The logoff parameter, that is, handlerthread. getlogoff (). Note: This process can only be called after handlerthread is started. Otherwise, an error is reported. If getlooper () returns NULL, a program Exception error occurs.
Handler handler = new handler (HT. getlooper ()){
....
Public void handlemessage (Message MSG ){
...... /* The processing here will not be executed in the main thread, but in the handlerthread thread, it can be executed through thread. currentthread (). GETID () or thread. currentthread (). getname () to determine */
}
};