国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Android源碼解析--享元設(shè)計(jì)模式,handler消息傳遞機(jī)制(基于Android API 33 SDK分析)

這篇具有很好參考價(jià)值的文章主要介紹了Android源碼解析--享元設(shè)計(jì)模式,handler消息傳遞機(jī)制(基于Android API 33 SDK分析)。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

Android源碼解析–享元設(shè)計(jì)模式,handler消息傳遞機(jī)制(基于Android API 33 SDK分析)

一. 定義

使用共享對(duì)象可有效地支持大量的細(xì)粒度的對(duì)象

核心:對(duì)象復(fù)用。

1.1 享元模式Demo

火車票購票Demo

//火車票
public class Ticket {
    private String from;
    private String to;

    public Ticket(String from, String to) {
        this.from = from;
        this.to = to;
    }

    public int getPrice() {
        return new Random().nextInt(100) + 20;
    }
}

緩存對(duì)象在一個(gè)Map中。下面我們還會(huì)分析

//火車票查詢工廠
public class TicketFactory {
    public static Map<String, Ticket> sTicketMap = new HashMap<>();

    public static Ticket getTicket(String from, String to) {
        String key = from + "-" + to + "";
        Ticket ticket = sTicketMap.get(key);
        if (ticket != null) {
            return ticket;
        }
        ticket = new Ticket(from, to);
        sTicketMap.put(key, ticket);
        return ticket;
    }
}

二. Android中源碼實(shí)例分析Message

用法

val obtain = Message.obtain()

跟進(jìn)去

    /**
     * Return a new Message instance from the global pool. Allows us to
     * avoid allocating new objects in many cases.
     */
    public static Message obtain() {
        //防止多線程并發(fā)
        synchronized (sPoolSync) {
            //從線程池取對(duì)象
            if (sPool != null) {
                //鏈表取出每個(gè)Message對(duì)象
                Message m = sPool;
                sPool = m.next;
                m.next = null;
                m.flags = 0; // clear in-use flag
                sPoolSize--;
                return m;
            }
        }
        return new Message();
    }

這就是最明顯的一個(gè)享元設(shè)計(jì)模式。

三. Message的關(guān)聯(lián)者Handler

Android 開發(fā)一個(gè)知識(shí)點(diǎn):UI 不能夠在子線程中更新。

class DebugActivity : AppCompatActivity() {
    private val TAG = javaClass.simpleName
    private var handler: Handler = Handler(Looper.getMainLooper())
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }
    fun doSomething(){
        thread {
            //耗時(shí)操作,得到結(jié)果,不能在這個(gè)線程更新 UI
            // Handler 將結(jié)果傳遞到主線程中,更新UI
            handler.post {
                //更新UI
            }
        }
    }
}

我們跟進(jìn)post函數(shù)

 public final boolean post(@NonNull Runnable r) {
    
       return  sendMessageDelayed(getPostMessage(r), 0);
 }
 private static Message getPostMessage(Runnable r) {
        Message m = Message.obtain();
        m.callback = r;
        return m;
  } 

Handler 傳遞了一個(gè) Runnable給UI線程,裝到一個(gè) Message 對(duì)象中。

跟進(jìn)sendMessageDelayed函數(shù)

public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
 }
 public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
     //當(dāng)前 Handler 所在的消息隊(duì)列
        MessageQueue queue = mQueue;
        if (queue == null) {
            RuntimeException e = new RuntimeException(
                    this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
            return false;
        }
     //將消息添加到消息隊(duì)列中
        return enqueueMessage(queue, msg, uptimeMillis);
 }

sendMessageDelayed 函數(shù)調(diào)用了 sendMessageAtTime函數(shù),不手動(dòng)傳遞 Looper 那么 Handler 持有的 Looper 就是當(dāng)前線程的 Looper,也就是說在哪個(gè)線程創(chuàng)建的 Handler,就是哪個(gè)線程的 Looper。

在 getPostMessage 中的 Message 對(duì)象是Message.obtain()函數(shù)

 Message m = Message.obtain();

分析下這段代碼,

    /**
     * Return a new Message instance from the global pool. Allows us to
     * avoid allocating new objects in many cases.
     */
    public static Message obtain() {
        //防止多線程并發(fā)
        synchronized (sPoolSync) {
            //從線程池取對(duì)象
            if (sPool != null) {
                //鏈表取出每個(gè)Message對(duì)象
                Message m = sPool;
                sPool = m.next;
                m.next = null;
                m.flags = 0; // clear in-use flag
                sPoolSize--;
                return m;
            }
        }
        return new Message();
    }

