当前位置:网站首页>Handler、Message、Looper、MessageQueue
Handler、Message、Looper、MessageQueue
2022-06-25 11:15:00 【User 9854323】
List of articles
- One 、 What is? handler
- Two 、handler Message mechanism principle
- 3、 ... and 、Handler Message mechanism component
- 3、 ... and 、Handler The three ways of using
- Four 、Handler Memory leak problem
One 、 What is? handler
Two 、handler Message mechanism principle
handler Message mechanism principle : The essence is to implement a message queue between threads (MessageQueue). producer Handler When an asynchronous thread passes sendMessageDelayed() Add messages to MessageQueue, consumer Looper adopt loop() The middle loop will MessageQueue Medium msg Take it out and send it to generate this msg Of handler Of handleMessage() Processing in the main thread ;
3、 ... and 、Handler Message mechanism component
Handler
public Handler(Callback callback, boolean async) {
//mLooper There is only one per thread Looper
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}sendMessageDelayed take msg Send to message queue
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}looper take msg Distribute here , Then the thread that accepts the message processes msg
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
// Accept msg The thread that processes the message
handleMessage(msg);
}
}Message
public final class Message implements Parcelable {
/**
* User defined message code , So that the recipient can recognize the content of this message . Every {@link Handler} Each has its own message code name
* Space , So you don't have to worry about conflicts with other handlers .
*/
public int what;
/**
* Optional Messenger, Replies to this message can be sent . Exactly how to use it * Semantics depend on the sender and receiver .
*/
public Messenger replyTo;
/**
* Optional fields , Indicates the... That sent the message uid. This is only for {@link Messenger} The published message is valid ; otherwise , It will be -1.
*/
public int sendingUid = -1;
/*package*/ int flags;
/*package*/ Bundle data;
/*package*/ Handler target;
/*package*/ Runnable callback;
// We store the linked list of these things
/*package*/ Message next;Looper
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
} public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
// This must be in a local variable, in case a UI event sets the logger
final Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what);
}
try {
//lopper Here according to msg.target(handler) distribution msg
msg.target.dispatchMessage(msg);
end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}MessageQueue
// At the bottom is the form of linked list msg
Message next() {
final long ptr = mPtr;
if (ptr == 0) {
return null;
}
for (;;) {
synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null) {
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
if (now < msg.when) {
// Next message is not ready. Set a timeout to wake up when it is ready.
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// Got a message.
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
if (DEBUG) Log.v(TAG, "Returning message: " + msg);
msg.markInUse();
return msg;
}
} else {
// No more messages.
nextPollTimeoutMillis = -1;
}
}3、 ... and 、Handler The three ways of using
Known from the following code ,handler Yes 3 Method of use :
Handler in looper Finally, put msg Send to this method :
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
//1、 Threads run regularly
handleCallback(msg);
} else {
if (mCallback != null) {
//2、mCallback The callback method
if (mCallback.handleMessage(msg)) {
return;
}
}
//3、handler Methods
handleMessage(msg);
}
}
private static void handleCallback(Message message) {
message.callback.run();
}1)、 Run a thread regularly :public final boolean post(Runnable r) 2)、1) When not satisfied , Then when callBack Isn't empty , Callbacks callBack Of handleMessage() Method :
public Handler(Callback callback) {
this(callback, false);
}
public interface Callback {
public boolean handleMessage(Message msg);
}3)、 above 1)、2) When they are not satisfied , call handler Of handleMessage() Method ;
1、 Run a thread regularly
example 1:
private Runnable mNextRunnable = new Runnable() {
@Override
public void run() {
mHandler.removeCallbacks(mNextRunnable);
if(isCycle()){
setCurrentItem(getCurrentItem() + 1, true);
mHandler.postDelayed(mNextRunnable, mDelayTime);
}
}
};example 2:
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
Activity activity = (Activity)context;
if (activity != null && !activity.isFinishing()) {
ToastUtil.makeToast(context,“ OK ”, Toast.LENGTH_SHORT).show();
}
}
}, 1000);Known from the following code : When the time comes msg Add to the queue
MessageQueue in :
boolean enqueueMessage(Message msg, long when) {
msg.when = when;
Message p = mMessages;
boolean needWake;
// When the time comes msg Add to the queue
if (p == null || when == 0 || when < p.when) {
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}2、1 When not satisfied , Then when callBack Isn't empty , Callbacks callBack Of handleMessage() Method
3、 above 1、2 When they are not satisfied , call handler Of handleMessage() Method ;
Four 、Handler Memory leak problem
reason :
1、 When using inner classes ( Including anonymous classes ) To create Handler When ,Handler Objects implicitly hold an external class object ( It's usually a Activity) References to ( How else can you get through Handler To operate Activity Medium View?). and Handler Usually with a time-consuming background thread ( For example, pulling pictures from the Internet ) Come together , This background thread finishes executing the task ( For example, after downloading the pictures ) after , Notify... By message mechanism Handler, then Handler Update the image to the interface . However , If the user turns off during a network request Activity, Under normal circumstances ,Activity No longer used , It could be in GC Recycled during inspection , But because the thread is not finished , And the thread holds Handler References to ( How else would it send a message to Handler?), This Handler And hold Activity References to , That leads to the Activity Cannot be recycled ( Memory leaks ), Until the end of the network request ( For example, after downloading the pictures ). 2、 in addition , If you execute Handler Of postDelayed() Method , This method will turn your Handler Load one Message, And put this Message push to MessageQueue in , So in what you set delay Before arriving , There will be one MessageQueue -> Message -> Handler -> Activity Chain , What caused you Activity Is held for reference and cannot be recycled .
give an example :
public class LeakCanaryActivity extends AppCompatActivity
private Handler mHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
Message message = Message.obtain();
message.what = 1;
mHandler.sendMessageDelayed(message,10*60*1000);
}
}terms of settlement
Method 1 : Program logic code .
1. Closing Activity Stop your background thread .
Thread stopped , It's like cutting off Handler A line connected to the outside ,Activity It will be recycled at the right time .
private void recycle() {
mExecutor.shutdownNow();
}2. The message object is removed from the message queue
If your Handler Be being delay Of Message Holding quotes , Then use the corresponding Handler Of removeCallbacks() Method , Just remove the message object from the message queue .
/**
* Delete any pending in the message queue Runnable
*/
public final void removeCallbacks(Runnable r)
{
mQueue.removeMessages(this, r, null);
}example :
private void recycle() {
if (mHandler != null) {
mHandler.removeCallbacks(null);
}
}Method 2 : take Handler Declared as a static class ,activity Use weak references to assign values to
Static classes do not hold objects of external classes , So your Activity Can be recycled at will . The code is as follows :
static class MyHandler extends Handler {
@Override
public void handleMessage(Message msg) {
mImageView.setImageBitmap(mBitmap);
}
}But it's not that simple . After using the above code , You'll find that , because Handler No longer holds references to external class objects , Cause the program doesn't allow you to Handler In the operation Activity The object of . So you need to be in Handler Add a pair to Activity The weak references (WeakReference):
static class MyHandler extends Handler {
WeakReference<Activity > mActivityReference;
MyHandler(Activity activity) {
mActivityReference= new WeakReference<Activity>(activity);
}
@Override
public void handleMessage(Message msg) {
final Activity activity = mActivityReference.get();
if (activity != null) {
mImageView.setImageBitmap(mBitmap);
}
}
}边栏推荐
- GaussDB 集群维护案例集-sql执行慢
- Spannable 和 Editable、SpannableString 和 SpannableString
- 每日3题(2)- 找出数组中的幸运数
- Démarrer avec Apache shenyu
- Comparator(用于Arrays.sort)
- 10.1. Oracle constraint deferred, not deferred, initially deferred and initially deferred
- Android: generic mapping analysis of gson and JSON in kotlin
- zabbix分布式系统监控
- GaussDB 如何统计用户sql的响应时间
- Dragon Book tiger Book whale Book gnawing? Try the monkey book with Douban score of 9.5
猜你喜欢

