Android組件_Handler Looper Message理解

Android組件_Handler Looper Message理解

一半哟、Handler機(jī)制概述

Handler機(jī)制是Android中一種消息處理機(jī)制。
主要組成或重要概念:

  1. Message,線程間通訊的數(shù)據(jù)單元。
  2. Message Queue,消息隊(duì)列拣挪,用來存放Handler發(fā)布的消息擦酌,按照FIFO執(zhí)行俱诸。
  3. Handler是Message的主要處理者,負(fù)責(zé)將Message添加到消息隊(duì)列意見對消息隊(duì)列中的Message進(jìn)行處理赊舶。
  4. Looper循環(huán)器睁搭,循環(huán)去除Message Queue里面的Message,并交付給相應(yīng)的Handler進(jìn)行處理笼平。
  5. Thread UI thread通常就是main thread园骆,Android啟動(dòng)程序時(shí)會(huì)替它建立一個(gè)Message Queue。
    每一個(gè)線程里可以含有一個(gè)Looper對象以及MessageQueue數(shù)據(jù)結(jié)構(gòu)寓调。
  6. ThreadLocal 他的作用是幫助Handler獲得當(dāng)前線程的Looper(多個(gè)線程可能有多個(gè)Looper)

二锌唾、使用場景

  1. 我們常常用Handler來更新UI,但是不是說Handler就是把用來更新UI的,耗時(shí)的I/O操作晌涕,讀取文件滋捶,訪問網(wǎng)絡(luò)等等都是可以在Handler里面操作的。

  2. 子線程間通訊余黎,可以在一個(gè)子線程中去創(chuàng)建一個(gè)Handler重窟,然后使用這個(gè)handler實(shí)例在任何其他線程中發(fā)送消息,最終處理消息的代碼都會(huì)在你創(chuàng)建Handler實(shí)例的線程中運(yùn)行惧财。

  3. 延時(shí)任務(wù)等

三巡扇、使用方法

3.1. 子線程線程里更新UI

public class MainActivity extends AppCompatActivity {
    //主線程中的handler
    Handler mHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            //獲得剛才發(fā)送的Message對象,然后在這里進(jìn)行UI操作
            Log.e(TAG,"------------> msg.what = " + msg.what);
            ...
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //在子線程中發(fā)送更新消息給主線程的handler去更新UI
        new Thread(new Runnable() {
            @Override
            public void run() {
                Message m = mHandler.obtainMessage();
                ...
                mHandler.sendMessage(m);
            }
        }).start();
    }
}

3.2 子線程間通信

        final Handler[] h = new Handler[1];
        new Thread(new Runnable() {
            @Override
            public void run() {
                Looper.prepare();//創(chuàng)建子線程的looper垮衷,子線程使用handler消息傳遞厅翔,這一步必須要有,因?yàn)槟J(rèn)的子線程是沒有Looper對象的
                h[0] = new Handler() {
                    @Override
                    public void handleMessage(Message msg) {
                        super.handleMessage(msg);
                        Log.e(TAG,"------------> msg.what = " + msg.what);
                    }
                };
                Looper.loop();//消息池消息循環(huán)處理
            }
        }, "work1").start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                Message msg = h[0].obtainMessage();
                //msg.sendToTarget();
                h[0].sendEmptyMessage(0);//在work2子線程中使用持有work1子線程looper的handler發(fā)送消息至work1中去做消息處理
            }
        }, "work2").start();

3.3 HandlerThread使用

    {
        MyHandlerThread mHandlerThread = new MyHandlerThread("work");
        Handler mHandler = new Handler(mHandlerThread.getLooper()){//將該mHandler與HandlerThread對象的Looper關(guān)聯(lián)起來
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
            }
        };
    }

    MyHandlerThread mHandlerThread = new MyHandlerThread("work");
        Handler mHandler = new Handler(mHandlerThread.getLooper()){
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
            }
        };
    }

3.4 Handler CallBack參數(shù)使用
在構(gòu)造Handler對象的時(shí)候可以穿入CallBack參數(shù)搀突,如下

//主線程:
  Handler handler = new Handler(new Handler.Callback() {
        @Override
        public boolean handleMessage(Message msg) {
            return false;
        }
    });
//其他線程中:
handler.sendMessageXXX(msg);