Message消息池沒有使用 map 這樣的容器,使用的是鏈表。

在這里插入圖片描述

如何放到這個(gè)消息池里面呢?

我們看

Message 對(duì)象回收到消息池中

public void recycle() {
    //該消息還在使用
        if (isInUse()) {
            if (gCheckRecycle) {
                throw new IllegalStateException("This message cannot be recycled because it "
                        + "is still in use.");
            }
            return;
        }
    //消息添加到消息池中
        recycleUnchecked();
    }

跟進(jìn)recycleUnchecked()

 void recycleUnchecked() {
        // Mark the message as in use while it remains in the recycled object pool.
        // Clear out all other details.
     //清空消息狀態(tài)
     flags = FLAG_IN_USE;
        what = 0;
        arg1 = 0;
        arg2 = 0;
        obj = null;
        replyTo = null;
        sendingUid = UID_NONE;
        workSourceUid = UID_NONE;
        when = 0;
        target = null;
        callback = null;
        data = null;
		//回收消息到消息池中
        synchronized (sPoolSync) {
            if (sPoolSize < MAX_POOL_SIZE) {
                next = sPool;
                sPool = this;
                sPoolSize++;
            }
        }
    }

這里用鏈表當(dāng)作了一個(gè)緩存池,存消息對(duì)象。每生成一條消息就會(huì)加入到鏈表在。

四. Android 的消息機(jī)制

Android應(yīng)用程序的入口實(shí)際上是ActivityThread,跟進(jìn)去

public static void main(String[] args) {
        ......
		//創(chuàng)建Looper,UI線程的消息隊(duì)列
        Looper.prepareMainLooper();
		......
    	//啟動(dòng)應(yīng)用程序
        ActivityThread thread = new ActivityThread();
        thread.attach(false, startSeq);
		//循環(huán)消息
        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

Looper 從消息隊(duì)列中取消息,處理消息。Handler不斷地往消息隊(duì)列中添加消息,消息不斷地被處理。

那么Handler是如何關(guān)聯(lián)消息隊(duì)列

Handler 的構(gòu)造函數(shù)

public Handler(@Nullable Callback callback, boolean async) {
      ......
        mLooper = Looper.myLooper();//獲取 Looper
 	 ......
        mQueue = mLooper.mQueue;//獲取消息隊(duì)列
        mCallback = callback;
        mAsynchronous = async;
    }

Handler 通過myLooper()來獲取 Looper 對(duì)象,

跟進(jìn)myLooper()

public static @Nullable Looper myLooper() {
    //myLooper通過sThreadLocal.get()獲取
        return sThreadLocal.get();
    }

Looper對(duì)象存儲(chǔ)在sThreadLocal中的,

	@Deprecated
    public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }
//prepare()方法中創(chuàng)建了一個(gè) Looper 對(duì)象
	private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        //將該對(duì)象設(shè)置給了sThreadLocal,這樣線程和隊(duì)列就關(guān)聯(lián)上了
        sThreadLocal.set(new Looper(quitAllowed));
    }

Handler和線程、線程的消息隊(duì)列關(guān)聯(lián),Handler 發(fā)送的消息就會(huì)被執(zhí)行在這個(gè)線程上。

調(diào)用 Looper 的 loop 函數(shù),不斷地從消息隊(duì)列中取出、處理消息

 public static void loop() {
      ......
          //死循環(huán)
        for (;;) {
            //取消息
            if (!loopOnce(me, ident, thresholdOverride)) {
                return;
            }
        }
    }

跟進(jìn)loopOnce

private static boolean loopOnce(final Looper me,
            final long ident, final int thresholdOverride) {
    //獲取消息 (might block )
        Message msg = me.mQueue.next(); // might block
       ......
        try {
            //處理消息
            msg.target.dispatchMessage(msg);
            if (observer != null) {
                observer.messageDispatched(token, msg);
            }
            dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
        } 
    	......
            //回收消息,也就是我們分析享元模式時(shí)提到的將 Message 添加到消息池的操作
        msg.recycleUnchecked();

        return true;
    }

看看next()核心代碼

Message next() {
       		......
			//native層的事件
            nativePollOnce(ptr, nextPollTimeoutMillis);
				......
                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;
                }

              ......
        }
    }