scrapy+scrapyd+gerapy 爬虫调度框架

SystemVerilog (XIII) - enumerate data types

Query method and interrupt method to realize USART communication

Dell technology performs the "fast" formula and plays ci/cd

Double tampon transparent cryptage et décryptage basé sur le cadre minifilter

Shen Ying, China Academy of communications and communications: font open source protocol -- Introduction to ofl v1.1 and analysis of key points of compliance

戴尔科技演绎“快”字诀,玩转CI/CD

At 16:00 today, Mr. sunxiaoming, a researcher of the Institute of computing, Chinese Academy of Sciences, took you into the quantum world

Open source invites you to participate in the openssf Open Source Security Online Seminar

网易开源的分布式存储系统 Curve 正式成为 CNCF 沙箱项目
随机推荐
Free access to the global human settlements layer (ghsl) dataset from Gee
金仓数据库 KingbaseES 插件dbms_session
C disk uses 100% cleaning method
Google Earth Engine (Gee) - evaluate réalise le téléchargement en un clic de toutes les images individuelles dans la zone d'étude (certaines parties de Shanghai)
ARM64汇编的函数有那些需要注意?
Kingbasees plug-in DBMS of Jincang database_ RANDOM
GaussDB 如何统计用户sql的响应时间
垃圾回收机制
【上云精品】节能提效!加速纺织业“智造”转型
过拟合原因及解决
金仓KFS数据级联场景部署
Apache ShenYu 入门
Android:kotlin中Gson与JSON的泛型映射解析
Google Earth Engine(GEE)——evaluate實現一鍵批量下載研究區內的所有單張影像(上海市部分區域)
金仓数据库 KingbaseES 插件DBMS_RANDOM
Software testing to avoid being dismissed during the probation period
SystemVerilog (XIII) - enumerate data types
3 Questions par jour (3) - vérifier l'existence d'entiers et de leurs doubles
Chinese translation of IMA Lazarus' the new giant, the goddess of Liberty
Database Series: MySQL index optimization summary (comprehensive version)