3.5 Handler post方法使用

    //主線程中創(chuàng)建mPostHandler
    Handler mPostHandler = new Handler();
    //子線程中使用post方法
     new Thread(new Runnable() {
            @Override
            public void run() {
               /* Message m = mHandler.obtainMessage();
                mHandler.sendMessage(m);*/
                mPostHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        //更新UI 知给,注意這里雖然操作寫在子線程中,事實(shí)運(yùn)行時(shí)是在主線程中描姚,原因分析在4.2.5中
                    }
                });
            }
        }).start();

3.6 Handler 延時(shí)任務(wù)/循環(huán)定時(shí)操作

延時(shí)任務(wù)
new Handler().postDelayed(new Runnable(){   
            public void run() {  
                   //show dialog
            }  
  }, 5000);  //延時(shí)5秒后執(zhí)行runnable run方法
循環(huán)定時(shí)操作:
1涩赢,首先創(chuàng)建一個(gè)Handler對象  
 Handler handler=new Handler();  

2,然后創(chuàng)建一個(gè)Runnable對
Runnable runnable=new Runnable(){  
   @Override  
   public void run() {  
    // TODO Auto-generated method stub  
    //要做的事情轩勘,這里再次調(diào)用此Runnable對象筒扒,以實(shí)現(xiàn)每兩秒實(shí)現(xiàn)一次的定時(shí)器操作  
    handler.postDelayed(this, 2000);  
   }  
};  

3,使用PostDelayed方法绊寻,兩秒后調(diào)用此Runnable對象  
handler.postDelayed(runnable, 2000);  

4花墩,如果想要關(guān)閉此定時(shí)器,可以這樣操作
handler.removeCallbacks(runnable); 

四澄步、原理分析

Handler機(jī)制的鐵三角-Handler冰蘑、Looper和MessageQueue,另外還有下面進(jìn)行淺入分析村缸。
整體架構(gòu) :

image.png

4.1 主線程Handler對象與主線程Looper對象關(guān)聯(lián)

對3.1中的例子進(jìn)行淺入的分析祠肥。

4.1.1 Handler對象初始化獲取主線程的Looper對象

1.主線程Handler對象初始化:

Handler mHandler = new Handler(){...}

默認(rèn)的構(gòu)造函數(shù)會(huì)將該Handler對象與當(dāng)前線程的Looper對象關(guān)聯(lián)。下面我們看下構(gòu)造函數(shù)是如何關(guān)聯(lián)上當(dāng)前線程的looper的梯皿。
Handler的默認(rèn)構(gòu)造函數(shù):

frameworks/base/core/java/android/os/Handler.java
    public Handler() {
        this(callback:null, async:false);
    }

2.如果該線程沒有l(wèi)ooper對象仇箱,該handler將拋異常:

    public Handler(Callback callback, boolean async) {
        ...
        mLooper = Looper.myLooper();//
        if (mLooper == null) {//如果當(dāng)前線程沒有Looper對象將拋出異常
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

3.sThreadLocal對象中保存著當(dāng)前線程的looper對象,Looper.myLooper()即用來獲取當(dāng)前線程的Looper對象:

frameworks/base/core/java/android/os/Looper.java
    public static @Nullable Looper myLooper() {
        return sThreadLocal.get();//這里獲取當(dāng)前線程的Looper對象
    }

4.1.2 主線程初始化時(shí)創(chuàng)建Looper對象及MessageQueue對象

1.對于UI線程即我們所說的Main線程及ActivityThread,在ActivityThread創(chuàng)建的時(shí)候东羹,main函數(shù)中創(chuàng)建了Looper對象剂桥,并通過Looper.loop()是主線程進(jìn)入消息循環(huán)中:

frameworks/base/core/java/android/app/ActivityThread.java
    public static void main(String[] args) {
        ...
        Looper.prepareMainLooper(); //創(chuàng)建主線程Looper對象

        ActivityThread thread = new ActivityThread();
        thread.attach(false);

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }
        ...
        Looper.loop();//不斷循環(huán)處理MessageQueue中的消息
        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

2.Looper.prepareMainLooper()創(chuàng)建主線程的Looper以及MessageQueue,并通過Looper.loop()來開啟主線程的消息循環(huán):

frameworks/base/core/java/android/os/Looper.java
    public static void prepareMainLooper() {
        prepare(false);//創(chuàng)建Looper對象属提,并且將新建的looper對象與當(dāng)前線程關(guān)聯(lián)
        synchronized (Looper.class) {
            if (sMainLooper != null) { //可以看出主線程應(yīng)該只有一個(gè)Looper對象
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();//返回當(dāng)前線程的Looper對象
        }
    }

3.Looper.prepare()函數(shù)為當(dāng)前線程(此處為主線程权逗,也可以是其他線程)創(chuàng)建Looper對象,并將該對象設(shè)置至線程的sThreadLocal變量中:

  private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) { // 說明prepare不能調(diào)用兩次,否則會(huì)拋出異常斟薇,保證一個(gè)線程只有一個(gè)Looper實(shí)例
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));//sThreadLocal是一個(gè)ThreadLocal對象火惊,可以在一個(gè)線程中存儲(chǔ)變量。
    }