next 函數(shù)從消息隊(duì)列中依次取出消息,如果這個(gè)消息到了執(zhí)行時(shí)間,那么就將這條消息返回給 Looper,隊(duì)列鏈表的指針后移。

五. 子線程中創(chuàng)建Handler拋出異常

class DebugActivity : AppCompatActivity() {
    private val TAG = javaClass.simpleName
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        thread {
            val handler = Handler()
        }
    }
 
}

Android源碼解析--享元設(shè)計(jì)模式,handler消息傳遞機(jī)制(基于Android API 33 SDK分析),java和Android設(shè)計(jì)模式,android,設(shè)計(jì)模式

分析:Looper 對(duì)象是 ThreadLocal,每個(gè)線程都有自己的Looper,要在子線程中創(chuàng)建 Handler 對(duì)象時(shí),如果 Looper 為空,那么就會(huì)拋出異常。跟進(jìn)Handler的構(gòu)造方法看看

public Handler(@Nullable Callback callback, boolean async) {
        ......
        //獲取looper
        mLooper = Looper.myLooper();
        if (mLooper == null) {
            //拋出異常
            throw new RuntimeException(
                "Can't create handler inside thread " + Thread.currentThread()
                        + " that has not called Looper.prepare()");
        }
     ......
    }

mLooper 對(duì)象為空,拋出異常。該線程中的Looper 對(duì)象還沒有創(chuàng)建,在子線程中沒有手動(dòng)調(diào)用 Looper.prepare之前該線程的 Looper為空,解決方法就是在構(gòu)造 Handler 之前為當(dāng)前線程設(shè)置 Looper 對(duì)象。文章來源地址http://www.zghlxwxcb.cn/news/detail-674075.html

class DebugActivity : AppCompatActivity() {
    private val TAG = javaClass.simpleName
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        thread {
            //綁定到 ThreadLocal中
            Looper.prepare()
            val handler = Handler()
            //啟動(dòng)消息循環(huán)
            Looper.loop()
        }
    }

}

這樣子線程的Looper對(duì)象就不會(huì)為null了,有了自己的消息隊(duì)列。

