Handler筆記

1卵史、數(shù)據(jù)通信會帶來什么開發(fā)中的問題菜循?
(1)線程間如何進(jìn)行通信
Handler通信實(shí)現(xiàn)的方案實(shí)際上是內(nèi)存共享方案柄驻。
(2)為什么線程間不會干擾
(3)為什么wait/notify的用武之地不大
因?yàn)镠andler已經(jīng)將需要這部分功能進(jìn)行了Linux層的封裝
1、Looper的創(chuàng)建涮母,如果想在一個線程中使用Handler則第一步為執(zhí)行Looper.prepare 配深,Looper中存在一個靜態(tài)的變量ThreadLocal携添,prepare方法中new一個Looper,并將這個Looper保存到ThreadLocal中篓叶。
2烈掠、Looper的無線循環(huán)啟動,在子線程的run方法中的最后缸托,啟動Looper.loop, 這個是一個無限循環(huán)左敌,一直從MQ中獲取消息進(jìn)行處理。
3嗦董、MessageQuenue的創(chuàng)建母谎,MQ是Looper的成員變量,在Looper的構(gòu)造函數(shù)中創(chuàng)建京革。
4奇唤、Handler的創(chuàng)建,在任意線程中創(chuàng)建Handler匹摇,都會通過Looper的ThreadLocal獲取一下當(dāng)前線程的Looper咬扇,如果沒有獲得Looper則拋出異常,Handler會持有Looper和從Looper中獲取的MQ廊勃、
5懈贺、使用经窖,Handler.sendMessage,最終都會調(diào)用MQ的enqueueMessage將消息入隊
6、在Looper從MQ中拿到消息后梭灿,就會調(diào)用與消息綁定的Handler的handlerMessage方法,也就是msg.handler.handlerMessage處理消息堡妒。

1、主線程的Handler啟動
一個APP的啟動流程是從桌面啟動器Lanuncher點(diǎn)擊圖標(biāo)-->fork一個zygote進(jìn)程搬泥,分配一個JVM,JVM的main函數(shù)在ActivityThread中,在ActivityThread的main方法中伏尼,執(zhí)行
Looper.prepareMainLooper,為主線程準(zhǔn)備一個Looper忿檩,執(zhí)行Loop.loop開始循環(huán)MQ爆阶。

Loop.loop中是一個死循環(huán)燥透,一直調(diào)用MQ的queue.next查詢讀取消息。
因?yàn)閘oop是個死循環(huán)扰她,也就是所有的代碼都會在Loop中執(zhí)行兽掰。
線程間通信只是Handler的一個附屬的功能,真實(shí)的作用是所有的代碼都在Handler中執(zhí)行窖壕。維持著Android APP運(yùn)行的框架瞻讽。所以要重視。
那Loop如何停掉速勇,
for(;;){
Message msg = queue.next();
if(msg == null){//什么時候返回一個為空的msg的message,1养匈、應(yīng)用退出呕乎,調(diào)用quit()
//沒有消息 陨晶,意味著這messageQueue正在退出。
return;
}
}

handler-->sendMessage,消息起點(diǎn)
handlerMessage //消息結(jié)束湿刽。中間發(fā)生了什么,需要看源碼撮躁。


image.png

優(yōu)先級隊列
入隊: Handler.sendMessage-> MQ-> enqueueMessage,向MQ中放入Message买雾,在消息隊列中插入一個消息。
出隊: Loop.loop 中MQ.next()方法嗤军,出隊列晃危。那是誰來取吶,是Loop來調(diào)用震叮,

Looper.loop->MQ.next->msg.target.dispatch->handleMessage()鳍鸵。

問題偿乖,從細(xì)節(jié)上來說,Message在動的過程
Message怎么來的媳禁,new 或者 obtain;無論Message怎么創(chuàng)建画切,都是一塊內(nèi)存霍弹。
子線程
主線程
因?yàn)閮?nèi)存不分線程,所以子線程和主線程都可以使用一塊內(nèi)存拧烦。
handle = new Handler(){
handleMessage()
{

}

}
new Thead(new Runable(){
void run(){
Looper.prepare
Loop.loop
handle.sendEmptyMessage(new Message)钝计;//子線程創(chuàng)建消息齐佳。
}

})

MQ的數(shù)據(jù)結(jié)構(gòu)炼吴,由單鏈表形成的優(yōu)先級隊列疫衩。優(yōu)先級隊列是有順序的闷煤。
Message.next-->Message-->next-->Message
先后順序,時間假褪,先后順序近顷。