4.Looper.myLooper()返回當(dāng)前線程的Looper對象奔垦,這里也就驗(yàn)證了myLooper()的確是從sThreadLocal變量中獲取了當(dāng)前線程的Looper對象屹耐。

    public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }

概述一下就是,主線程在初始化時(shí)就生成了含有一個(gè)不可退出的MessageQueue的Looper對象椿猎,并將該Looper對象保存在主線程的sThreadLocal變量中惶岭;
當(dāng)在主線程中創(chuàng)建Handler對象時(shí),會(huì)將該Handler對象與當(dāng)前線程的sThreadLocal變量中保存的主線程Looper對象關(guān)聯(lián)起來犯眠。
因此按灶,在上面3.1的例子中,主線程new一個(gè)Handler對象時(shí)會(huì)將該Handler對象與主線程中的Looper對象關(guān)聯(lián)筐咧,執(zhí)行Looper.loop()不斷循環(huán)處理消息鸯旁;

4.2 Handler、Looper量蕊、Message及HandlerThread淺析

4.2.1 Handler

1.可以使用的方法

post(Runnable)
postAtTime(Runnable,long)
postDelayed(Runnable long)
sendEmptyMessage(int)
sendMessage(Message)
sendMessageDelayed(Message,long)
sendMessageAtTime(Message,long) 

2.以上方法都最終都將調(diào)用sendMessageAtTime(),將消息加入msg的目標(biāo)Handler對象關(guān)聯(lián)的Looper持有的消息隊(duì)列中铺罢,之后就是排隊(duì)消息隊(duì)列循環(huán)處理消息了:

    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); //將該消息加入該消息的目標(biāo)handler關(guān)聯(lián)的looper中的消息隊(duì)列中
    }

4.2.2 Looper:

1.Looper構(gòu)造函數(shù),看到Looper的構(gòu)造函數(shù)里新建了一個(gè)MessageQueue對象:

    private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);//創(chuàng)建消息隊(duì)列
        mThread = Thread.currentThread();
    }

2.Looper.loop(),循環(huán)處理消息隊(duì)列中消息的函數(shù):

    /**
     * Run the message queue in this thread. Be sure to call
     * {@link #quit()} to end the loop.
     */
    public static void loop() {
        ...
        // Make sure the identity of this thread is that of the local process,
        // and keep track of what that identity token actually is.
        Binder.clearCallingIdentity();
        final long ident = Binder.clearCallingIdentity();

        for (;;) {
            Message msg = queue.next(); // might block残炮,若無消息則會(huì)阻塞在這里韭赘。
            ...
            try {
                msg.target.dispatchMessage(msg); //調(diào)用發(fā)該message的handler的dispatchMessage方法;
            } finally {
            }
            ...
            msg.recycleUnchecked();//處理完的msg可以進(jìn)行回收势就,實(shí)現(xiàn)的地方清除了該msg對象的內(nèi)容泉瞻,并將其保留在消息池中,以供循環(huán)使用            
        }
    }

3.在dispatchMessage中進(jìn)行消息處理苞冯,post方法中的runnable就是這里的msg.callback

frameworks/base/core/java/android/os/Handler.java
    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg); //執(zhí)行post方法中的runnable方法
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) { //如果創(chuàng)建handler時(shí)有傳入callback的話
                    return;
                }
            }
            handleMessage(msg);//創(chuàng)建handler時(shí)需復(fù)寫方法handleMessage(),處理消息
        }
    }

3.1首先會(huì)判斷msg.callback存不存在袖牙,msg.callback是Runnable類型,如果msg.callback存在舅锄,那么說明該Message是通過執(zhí)行Handler的postXXX系列方法將Message放入到消息隊(duì)列中的鞭达,這種情況下會(huì)執(zhí)行handleCallback(msg), handleCallback源碼如下:

