Use Handler in Android to implement message delivery mechanism (3)
In the second article "using Handler in Android to implement message distribution mechanism (I)", we mentioned that the Logoff of the main thread is when the Android system starts the App, we have already created the Handler for us. If Handler needs to be used in the child thread, We need to explicitly call The logoff prepare method and loop method, to create a unique logoff for the sub-thread.
The Code is as follows:
class LooperThread extends Thread { public Handler mHandler; public void run() { Looper.prepare(); mHandler = new Handler() { public void handleMessage(Message msg) { Log.v("Test", "Id of LooperThread : " + Thread.currentThread().getId()); ... } } }; Looper.loop(); } }
In fact, the Android SDK has provided such an implementation, a class called HandlerThread, which inherits the thread and calls logoff in its run method. prepare () and logoff. loop () method to create a thread with logoff, as shown in the following code:
@Override public void run() { mTid = Process.myTid(); Looper.prepare(); synchronized (this) { mLooper = Looper.myLooper(); notifyAll(); } Process.setThreadPriority(mPriority); onLooperPrepared(); Looper.loop(); mTid = -1; }
The logoff corresponding to the Handler defined in the main thread still belongs to the main thread. In fact, it only implements asynchronous processing in the main thread.
In daily development, HandlerIntent can be used to implement business processing in sub-threads.
Generally, we create a class to inherit HandlerThread, as shown below:
public class MyHandlerThread extends HandlerThread { public MyHandlerThread(String name) { super(name); } } protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.v("Test", "Id of MainThread : " + Thread.currentThread().getId()); MyHandlerThread myHandlerThread = new MyHandlerThread("MyHandlerThread"); myHandlerThread.start(); Handler handler = new Handler(myHandlerThread.getLooper(), new Callback() { @Override public boolean handleMessage(Message msg) { Log.v("Test", "id of Thread by Callback : " + Thread.currentThread().getId()); return false; } }); handler.sendEmptyMessage(0); }
In this example, a MyHandlerThead object is created. Remember, it is a thread, so you need to call its start method to run the thread.
Next, we need to use one of Handler's constructor Handler (loler, Callback) to assign the Looper in the HandlerThread to handler, and then pass in the Handler. callback interface implementation class, as shown in the code above.
Finally, call the sendMessage method. The result is as follows:
10-28 17:24:50.438: V/Test(31694): Id of MainThread : 110-28 17:24:50.448: V/Test(31694): id of Thread by Callback : 91617
It can be seen that the processing logic of handleMessage is already running in another thread.
Generally, Handler is also implemented when handlerThread is created. the Callback interface encapsulates the code logic to be implemented in this thread to make the code more readable, as shown below:
public class MyHandlerThread extends HandlerThread implements Callback{ public MyHandlerThread(String name) { super(name); } @Override public boolean handleMessage(Message msg) { Log.v("Test", "id of Thread by Callback : " + Thread.currentThread().getId()); return true; } } protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.v("Test", "Id of MainThread : " + Thread.currentThread().getId()); MyHandlerThread myHandlerThread = new MyHandlerThread("MyHandlerThread"); myHandlerThread.start(); Handler handler = new Handler(myHandlerThread.getLooper(), myHandlerThread); handler.sendEmptyMessage(0); }
When it comes to code readability, sometimes we pay more attention to the hierarchy or modularity and coupling between codes.
Different business logic and functions should be implemented in different modules, and the module and module can communicate with each other through a message, we can use Handler and HandlerThread.
For example, the class diagram of a small browser Demo recently made is as follows:
MessageDispatcher is used to store the Handler of each module. Its structure is as follows:
private static MessageDispatcher mMsgDispatcher; private SparseArray
mHandlers; ... public void sendMessage(int target, int from, int msgWhat, Object obj){ Handler handler = mHandlers.get(target); if(handler == null){ Logger.v("There is no Handler registered by target " + target); return; } Message msg = handler.obtainMessage(); msg.what = msgWhat; msg.obj = obj; msg.arg1 = from; handler.sendMessage(msg); }; public void registerHanlder(int key, Handler handler){ mHandlers.put(key, handler); } public void unregisterHanlder(int key){ if(mHandlers.get(key) != null){ mHandlers.delete(key); } } public void destroy(){ mHandlers = null; }
In different module implementations, we can call the registerHandler method to register the Handler of the object to MessageDispatcher, and then specify the target through the sendMessage method, if the target module also sends a message to MessageDispatcher, the Handler can be obtained, and then the Handler can be used to send messages and process them.
For example, we send a message to BookmarkManager in BookmarkActivity, as follows:
mMessageDispatcher.sendMessage(MessageConstant.TARGET_BOOKMARK_MGR, MessageConstant.TARGET_BOOKMARK_ACTIVITY, MessageConstant.MSG_BOOKMARK_GET_ALL_DIR, sparseArray);
In BookmarkManager, when the handler receives the corresponding message, it will process the corresponding message as follows:
class BookmarkHandlerThread extends HandlerThread implements Callback{ public BookmarkHandlerThread(String name) { super(name); } @SuppressWarnings("unchecked") public boolean handleMessage(Message msg){ switch(msg.what){ case MessageConstant.MSG_BOOKMARK_GET_ALL_DIR: //Do Something
In this way, we can separate the business logic and data operations to implement functional programming.
Although it's just not a very mature idea, I still want to share with you the hope that when designing the code architecture, we can layer and block it based on functions, business needs, or basic frameworks, implement loose coupling of code.
End.