有sendMessageAtTime方法窒升,有時間順序。
那么是怎么排序的吶域醇?看enqueueMessage
if (p == null || when == 0 || when < p.when) {這個是隊列為空冤寿《搅看else不為空
{
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {//找到一個p狠角,當(dāng)p為空或者p的執(zhí)行時間大于當(dāng)前入隊msg的時間
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p; // invariant: p == prev.next//將msg按照時間順序插入隊列
prev.next = msg;
}
排序算法丰歌,插入。
為什么是一個隊列眼溶,先進(jìn)先出晓勇。
先進(jìn)無法保證,因?yàn)橛袝r間排序绰筛,那么先出吶铝噩?
看,loop 毛甲,一直都是mq.next 一直取最前面的一個具被,所以是一個隊列硬猫。

Looper源碼分析。
核心在與構(gòu)造函數(shù)坑雅,一個數(shù)loop函數(shù)裹粤,ThreadLocal
1蜂林、初始化
私有構(gòu)造函數(shù),如果構(gòu)造函數(shù)是共有的矮锈,那么Loop就滿天飛了苞笨,不能進(jìn)行控制子眶。
ThreadLocal,多線程粤咪,線程上下文的存儲變量寥枝。每一個線程都有一個ThreadLocalMap,里面有個如因信用的Entry鍵值對(ThreadLocal k,Object v)
ThreadLocal.set 先獲取當(dāng)前線程對應(yīng)的map,map.set(this,value);

一個線程只有一個Looper ,并且Looper是不能改的。為什么蝌麸?
因?yàn)橐粋€線程中只有一個ThreadLocalMap >> (this,value) this是唯一的threadLocal,所以value是唯一的艾疟,如何保證ThreadLocal/只對應(yīng)一個value
<key,value> set(key1,value1) set(key1,value2);
因?yàn)樵趐repare之前判斷一下
if(sThreadLocal.get() != null){
throw 異常.
}

2蔽莱、MessageQuenue屬于哪個線程
這個說法是錯誤的盗冷,只有執(zhí)行的函數(shù)才能說屬于哪個線程的。變量是可以共享的柑司。

Handler設(shè)計的亮點(diǎn)

面試題:
1锅劝、一個線程有幾個Handler?
無數(shù)個故爵,Handler機(jī)制只有一個
2、一個線程有幾個Looper?劲室,只有一個结窘,用過threadLocap和prepare 的 threadLocal,get來保證只能為一個線程設(shè)置一個Looper
3隧枫、Handler內(nèi)存泄露的原因?為什么其他的內(nèi)部類沒有說過這個問題?
static :
內(nèi)部類持有外部類的對象确买。
recycleView adpter ViewHolder 也是內(nèi)部類纱皆?
是生命周期的問題。
enqueueMessage{
msg.target = thiss;
}
Message持有了Handler ,Handler持有了Activity 铛楣,message可能會特定的時間后執(zhí)行艺普,那么message就不能被釋放歧譬,也就是Handler不能被釋放,Handler持有的Activity也不能被釋放矢洲,形成了內(nèi)存泄露读虏。

4袁滥、為啥主線程可以直接new Handler呻拌,子線程想要new Handler要干什么?
5靴拱、子線程中維護(hù)的Looper,消息隊列無消息的時候的處理方案是什么猾普,有什么用?
需要quit
涉及到初家,睡眠和喚醒。MessageQueue的等待和喚醒機(jī)制陌知。
Message的enqueueMessage沒有限制入隊的消息數(shù)量仆葡,因?yàn)檫@個MQ是大家公用的志笼。
MQ的輪詢?nèi)∠?如果沒有消息則會阻塞
這里的阻塞有兩個方面阻塞
1、如果取出的消息還沒有到要執(zhí)行的時刻韧掩,那就得阻塞
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);
}計算

循環(huán)一遍后從頭開始窖铡, nativePollOnce(ptr, nextPollTimeoutMillis);//睡眠執(zhí)行等待操作

2万伤、第二層等待
如果消息隊列為空敌买,
nextPollTimeoutMillis = -1;//標(biāo)識永久 等待,直到有人過來喚醒聋庵。
喚醒 if(needWake){
nativeWake(mPtr)
}


native層

最終是調(diào)用到了Linux層的epoll_wait來實(shí)現(xiàn)等待祭玉。

enquenueMessage

最終也是調(diào)用到了Linux層的脱货。
子線程的消息為空時一定要調(diào)用quit來退出:
quit:喚醒線程-->messageQuenue->null->退出loop

