[- Video篇 -]:記一次Handler的使用
0.前言
最近在重構我的影片播放器,專案有點點複雜,不可能全面的記錄
接下來,挑一些要點來記錄一下,上下文鋪設比較繁瑣,所以用虛擬碼
本文可以算是對的補充
功能需求:
如果皮膚未顯示,點選螢幕 [顯示皮膚], 5s後[自動隱藏皮膚]
如果皮膚已顯示,點選皮膚[隱藏皮膚]
1.使用Handler傳送延遲訊息
可能平時Handler都是post用來切換執行緒,它的本職是收發訊息
這裡很容易想到使用Handler傳送延遲訊息
override fun showPanel() {
isShow = true
//TODO 顯示皮膚處理邏輯
//使用Handler五秒鐘之後隱藏皮膚
mHandler.sendEmptyMessageDelayed(100, 5000)
}
private val mHandler = Handler {
//TODO 顯示皮膚處理邏輯 hidePanel()
false
}
2.問題來了
在用的時候總感覺哪裡不對勁,後來想想Handler的模型,應該是上一個訊息的鍋
我畫了一個圖,應該很明顯,在第四秒點選時,第五秒仍會觸發上一次的資訊
也就導致了第四秒的顯示皮膚只停留了1s,所以體驗很不好,既然發現問題了,那就解決一下唄
override fun showPanel() {
isShow = true
//TODO 顯示皮膚處理邏輯
//使用Handler五秒鐘之後隱藏皮膚
mHandler.removeMessages(100)//移除訊息
mHandler.sendEmptyMessageDelayed(100, 5000)
}
解決起來很簡單,顯示皮膚時把訊息移除就行了
本次記錄結束,為了感覺不那麼水。瞟一眼原始碼吧
3.根據what移除訊息原始碼
---->[Handler#removeMessages(int)]-------------------------
|-- 根據訊息的what標識刪除訊息,可見是MessageQueue光環-----------
public final void removeMessages(int what) {
mQueue.removeMessages(this, what, null);
}
---->[MessageQueue#removeMessages(Handler, int,Object)]-----------
void removeMessages(Handler h, int what, Object object) {
if (h == null) {//Handler為空,直接返回
return;
}
synchronized (this) {
Message p = mMessages;//訊息佇列的第一個物件
// Remove all messages at front.-----------移除開頭符合條件的訊息----------
//如果條件為真下面的程式碼會執行,此時p節點是我們想要移除的
// 貌似只是開頭為目標節點才會執行 ---------------
while (p != null && p.target == h && p.what == what
&& (object == null || p.obj == object)) {
Message n = p.next;//臨時變數n 記錄下一節點
mMessages = n;
p.recycleUnchecked();//回收掉p訊息
p = n;//此時的p是目標的下一節點
}
// Remove all messages after front. ---- 移除開頭之後符合條件的訊息 --------
while (p != null) {//遍歷所有p之後的節點
Message n = p.next; //目標節點的下一節點
if (n != null) {
if (n.target == h && n.what == what//現在n是我們想要移除的
&& (object == null || n.obj == object)) {
Message nn = n.next;
n.recycleUnchecked();//回收掉n訊息
p.next = nn;
continue;
}
}
p = n;
}
}
}
4.根據訊息的Runnable移除訊息
這個和上面差不多,不過很少人用Message的Runnable吧,Message本身可以新增一個Runnable的可執行體
在Handler的dispatchMessage
中會優先觸發訊息的callback,即Runnable物件,而不會執行Handler自身的回撥
---->[Handler#dispatchMessage]---------------
public void dispatchMessage(Message msg) {
if (msg.callback != null) {//如果msg有回撥
handleCallback(msg);//處理msg的callback
} else {
if (mCallback != null) {//這個上面舉例說明過,不說了
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);//回撥覆寫的handleMessage方法
}
}
---->[Handler#handleCallback]---------------
private static void handleCallback(Message message) {
message.callback.run();
}
---->[MessageQueue#removeMessages(Handler,Runnable,Object)]-----------
void removeMessages(Handler h, Runnable r, Object object) {
if (h == null || r == null) {
return;
}
synchronized (this) {
Message p = mMessages;
// Remove all messages at front.
//注意這裡用的是 == ,也就是匹配的是物件的記憶體地址 ----------
while (p != null && p.target == h && p.callback == r
&& (object == null || p.obj == object)) {
Message n = p.next;
mMessages = n;
p.recycleUnchecked();
p = n;
}
// Remove all messages after front.
while (p != null) {
Message n = p.next;
if (n != null) {
if (n.target == h && n.callback == r
&& (object == null || n.obj == object)) {
Message nn = n.next;
n.recycleUnchecked();
p.next = nn;
continue;
}
}
p = n;
}
}
}
---->[Handler#removeCallbacks]---------------
|--- 根據訊息的Runnable移除訊息
public final void removeCallbacks(Runnable r){
mQueue.removeMessages(this, r, null);
}
所以,也可以根據message的回撥移除訊息
private val mHandler = Handler()
val callback = Runnable {
//TODO 顯示皮膚處理邏輯 hidePanel()
}
override fun showPanel() {
isShow = true
//TODO 顯示皮膚處理邏輯
//使用Handler五秒鐘之後隱藏皮膚
mHandler.removeCallbacks(callback)
mHandler.sendEmptyMessageDelayed(100, 5000)
}
好了,這篇小記就到這裡
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/3137/viewspace-2824680/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- [- Video篇 -]:記一次SQLite的使用IDESQLite
- Android---元件篇---Handler的使用(1)[轉]Android元件
- MYSQL使用記錄之:handlerMySql
- Handler的使用、記憶體洩漏和解決記憶體
- Android學習筆記06——handler的使用Android筆記
- 避免使用Handler而造成的記憶體洩漏記憶體
- 從Handler.post(Runnable r)再一次梳理Android的訊息機制(以及handler的記憶體洩露)Android記憶體洩露
- 記一次uniapp video元件影片無法播放問題APPIDE元件
- 記一次面試後的經歷,求解篇面試
- Android中Handler的使用Android
- Android Handler機制理解和AsyncTask使用小記Android
- 記一次觀察者模式的使用模式
- 記一次使用Oauth的情況OAuth
- Android中使用Handler造成記憶體洩露的分析和解決Android記憶體洩露
- Android原始碼解析Handler系列第(四)篇 --- 打破Handler那些困惑事兒Android原始碼
- Android中Handler的正確使用Android
- 原始碼篇:Handler那些事(萬字長文)原始碼
- Android中使用Handler為何造成記憶體洩漏?Android記憶體
- 記一次元件化開發中使用ButterKnife的使用元件化
- .NET 8 Video教程介紹(開篇)IDE
- Movavi Video Suite 使用教程|如何燒錄DVD ?使用Movavi Video Suite!IDEUI
- Android學習筆記·HandlerAndroid筆記
- Handler、MessageQueue、Looper的分析(複習筆記)OOP筆記
- 記一次使用windbg排查記憶體洩漏的過程記憶體
- 記一次 Laravel 使用 Redis 踩得坑LaravelRedis
- 記一次HttpClient使用問題分析HTTPclient
- 記一次控制器中介軟體的使用
- 記一次 Mysql 日期使用不當造成的 bugMySql
- android Handler導致的記憶體洩露Android記憶體洩露
- Android中Handler引起的記憶體洩露Android記憶體洩露
- Android 中 Handler 引起的記憶體洩露Android記憶體洩露
- Handler的原理
- Android Handler的使用方式和注意事項Android
- Android 9.0 原始碼_機制篇 -- 全面解析 HandlerAndroid原始碼
- Handler訊息機制及handler原理(Handler,Looper,MessageQueue),自定義HandlerOOP
- jquery , find the event handler,找到jquery中的event handlerjQuery
- 記一次使用第三方庫的坑
- 記一次 Ant Design Menu元件的使用與深入元件