到了這里,關(guān)于Android源碼解析--享元設(shè)計(jì)模式,handler消息傳遞機(jī)制(基于Android API 33 SDK分析)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 【前端設(shè)計(jì)模式】之享元模式

    享元模式是一種結(jié)構(gòu)型設(shè)計(jì)模式,它通過共享對(duì)象來減少內(nèi)存使用和提高性能。在前端開發(fā)中,享元模式可以用于優(yōu)化大量相似對(duì)象的創(chuàng)建和管理,從而提高頁面的加載速度和用戶體驗(yàn)。 共享對(duì)象:享元模式通過共享相似對(duì)象來減少內(nèi)存使用。相似對(duì)象可以共享一些不變的狀

    2024年02月08日
    瀏覽(26)
  • 設(shè)計(jì)模式-享元模式(Flyweight)

    享元模式(Flyweight Pattern)是一種結(jié)構(gòu)型設(shè)計(jì)模式,它的主要目標(biāo)是減少應(yīng)用程序中對(duì)象的數(shù)量,以節(jié)省內(nèi)存和提高性能。這一模式適用于對(duì)象數(shù)量龐大且相似的情況,通過共享內(nèi)部狀態(tài)來減少對(duì)象的創(chuàng)建。 在本篇博客中,我們將詳細(xì)介紹享元模式的概念,并提供一個(gè)簡單的

    2024年02月09日
    瀏覽(44)
  • 【23種設(shè)計(jì)模式】享元模式【?】

    個(gè)人主頁 :金鱗踏雨 個(gè)人簡介 :大家好,我是 金鱗 ,一個(gè)初出茅廬的Java小白 目前狀況 :22屆普通本科畢業(yè)生,幾經(jīng)波折了,現(xiàn)在任職于一家國內(nèi)大型知名日化公司,從事Java開發(fā)工作 我的博客 :這里是CSDN,是我學(xué)習(xí)技術(shù),總結(jié)知識(shí)的地方。希望和各位大佬交流,共同進(jìn)

    2024年02月09日
    瀏覽(28)
  • js設(shè)計(jì)模式:享元模式

    js設(shè)計(jì)模式:享元模式

    當(dāng)需要處理很多非常類似操作的時(shí)候,可以創(chuàng)建可以共享的對(duì)象,并暴露接口供其他對(duì)象調(diào)用 這個(gè)對(duì)象內(nèi)包含這些操作的處理邏輯,可以優(yōu)化性能 ?

    2024年02月22日
    瀏覽(19)
  • 設(shè)計(jì)模式之享元模式

    設(shè)計(jì)模式之享元模式

    本文看下一種結(jié)構(gòu)型設(shè)計(jì)模式,享元模式。 當(dāng)程序需要大量的重復(fù)對(duì)象,并且這些大量的重復(fù)對(duì)象只有部分屬性不相同,其他都是相同的時(shí)候,就可以考慮使用享元設(shè)計(jì)模式設(shè)計(jì)模式來實(shí)現(xiàn)。典型的如圍棋游戲中的棋子,除了顏色和位置不同外,其他都相同。射擊游戲中的子

    2024年02月17日
    瀏覽(18)
  • Java設(shè)計(jì)模式-享元模式

    在Java領(lǐng)域的軟件開發(fā)中,設(shè)計(jì)模式是提高代碼可維護(hù)性和可擴(kuò)展性的重要工具。其中,享元模式是一種被廣泛使用的設(shè)計(jì)模式,它通過優(yōu)化對(duì)象的重用來提升系統(tǒng)性能。 享元模式是一種結(jié)構(gòu)型設(shè)計(jì)模式,旨在通過共享對(duì)象來減少系統(tǒng)中的對(duì)象數(shù)量,從而提升性能和減少內(nèi)存

    2024年02月06日
    瀏覽(26)
  • 設(shè)計(jì)模式結(jié)構(gòu)型——享元模式

    設(shè)計(jì)模式結(jié)構(gòu)型——享元模式

    目錄 什么是享元模式 享元模式的實(shí)現(xiàn) 享元模式角色 享元模式類圖 享元模式代碼實(shí)現(xiàn) 享元模式的特點(diǎn) 優(yōu)點(diǎn) 缺點(diǎn) 使用場(chǎng)景 注意事項(xiàng) ????????享元模式(Flyweight Pattern)是一種結(jié)構(gòu)型設(shè)計(jì)模式,享元模式中的“享元”指被共享的單元,享元模式通過復(fù)用對(duì)象,以達(dá)到節(jié)省

    2024年02月16日
    瀏覽(25)
  • Java 設(shè)計(jì)模式系列:享元模式

    Java 設(shè)計(jì)模式系列:享元模式

    享元模式(Flyweight Pattern)是一種軟件設(shè)計(jì)模式,用于減少內(nèi)存使用和提高性能。它通過共享細(xì)粒度對(duì)象來減少創(chuàng)建和銷毀對(duì)象時(shí)所需的內(nèi)存。享元模式適用于大量相似對(duì)象的場(chǎng)景,這些對(duì)象可以共享相同的狀態(tài)和行為。 享元模式的核心思想是將對(duì)象分為內(nèi)部狀態(tài)和外部狀態(tài)

    2024年04月15日
    瀏覽(40)
  • C#設(shè)計(jì)模式之---享元模式

    享元模式(Flyweight Pattern)是一種結(jié)構(gòu)型模式,是運(yùn)用共享技術(shù)有效的支持大量細(xì)粒度的對(duì)象。它使用共享對(duì)象,用來盡可能減少內(nèi)存使用量以及分享資訊給盡可能多的相似對(duì)象;它適合用于只是因重復(fù)而導(dǎo)致使用無法令人接受的大量內(nèi)存的大量對(duì)象。通常對(duì)象中的部分狀態(tài)

    2024年02月16日
    瀏覽(20)
  • 設(shè)計(jì)模式之享元模式筆記

    設(shè)計(jì)模式之享元模式筆記

    記錄下學(xué)習(xí)設(shè)計(jì)模式-享元模式的寫法。JDK使用版本為1.8版本。 意圖 :運(yùn)用共享技術(shù)有效地支持大量細(xì)粒度的對(duì)象。 結(jié)構(gòu) : 其中: Flyweight描述一個(gè)接口,通過這個(gè)接口Flyweight可以接受并作用于外部狀態(tài)。 ConcreteFlyweight實(shí)現(xiàn)Flyweight接口,并為內(nèi)部狀態(tài)(如果有)增加存儲(chǔ)空間。C

    2024年02月11日
    瀏覽(15)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包