6振峻、既然可以存在多個Handler往MessageQueue中添加數(shù)據(jù)(發(fā)消息時各個Handler可能處于不同的線程择份,那么如何確保線程安全的荣赶?)
enqueueMessage會加synchronized:內(nèi)置鎖?為啥叫內(nèi)置鎖利诺,是由jvm完成剩燥,系統(tǒng)的。
可以鎖代碼塊,對象胜卤。

 boolean enqueueMessage(Message msg, long when) {
        if (msg.target == null) {
            throw new IllegalArgumentException("Message must have a target.");
        }
        synchronized (this) //只要是鎖了this赁项,其他的函數(shù)和方法都不能調(diào)用悠菜,都是等待狀態(tài)

一個線程只有一個可以操作MQ的地方,而這個地方又加了鎖摩窃,所以可以確保線程安全猾愿。
enqueueMessage next quit方法都要進(jìn)行加鎖蒂秘。

到底:Message:從子線程->>發(fā)送到主線程
首先淘太,內(nèi)存是沒有線程的
子線程:里面執(zhí)行的函數(shù)蒲牧,這個函數(shù)就在子線程里面
thread: handler.sendMessage(msg) -> MessageQueue.enqueMessage(msg) MessageQueue是一個容器。
主線程的Loop就會去輪詢主線程對應(yīng)的MessageQueue显熏,loop函數(shù)是在主線程調(diào)度喘蟆,所以在MessageQueue的next中會調(diào)用msg.target.dispatchMessage方法鼓鲁,調(diào)用handleMessage處理Message

static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>( );整個APP里面唯一骇吭,所有線程公用一個。
Looper線程唯一棘脐。

7蛀缝、Message如何創(chuàng)建
obtain 和 new
注意:在Looper的loop中取出一個msg
msg.target.dispatchMessage(msg);后并沒有直接return 而是 執(zhí)行msg.recycleUnchecked();對msg進(jìn)行回收,放到sPool中屈梁,
synchronized (sPoolSync) {
if (sPoolSize < MAX_POOL_SIZE) {
next = sPool;
sPool = this;
sPoolSize++;
}
}
在池子中插入一個msg,這個是防止oom在讶,和內(nèi)存抖動构哺。避免多次new造成,使得內(nèi)存碎片嚴(yán)重蝗碎,造成內(nèi)存抖動蹦骑,造成OOM臀防,注意new的內(nèi)存是連續(xù)的袱衷,如果內(nèi)存夠致燥,但是不連續(xù),所以要不斷回收辐益,無法回收就OOM了智政。
這種設(shè)計模式就用了享元設(shè)計模式箱蝠,內(nèi)存復(fù)用。

8劫拗、Looper的死循環(huán)為什么不會導(dǎo)致應(yīng)用卡死
ANR 點(diǎn)擊事件 5s:也就是一個點(diǎn)擊Message的處理事件超過5s,然后用handler發(fā)送一個ANR消息杨幼,提醒。ANR的優(yōu)先級高四瘫。
廣播10s 找蜜。
這個是無關(guān)的問題,因?yàn)檫@些點(diǎn)擊事件被封裝為Message弓叛,
MSG:為啥block不會導(dǎo)致ANR?
block 線程沒事做了撰筷,CPU讓出毕籽。

消息機(jī)制之同步屏障:架構(gòu)思維
我們都知道井辆,Android系統(tǒng)16ms會刷新一次屏幕杯缺,如果主線程的消息過多萍肆,在16ms之內(nèi)沒有執(zhí)行完,必然會造成卡頓或者掉幀蜡塌。那怎么才能不排隊勿负,沒有延時的處理呢馏艾?這個時候就需要異步消息劳曹,在處理異步消息的時候,我們就需要同步屏障琅摩,讓異步消息不用排隊等候處理铁孵。可以理解為同步屏障是一堵墻房资,把同步消息隊列攔住蜕劝,先處理異步消息,等異步消息處理完了岖沛,這堵墻就會取消,然后繼續(xù)處理同步消息Silly_Monkey原文鏈接搭独。

異步消息:立刻執(zhí)行
同步消息/普通消息: 放在MQ中執(zhí)行
消息時根據(jù)執(zhí)行時間進(jìn)行先后排序婴削,然后消息時保存在隊列中,因而消息只能從隊列的頭取出來牙肝,那么問題來了唉俗,那需要緊急處理的消息怎么辦?
msg.target = null 做一個標(biāo)志(這就是一個同步屏障)配椭;msg1 -> msg2 -> msg3-> msg4 ->
20: 第20個消息非常重要虫溜,必須馬上執(zhí)行。 如何去做股缸?如何確保立即執(zhí)行衡楞。
msg.target = null -> msg1 -> msg2 -> msg3-> msg4 ->

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());找到一個異步消息,退出處理同步消息乓序。
}

