Handler, lofter, MessageQueue of Android Learning
Other threads in Andorid cannot directly update the UI control. Processing of relatively time-consuming data retrieval is usually done in other threads, after the thread is loaded successfully, the main thread executes the corresponding display operation, which reduces the impact on user experience.
A Message loop contains a Thread and a logoff. logoff is usually used to manage the Message queue of the current Thread. Therefore, if it is a Message loop, a Thread and a logoff are required. The main thread is a message loop, so it contains a logoff object. All the operations executed by the main thread are managed through logoff (get the corresponding message and execute the corresponding operation ). The created Backgroun thread usually does not contain the logoff object. You can also use HandlerTask to reload a class that contains logoff.
The implementation of HandlerTask involves the logoff process. The Code is as follows:
Message contains the following fields: what: Mainly used to define the Message type. Obj: Mainly used to save data. target: the Handler object that processes the message. Message creation and processing are completed by a handler, so the target is usually automatically filled.
At the same time, messages can only be consumed on a specific logoff, so each Handler is bound to a logoff. However, multiple Handler can be bound to the same logoff, which is also the reason why a new Handler can be created in the main thread. Therefore, Handler messages exist in the same message loop.
The specific relationship diagram is as follows:
Handler. obtainMessage () is used to obtain the Message instance. In this case, the binding relationship between Handler and Message is completed.
After obtaining the Message, you can call sendtoTarget () to send the Message to Handler. After receiving the message, Handler fills the corresponding message at the end of The logoff Message Queue loop.
HandlerThread. onLooperPrepared () is called during the first check queue of logoff. Therefore, you can create a Handler instance in this interface. Generally, Handler instances also need to create an overloaded handleMessage () to process specific messages in this function.
Handler can be used in other threads, but message processing is completed in the thread where the Handler is created, that is, it is consumed in the corresponding Looper.
A handler can be transferred to other threads in the main thread. Other threads can update data to the main thread or send data to the main thread through the handler. The following two methods can be used to process the data or handler message: (1) handleMessgae of handler can be implemented in the main thread, (2) you can also call the post interface by passing handler in other threads.
Method 1: parameters are transmitted to other threads in the main thread, and other threads Save the corresponding handler entity. At the same time, the handleMessage interface of the current handler must be implemented in the main thread. When other threads complete related processing or need to update, send data to the main thread sendMessage () by saving the data to the handler entity (). This implementation method requires the main thread to implement the handlerMessage function of different handler.
The basic code can be as follows: main Thread:... Thread background = new BackgroundThread (mHandler); background. start ();
...MHandler = new Handler (){@ OverridePublic void handleMessage (Message msg ){If (msg. what = MESSAGE_DOWNLOAD ){Token token = (Token) msg. obj;Log. I (TAG, "Got a request for url:" + requestMap. get (token ));HandleRequest (token );}}};
The processing in BackgroundThread is relatively simple: classBackgroundThread extends Thread {Handler mHandler ;... message message = mHandler. handler. obtainMessage ();... /* fill in the message and send the message */mHandler. sendMessage (message );}
Method 2: Obtain the handler of a main thread from the constructor of another thread, save the corresponding handler instance in the Thread class, and provide an interface in the Thread class, the purpose of this interface is to allow the main thread to register the corresponding interface and complete data processing operations in this interface. This interface is implemented by setting lister. The main thread directly transmits a handler during the process of creating the thread and sets the corresponding listener lister. Generally, operations related to UI control are completed. When data in the thread is sent to the main thread, you can call the post interface to call the listener set by the main thread in the post parameter. The parameter of the post method is a Runnable object, the void run () method must be implemented. You can call the listener registered by the main thread in this method.
Other threads: public class ThumbnailDownloader <Token> extends HandlerThread {.../* respectively stores the Handler passed by the main thread */Handler mResponseHandler;/* Save the listener object set by the main thread */Listener <Token> mListener;/* this interface is defined by the main thread or the thread that receives data */
Public interface Listener <Token> {void onThumbnailDownloaded (Token token, Bitmap thumbnail);}/* The Listener is the implementation process */public void setListener (listener <Token> Listener) {mListener = listener;} public ThumbnailDownloader (Handler responseHandler) {super (TAG); mResponseHandler = responseHandler ;}... handleRequest (token );... private void handleRequest (final Token token ){... mResponseHandler. post (new Runnable (){@ OverridePublic void run (){If (requestMap. get (token )! = UrlString ){Return;} RequestMap. remove (token );/* Update the UI control of the main thread through the interface object */MListener. onThumbnailDownloaded (token, bitmap );}});}}
Processing in the main thread:/* Passing the handler parameter to other threads */MThumbnailThread = new ThumbnailDownloader (new Handler ());/* Set the listener, which is actually the process of processing specific data */MThumbnailThread. setListener (new ThumbnailDownloader. Listener <ImageView> (){@ OverridePublic void onThumbnailDownloaded (ImageView token, Bitmap thumbnail ){/* Implement specific processing */If (isVisible ()){Token. setImageBitmap (thumbnail );}}); MThumbnailThread. start ();...
In fact, the post method is equivalent to the following code:Runnable myRunnable = new Runnable (){Public void run (){/* Actual processing functions */}};Message m = mHandler. obtainMessage ();M. callback = myRunnable;
That is, after callback is set in the message, the handleMessage interface defined in the handler creation process is not executed, but the passedThe run () function in Runnable.
The implementation method of method 2 is the same as that of communication between Fragment and Activity. The provider provides interfaces, and the provider must implement specific interfaces. In the Activity, the implements interface in the Activity class is used, while in the communication between multiple threads, the listener is set, listener parameters implement the service processing method. The service provider can directly call the interface object to realize the communication between threads.
Therefore, if Android is used to the implementation of this interface or listener, that is, defining an interface in one of the classes and obtaining the instance object of this interface in some way, for example, onAttach () is used between activities, and listener is set here. This object implements the specific object of a specific interface. The object of this interface can realize communication between two classes.
Class A: defines an interface and provides methods to obtain the interface instance. Generally, setLister is used. class B: implements specific interfaces and passes the specific interface instance to object A through setLister. A can call the specific implementation through the interface object passed by B to complete the communication between Class A and Class B. A can be A service provider, while B can be A service recipient.