private static void handleCallback(Message message) {
  message.callback.run();
}

這樣我們我們就清楚地看到我們執(zhí)行了msg.callback的run方法,也就是執(zhí)行了postXXX所傳遞的Runnable對象的run方法巧娱。
3.2.如果我們不是通過postXXX系列方法將Message放入到消息隊(duì)列中的碉怔,那么msg.callback就是null,代碼繼續(xù)往下執(zhí)行禁添,接著我們會(huì)判斷Handler的成員字段mCallback存不存在。mCallback是Hanlder.Callback類型的桨踪,我們在上面提到過老翘,在Handler的構(gòu)造函數(shù)中我們可以傳遞Hanlder.Callback類型的對象,該對象需要實(shí)現(xiàn)handleMessage方法,如果我們在構(gòu)造函數(shù)中傳遞了該Callback對象铺峭,那么我們就會(huì)讓Callback的handleMessage方法來處理Message墓怀。
3.3.如果我們在構(gòu)造函數(shù)中沒有傳入Callback類型的對象,那么mCallback就為null,那么我們會(huì)調(diào)用Handler自身的hanldeMessage方法卫键,該方法默認(rèn)是個(gè)空方法傀履,我們需要自己是重寫實(shí)現(xiàn)該方法。
綜上莉炉,我們可以看到Handler提供了三種途徑處理Message钓账,而且處理有前后優(yōu)先級(jí)之分:首先嘗試讓postXXX中傳遞的Runnable執(zhí)行,其次嘗試讓Handler構(gòu)造函數(shù)中傳入的Callback的handleMessage方法處理絮宁,最后才是讓Handler自身的handleMessage方法處理Message梆暮。

4.2.3 MessageQueue

1 MessageQueue的next()方法
在消息隊(duì)列中不斷取出消息,next方法是個(gè)無限循環(huán)的方法绍昂,如果有消息返回這條消息并從鏈表中移除啦粹,而沒有消息則一直阻塞在這里。

Message next() {
        for (;;) {
            synchronized (this) {
                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) {
                    ...
                        // Got a message.
                        mBlocked = false;
                        if (prevMsg != null) {
                            prevMsg.next = msg.next;
                        } else {
                            mMessages = msg.next;
                        }
                        msg.next = null;
                        msg.markInUse();
                        return msg;
                    }
                } 
        }
    }

4.2.4 HandlerThread

1.自帶Looper的Thread:

frameworks/base/core/java/android/os/HandlerThread.java
public class HandlerThread extends Thread {
@Override
    public void run() {
        ...
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        onLooperPrepared();
        Looper.loop();
        ...
    }
}

我們看到HandlerThread繼承自Thread窘游,并且在run函數(shù)中使用Looper.prepare()為使用線程創(chuàng)建了一個(gè)Looper對象唠椭,并且把該對象放到了該線程范圍內(nèi)的變量中(sThreadLocal);在Looper對象的構(gòu)造過程中忍饰,初始化了一個(gè)MessageQueue泪蔫,作為該Looper對象成員變量;loop()開啟了喘批,不斷的循環(huán)從MessageQueue中取消息處理了撩荣,當(dāng)沒有消息的時(shí)候會(huì)阻塞,有消息的到來的時(shí)候會(huì)喚醒饶深。
因此也可以使用HandlerThread餐曹,這樣可以不用像普通線程那樣需要Looper.prepare()和Looper.loop(),因?yàn)镠andlerThread為我們做好了準(zhǔn)備工作敌厘;

2.另外可以通過HandlerThread的getLooper方法獲的該HandlerThread的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();
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }

handleMessage

4.2.5 Handler中post方法

3.5中的例子中子線程中post中的run方法運(yùn)行在主線程中台猴,原因分析如下:
1.傳入Runnable對象

public final boolean post(Runnable r)
    {
       return  sendMessageDelayed(getPostMessage(r), 0);
    }

2.這里將Runnable封裝到一個(gè)Message對象中

  private static Message getPostMessage(Runnable r) {
        Message m = Message.obtain();
        m.callback = r; //將runnable傳入message對象中的callback變量中
        return m;
    }

3.之后與普通的handler sendMessage方法流程一致,調(diào)用用sendMessageAtTime俱两,將該消息加入該消息的目標(biāo)handler饱狂,及mPostHandler關(guān)聯(lián)的looper中的消息隊(duì)列中,如何處理在4.2.1 中有提到過宪彩。

  public final boolean sendMessageDelayed(Message msg, long delayMillis)
    {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }

也就是說休讳,雖然runnable復(fù)寫方法在子線程中,但是同樣是封裝成message對象傳入主線程的looper持有的MessageQueue對象中尿孔,在主線程中對封裝了runnable變量的message進(jìn)行消息執(zhí)行處理俊柔,因此post中的run方法是運(yùn)行在主線程中的筹麸。

五、注意事項(xiàng)

  1. Handler在處理消息需要嚴(yán)格區(qū)分是否是在UI線程中雏婶,Handler一般用在非UI線程中來傳遞消息物赶,在非UI線程中使用Handler來發(fā)送消息,消息
    處理會(huì)被嚴(yán)格執(zhí)行留晚,但如果在UI線程中使用Handler來發(fā)送消息酵紫,相同的消息在內(nèi)部會(huì)被合并,且執(zhí)行時(shí)序也得不到保證
  2. 因?yàn)镠andlerThread擁有自己的消息隊(duì)列错维,它不會(huì)干擾或阻塞UI線程奖地,比較合適處理那些需要花費(fèi)時(shí)間偏長的任務(wù)。我們只需要把任務(wù)發(fā)送給HandlerThread需五,然后就只需要等待任務(wù)執(zhí)行結(jié)束的時(shí)候通知返回到主線程就好了鹉动。
  3. android中handler使用應(yīng)該注意的由handler引起的OOM內(nèi)存泄漏) http://blog.csdn.net/javazejian/article/details/50839443
  4. 在普通線程中使用機(jī)制時(shí)要記得先Looper.prepare(); 最后還要Looper.loop();
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市宏邮,隨后出現(xiàn)的幾起案子泽示,更是在濱河造成了極大的恐慌,老刑警劉巖蜜氨,帶你破解...
    沈念sama閱讀 206,839評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件械筛,死亡現(xiàn)場離奇詭異,居然都是意外死亡飒炎,警方通過查閱死者的電腦和手機(jī)埋哟,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來郎汪,“玉大人赤赊,你說我怎么就攤上這事∩酚” “怎么了抛计?”我有些...
    開封第一講書人閱讀 153,116評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長照筑。 經(jīng)常有香客問我吹截,道長,這世上最難降的妖魔是什么凝危? 我笑而不...
    開封第一講書人閱讀 55,371評(píng)論 1 279
  • 正文 為了忘掉前任波俄,我火速辦了婚禮,結(jié)果婚禮上蛾默,老公的妹妹穿的比我還像新娘懦铺。我一直安慰自己,他們只是感情好趴生,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評(píng)論 5 374
  • 文/花漫 我一把揭開白布阀趴。 她就那樣靜靜地躺著昏翰,像睡著了一般苍匆。 火紅的嫁衣襯著肌膚如雪刘急。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,111評(píng)論 1 285
  • 那天浸踩,我揣著相機(jī)與錄音叔汁,去河邊找鬼。 笑死检碗,一個(gè)胖子當(dāng)著我的面吹牛据块,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播折剃,決...
    沈念sama閱讀 38,416評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼另假,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了怕犁?” 一聲冷哼從身側(cè)響起边篮,我...
    開封第一講書人閱讀 37,053評(píng)論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎奏甫,沒想到半個(gè)月后戈轿,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,558評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡阵子,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評(píng)論 2 325
  • 正文 我和宋清朗相戀三年思杯,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片挠进。...
    茶點(diǎn)故事閱讀 38,117評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡色乾,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出领突,到底是詐尸還是另有隱情暖璧,我是刑警寧澤,帶...
    沈念sama閱讀 33,756評(píng)論 4 324
  • 正文 年R本政府宣布攘须,位于F島的核電站漆撞,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏于宙。R本人自食惡果不足惜浮驳,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望捞魁。 院中可真熱鬧至会,春花似錦、人聲如沸谱俭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至县貌,卻和暖如春术陶,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背煤痕。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評(píng)論 1 262
  • 我被黑心中介騙來泰國打工梧宫, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人摆碉。 一個(gè)月前我還...
    沈念sama閱讀 45,578評(píng)論 2 355
  • 正文 我出身青樓塘匣,卻偏偏與公主長得像,于是被迫代替她去往敵國和親巷帝。 傳聞我的和親對象是個(gè)殘疾皇子忌卤,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評(píng)論 2 345

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