什么時候用到:就是在更新UI寺酪。
ViewRootImpl;
shceduleTraversalsf方法,調(diào)用MessageQueue得postSyncBarrier方法發(fā)送同步屏障和removeSyncBarrier方法移除同步屏障替劈。


    void scheduleTraversals() {
        if (!mTraversalScheduled) {
            mTraversalScheduled = true;
            mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();//發(fā)送同步屏障
            mChoreographer.postCallback(
                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);//發(fā)送異步消息
            if (!mUnbufferedInputDispatch) {
                scheduleConsumeBatchedInput();
            }
            notifyRendererOfFramePending();
            pokeDrawLockIfNeeded();
        }
    }

    private void postCallbackDelayedInternal(int callbackType,
            Object action, Object token, long delayMillis) {
        if (DEBUG_FRAMES) {
            Log.d(TAG, "PostCallback: type=" + callbackType
                    + ", action=" + action + ", token=" + token
                    + ", delayMillis=" + delayMillis);
        }

        synchronized (mLock) {
            final long now = SystemClock.uptimeMillis();
            final long dueTime = now + delayMillis;
            mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);

            if (dueTime <= now) {
                scheduleFrameLocked(now);
            } else {
                Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
                msg.arg1 = callbackType;
                msg.setAsynchronous(true);//UI更新消息是異步得
                mHandler.sendMessageAtTime(msg, dueTime);
            }
        }
    }

什么時候刪除同步屏障

    void unscheduleTraversals() {
        if (mTraversalScheduled) {
            mTraversalScheduled = false;
            mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
            mChoreographer.removeCallbacks(
                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
        }
    }

HandlerThread存在得意義

1寄雀、方便使用,方便初始化
2陨献、保證了線程得安全盒犹,解決有可能得異步問題。
如果不用眨业,HandlerThread急膀,那么我們要在使用Handler在子線程中處理消息,那么就需要在子線程得run方法創(chuàng)建Handler龄捡。

            public void run() {
                Looper.prepare();
                Handler handler = new Handler();
                Looper.loop();
            }

當(dāng)然卓嫂,也可以將子線程得Looper保存到子線程外部,用Handler(Looper)來創(chuàng)建Handler聘殖,但是把Looper放在外部,外部類持有Looper得引用晨雳,無法進(jìn)行釋放行瑞,可能導(dǎo)致內(nèi)存問題。

            public void run() {
                Looper.prepare();
                looper  = Looper.myLooper();
                Looper.loop();
            }

HandlerThread就是一個線程餐禁,不過在run方法中完了Looper得工作血久。

    @Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();//此時喚醒其他等待得鎖,但并不釋放鎖帮非,一定等到整個synchronized代碼塊執(zhí)行完了才釋放鎖氧吐。
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }

處理完任務(wù)>>service自動停止,內(nèi)存釋放末盔。

    /**
     * This method returns the Looper associated with this thread. If this thread not been started
     * or for any reason isAlive() returns false, this method will return null. If this thread
     * has been started, this method will block until the looper has been initialized.  
     * @return The looper.
     */
    public Looper getLooper() {
        if (!isAlive()) {
            return null;
        }
        
        // If the thread has been started, wait until the looper has been created.
        synchronized (this) {
            while (isAlive() && mLooper == null) {
                try {
                    wait();//發(fā)現(xiàn)Looper沒有創(chuàng)建完成有人想要獲取looper筑舅,等待,釋放鎖陨舱,wait();synchronized什么關(guān)系
//notifyall 釋放鎖嗎豁翎?
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }

IntentService

抽象類,子類繼承并實(shí)現(xiàn)onHandleIntent來處理耗時任務(wù)隅忿。
Handler得應(yīng)用
Service 處理后臺任務(wù)
一般new Thread處理任務(wù),而在IntenService中邦尊,onCreate方法里面創(chuàng)建了HandlerThread和一個ServiceHandler,在onStart方法中

    @Override
    public void onStart(@Nullable Intent intent, int startId) {
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        mServiceHandler.sendMessage(msg);
    }
 private final class ServiceHandler extends Handler {
        public ServiceHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            onHandleIntent((Intent)msg.obj);執(zhí)行任務(wù)
            stopSelf(msg.arg1);自殺背桐,關(guān)閉Service
        }
    }

應(yīng)用需求:一項(xiàng)任務(wù)分為幾個子任務(wù),等子任務(wù)全部完成后蝉揍,這項(xiàng)任務(wù)才算完成链峭,
這個需求可以用多線程來處理,一個線程處理完 -->下一個-->下一個又沾。

IntentService就可以幫我們完成這個工作弊仪,而且,能夠很好得管理線程杖刷,保證只有一個子線程處理工作励饵,而且是一個一個得完成任務(wù),有條不紊滑燃。

到底還有別的地方在用嗎役听?
fragment生命周期管理
如何保證attach先執(zhí)行FragmentPagerAdapter
mCurTransaction.attach(fragment); mCurTransaction.detach((Fragment)object);

Glide生命周期管理
Handler loop休眠為什么不會導(dǎo)致ANR
Messagequeue隊列處理機(jī)制,在fragment生命周期管理中的應(yīng)用

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末表窘,一起剝皮案震驚了整個濱河市典予,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌乐严,老刑警劉巖瘤袖,帶你破解...
    沈念sama閱讀 222,104評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異昂验,居然都是意外死亡捂敌,警方通過查閱死者的電腦和手機(jī)艾扮,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來黍匾,“玉大人栏渺,你說我怎么就攤上這事∪裱模” “怎么了磕诊?”我有些...
    開封第一講書人閱讀 168,697評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長纹腌。 經(jīng)常有香客問我霎终,道長,這世上最難降的妖魔是什么升薯? 我笑而不...
    開封第一講書人閱讀 59,836評論 1 298
  • 正文 為了忘掉前任莱褒,我火速辦了婚禮,結(jié)果婚禮上涎劈,老公的妹妹穿的比我還像新娘广凸。我一直安慰自己,他們只是感情好蛛枚,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,851評論 6 397
  • 文/花漫 我一把揭開白布谅海。 她就那樣靜靜地躺著,像睡著了一般蹦浦。 火紅的嫁衣襯著肌膚如雪扭吁。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,441評論 1 310
  • 那天盲镶,我揣著相機(jī)與錄音侥袜,去河邊找鬼。 笑死溉贿,一個胖子當(dāng)著我的面吹牛枫吧,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播顽照,決...
    沈念sama閱讀 40,992評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼由蘑,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了代兵?” 一聲冷哼從身側(cè)響起尼酿,我...
    開封第一講書人閱讀 39,899評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎植影,沒想到半個月后裳擎,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,457評論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡思币,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,529評論 3 341
  • 正文 我和宋清朗相戀三年鹿响,在試婚紗的時候發(fā)現(xiàn)自己被綠了羡微。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,664評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡惶我,死狀恐怖妈倔,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情绸贡,我是刑警寧澤盯蝴,帶...
    沈念sama閱讀 36,346評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站听怕,受9級特大地震影響捧挺,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜尿瞭,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,025評論 3 334
  • 文/蒙蒙 一闽烙、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧声搁,春花似錦黑竞、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至充石,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間霞玄,已是汗流浹背骤铃。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留坷剧,地道東北人惰爬。 一個月前我還...
    沈念sama閱讀 49,081評論 3 377
  • 正文 我出身青樓,卻偏偏與公主長得像惫企,于是被迫代替她去往敵國和親撕瞧。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,675評論 2 359

推薦閱讀更多精彩內(nèi)容

  • 背景 Handler是android中比較重要的機(jī)制狞尔,是日常開發(fā)中也會經(jīng)常遇到丛版。另外,也是面試過程中必問的問題之一...
    小吵鬧123閱讀 161評論 0 0
  • Handler 發(fā)送(延時)/接收/處理消息 1.UI線程更新 2.主/子線程通信 主要的幾個類...
    水妖閱讀 112評論 0 0
  • 剛開始學(xué)習(xí)Android的時候偏序,知道異步線程無法更新UI页畦,于是找了個能把更新的動作拋給UI線程的東西,這個東西就是...
    DoubleYouJiang閱讀 160評論 0 0
  • 本著針對面試研儒,不負(fù)責(zé)任的態(tài)度豫缨,寫下《面試總結(jié)》系列独令。本系列記錄面試過程中各個知識點(diǎn),而不是入門系列好芭,如果有不懂的自...
    DB_BOY閱讀 1,086評論 6 9
  • 1,handler 機(jī)制中燃箭,存在哪些角色?各自承擔(dān)了什么功能舍败? 1.Handler :消息輔助類& 對外的接口& ...
    戲先生閱讀 568評論 0 6