Android中AsyncTask使用詳解

Android中我們可以通過Thread+Handler實(shí)現(xiàn)多線程通信霞揉,一種經(jīng)典的使用場景是:在新線程中進(jìn)行耗時操作工闺,當(dāng)任務(wù)完成后通過Handler向主線程發(fā)送Message表锻,這樣主線程的Handler在收到該Message之后就可以進(jìn)行更新UI的操作别渔。上述場景中需要分別在Thread和Handler中編寫代碼邏輯巍虫,為了使得代碼更加統(tǒng)一,我們可以使用AsyncTask類吆豹。
AsyncTask是Android提供的一個助手類忧勿,它對Thread和Handler進(jìn)行了封裝杉女,方便我們使用。Android之所以提供AsyncTask這個類鸳吸,就是為了方便我們在后臺線程中執(zhí)行操作熏挎,然后將結(jié)果發(fā)送給主線程,從而在主線程中進(jìn)行UI更新等操作晌砾。在使用AsyncTask時坎拐,我們無需關(guān)注Thread和Handler,AsyncTask內(nèi)部會對其進(jìn)行管理养匈,這樣我們就只需要關(guān)注于我們的業(yè)務(wù)邏輯即可哼勇。
AsyncTask有四個重要的回調(diào)方法,分別是:onPreExecute呕乎、doInBackground, onProgressUpdate 和 onPostExecute积担。這四個方法會在AsyncTask的不同時期進(jìn)行自動調(diào)用,我們只需要實(shí)現(xiàn)這幾個方法的內(nèi)部邏輯即可猬仁。這四個方法的一些參數(shù)和返回值都是基于泛型的帝璧,而且泛型的類型還不一樣,所以在AsyncTask的使用中會遇到三種泛型參數(shù):Params, Progress 和 Result湿刽,如下圖所示:

  • Params表示用于AsyncTask執(zhí)行任務(wù)的參數(shù)的類型
  • Progress表示在后臺線程處理的過程中晤郑,可以階段性地發(fā)布結(jié)果的數(shù)據(jù)類型
  • Result表示任務(wù)全部完成后所返回的數(shù)據(jù)類型

我們通過調(diào)用AsyncTask的execute()方法傳入?yún)?shù)并執(zhí)行任務(wù)戳晌,然后AsyncTask會依次調(diào)用以下四個方法:

  • onPreExecute

該方法的簽名如下所示:


該方法有MainThread注解骑脱,表示該方法是運(yùn)行在主線程中的厂镇。在AsyncTask執(zhí)行了execute()方法后就會在UI線程上執(zhí)行onPreExecute()方法,該方法在task真正執(zhí)行前運(yùn)行雅镊,我們通辰罄祝可以在該方法中顯示一個進(jìn)度條,從而告知用戶后臺任務(wù)即將開始仁烹。

  • doInBackground

該方法的簽名如下所示:



該方法有WorkerThread注解耸弄,表示該方法是運(yùn)行在單獨(dú)的工作線程中的,而不是運(yùn)行在主線程中晃危。doInBackground會在onPreExecute()方法執(zhí)行完成后立即執(zhí)行叙赚,該方法用于在工作線程中執(zhí)行耗時任務(wù)老客,我們可以在該方法中編寫我們需要在后臺線程中運(yùn)行的邏輯代碼僚饭,由于是運(yùn)行在工作線程中,所以該方法不會阻塞UI線程胧砰。該方法接收Params泛型參數(shù)鳍鸵,參數(shù)params是Params類型的不定長數(shù)組,該方法的返回值是Result泛型尉间,由于doInBackgroud是抽象方法偿乖,我們在使用AsyncTask時必須重寫該方法击罪。在doInBackground中執(zhí)行的任務(wù)可能要分解為好多步驟,每完成一步我們就可以通過調(diào)用AsyncTask的publishProgress(Progress…)將階段性的處理結(jié)果發(fā)布出去贪薪,階段性處理結(jié)果是Progress泛型類型媳禁。當(dāng)調(diào)用了publishProgress方法后,處理結(jié)果會被傳遞到UI線程中画切,并在UI線程中回調(diào)onProgressUpdate方法竣稽,下面會詳細(xì)介紹。根據(jù)我們的具體需要霍弹,我們可以在doInBackground中不調(diào)用publishProgress方法毫别,當(dāng)然也可以在該方法中多次調(diào)用publishProgress方法。doInBackgroud方法的返回值表示后臺線程完成任務(wù)之后的結(jié)果典格。

  • onProgressUpdate

上面我們知道岛宦,當(dāng)我們在doInBackground中調(diào)用publishProgress(Progress…)方法后,就會在UI線程上回調(diào)onProgressUpdate方法耍缴,該方法的方法簽名如下所示:



該方法也具有MainThread注解砾肺,表示該方法是在主線程上被調(diào)用的,且傳入的參數(shù)是Progress泛型定義的不定長數(shù)組私恬。如果在doInBackground中多次調(diào)用了publishProgress方法债沮,那么主線程就會多次回調(diào)onProgressUpdate方法。

  • onPostExecute

該方法的簽名如下所示:



該方法也具有MainThread注解本鸣,表示該方法是在主線程中被調(diào)用的疫衩。當(dāng)doInBackgroud方法執(zhí)行完畢后,就表示任務(wù)完成了荣德,doInBackgroud方法的返回值就會作為參數(shù)在主線程中傳入到onPostExecute方法中闷煤,這樣就可以在主線程中根據(jù)任務(wù)的執(zhí)行結(jié)果更新UI。

下面我們就以下載多個文件的示例演示AsyncTask的使用過程涮瞻。

布局文件如下所示:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    tools:context=".MainActivity">

    <Button android:id="@+id/btnDownload"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="onClick"
        android:text="開始下載" />

    <TextView android:id="@+id/textView"
        android:layout_below="@id/btnDownload"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</RelativeLayout>

界面上有一個“開始下載”的按鈕鲤拿,點(diǎn)擊該按鈕即可通過AsyncTask下載多個文件,對應(yīng)的Java代碼如下所示:

package com.ispring.asynctask;

import android.app.Activity;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

public class MainActivity extends Activity implements Button.OnClickListener {

    TextView textView = null;
    Button btnDownload = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView = (TextView)findViewById(R.id.textView);
        btnDownload = (Button)findViewById(R.id.btnDownload);
        Log.i("iSpring", "MainActivity -> onCreate, Thread name: " + Thread.currentThread().getName());
    }

    @Override
    public void onClick(View v) {
        //要下載的文件地址
        String[] urls = {
                "http://blog.csdn.net/iispring/article/details/47115879",
                "http://blog.csdn.net/iispring/article/details/47180325",
                "http://blog.csdn.net/iispring/article/details/47300819",
                "http://blog.csdn.net/iispring/article/details/47320407",
                "http://blog.csdn.net/iispring/article/details/47622705"
        };

        DownloadTask downloadTask = new DownloadTask();
        downloadTask.execute(urls);
    }

    //public abstract class AsyncTask<Params, Progress, Result>
    //在此例中署咽,Params泛型是String類型近顷,Progress泛型是Object類型,Result泛型是Long類型
    private class DownloadTask extends AsyncTask<String, Object, Long> {
        @Override
        protected void onPreExecute() {
            Log.i("iSpring", "DownloadTask -> onPreExecute, Thread name: " + Thread.currentThread().getName());
            super.onPreExecute();
            btnDownload.setEnabled(false);
            textView.setText("開始下載...");
        }

        @Override
        protected Long doInBackground(String... params) {
            Log.i("iSpring", "DownloadTask -> doInBackground, Thread name: " + Thread.currentThread().getName());
            //totalByte表示所有下載的文件的總字節(jié)數(shù)
            long totalByte = 0;
            //params是一個String數(shù)組
            for(String url: params){
                //遍歷Url數(shù)組宁否,依次下載對應(yīng)的文件
                Object[] result = downloadSingleFile(url);
                int byteCount = (int)result[0];
                totalByte += byteCount;
                //在下載完一個文件之后窒升,我們就把階段性的處理結(jié)果發(fā)布出去
                publishProgress(result);
                //如果AsyncTask被調(diào)用了cancel()方法,那么任務(wù)取消慕匠,跳出for循環(huán)
                if(isCancelled()){
                    break;
                }
            }
            //將總共下載的字節(jié)數(shù)作為結(jié)果返回
            return totalByte;
        }

        //下載文件后返回一個Object數(shù)組:下載文件的字節(jié)數(shù)以及下載的博客的名字
        private Object[] downloadSingleFile(String str){
            Object[] result = new Object[2];
            int byteCount = 0;
            String blogName = "";
            HttpURLConnection conn = null;
            try{
                URL url = new URL(str);
                conn = (HttpURLConnection)url.openConnection();
                InputStream is = conn.getInputStream();
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                byte[] buf = new byte[1024];
                int length = -1;
                while ((length = is.read(buf)) != -1) {
                    baos.write(buf, 0, length);
                    byteCount += length;
                }
                String respone = new String(baos.toByteArray(), "utf-8");
                int startIndex = respone.indexOf("<title>");
                if(startIndex > 0){
                    startIndex += 7;
                    int endIndex = respone.indexOf("</title>");
                    if(endIndex > startIndex){
                        //解析出博客中的標(biāo)題
                        blogName = respone.substring(startIndex, endIndex);
                    }
                }
            }catch(MalformedURLException e){
                e.printStackTrace();
            }catch(IOException e){
                e.printStackTrace();
            }finally {
                if(conn != null){
                    conn.disconnect();
                }
            }
            result[0] = byteCount;
            result[1] = blogName;
            return result;
        }

        @Override
        protected void onProgressUpdate(Object... values) {
            Log.i("iSpring", "DownloadTask -> onProgressUpdate, Thread name: " + Thread.currentThread().getName());
            super.onProgressUpdate(values);
            int byteCount = (int)values[0];
            String blogName = (String)values[1];
            String text = textView.getText().toString();
            text += "\n博客《" + blogName + "》下載完成饱须,共" + byteCount + "字節(jié)";
            textView.setText(text);
        }

        @Override
        protected void onPostExecute(Long aLong) {
            Log.i("iSpring", "DownloadTask -> onPostExecute, Thread name: " + Thread.currentThread().getName());
            super.onPostExecute(aLong);
            String text = textView.getText().toString();
            text += "\n全部下載完成,總共下載了" + aLong + "個字節(jié)";
            textView.setText(text);
            btnDownload.setEnabled(true);
        }

        @Override
        protected void onCancelled() {
            Log.i("iSpring", "DownloadTask -> onCancelled, Thread name: " + Thread.currentThread().getName());
            super.onCancelled();
            textView.setText("取消下載");
            btnDownload.setEnabled(true);
        }
    }
}

點(diǎn)擊下載按鈕后台谊,界面如下所示:



控制臺輸出如下所示:


下面對以上代碼進(jìn)行一下說明蓉媳。

  1. 我們在MainActivity中定義了內(nèi)部類DownloadTask譬挚,DownloadTask繼承自AsyncTask,在該例中酪呻,Params泛型是String類型减宣,Progress泛型是Object類型,Result泛型是Long類型玩荠。

  2. 我們定義了一個Url字符串?dāng)?shù)組蚪腋,將該數(shù)組傳遞給AsyncTask的execute方法,用于異步執(zhí)行task姨蟋。

  3. 在執(zhí)行了downloadTask.execute(urls)之后屉凯,AsyncTask會自動回調(diào)onPreExecute方法,在該方法中我們將textView設(shè)置為“開始下載…”幾個字眼溶,告知用戶即將執(zhí)行下載操作悠砚。通過控制臺輸出我們也可以看出該方法是在主線程中執(zhí)行的。

  4. 在執(zhí)行了onPreExecute方法之后堂飞,AsyncTask會回調(diào)doInBackground方法灌旧,該方法中的輸入?yún)?shù)是String類型的不定長數(shù)組,此處的String就對應(yīng)著Params泛型類型绰筛,我們在該方法中遍歷Url數(shù)組枢泰,依次下載對應(yīng)的文件,當(dāng)我們下載完一個文件铝噩,就相當(dāng)于我們階段性地完成了一部分任務(wù)衡蚂,我們就通過調(diào)用publishProgress方法將階段性處理結(jié)果發(fā)布出去。在此例中我們將階段性的處理結(jié)果定義為Object類型骏庸,即Progress泛型類型毛甲。通過控制臺輸出我們可以看出doInBackground方法是運(yùn)行在新的工作線程”AsyncTask #1”中的,AsyncTask的工作線程都是以”AsyncTask #”然后加上數(shù)字作為名字具被。當(dāng)所有文件下載完成后玻募,我們就可以通過totalSize返回所有下載的字節(jié)數(shù),返回值類型為Long一姿,對應(yīng)著AsyncTask中的Result泛型類型七咧。

  5. 在doInBackground方法中,每當(dāng)下載完一個文件叮叹,我們就會調(diào)用publishProgress方法發(fā)布階段性結(jié)果艾栋,之后AsyncTask會回調(diào)onProgressUpdate方法,在此例中衬横,onProgressUpdate的參數(shù)為Object類型裹粤,對應(yīng)著AsyncTask中的Progress泛型類型终蒂。通過控制臺輸出我們可以發(fā)現(xiàn)蜂林,該方法是在主線程中調(diào)用的遥诉,在該方法中我們會通過textView更新UI,告知用戶哪個文件下載完成了噪叙,這樣用戶體驗(yàn)相對友好矮锈。

  6. 在整個doInBackground方法執(zhí)行完畢后,AsyncTask就會回調(diào)onPostExecute方法睁蕾,在該方法中我們再次通過textView更新UI告知用戶全部下載任務(wù)完成了苞笨。

  7. 在通過execute方法執(zhí)行了異步任務(wù)之后,可以通過AsyncTask的cancel方法取消任務(wù)子眶,取消任務(wù)后AsyncTask會回調(diào)onCancelled方法瀑凝,這樣不會再調(diào)用onPostExecute方法。

在使用Android的過程中臭杰,有以下幾點(diǎn)需要注意:

  • AsyncTask的實(shí)例必須在主線程中創(chuàng)建粤咪。

  • AsyncTask的execute方法必須在主線程中調(diào)用。

  • onPreExecute()渴杆、onPostExecute(Result),寥枝、doInBackground(Params…) 和 onProgressUpdate(Progress…)這四個方法都是回調(diào)方法,Android會自動調(diào)用磁奖,我們不應(yīng)自己調(diào)用囊拜。

  • 對于一個AsyncTack的實(shí)例,只能執(zhí)行一次execute方法比搭,在該實(shí)例上第二次執(zhí)行execute方法時就會拋出異常冠跷。

通過上面的示例,大家應(yīng)該熟悉了AsyncTask的使用流程身诺。我們上面提到蔽莱,對于某個AsyncTask實(shí)例,只能執(zhí)行一次execute方法戚长,如果我們想并行地執(zhí)行多個任務(wù)怎么辦呢盗冷?我們可以考慮實(shí)例化多個AsyncTask實(shí)例,然后分別調(diào)用各個實(shí)例的execute方法同廉,為了探究效果仪糖,我們將代碼更改如下所示:

public void onClick(View v) {
        //要下載的文件地址
        String[] urls = {
                "http://blog.csdn.net/iispring/article/details/47115879",
                "http://blog.csdn.net/iispring/article/details/47180325",
                "http://blog.csdn.net/iispring/article/details/47300819",
                "http://blog.csdn.net/iispring/article/details/47320407",
                "http://blog.csdn.net/iispring/article/details/47622705"
        };

        DownloadTask downloadTask1 = new DownloadTask();
        downloadTask1.execute(urls);

        DownloadTask downloadTask2 = new DownloadTask();
        downloadTask2.execute(urls);
    }

在單擊了按鈕之后,我們實(shí)例化了兩個DownloadTask迫肖,并分別執(zhí)行其execute方法锅劝,運(yùn)行后界面如下所示:

控制臺輸出如下所示:



我們觀察一下控制臺的輸出結(jié)果,可以發(fā)現(xiàn)對于downloadTask1蟆湖,doInBackground方法是運(yùn)行在線程“AsyncTask #1”中的故爵;對于downloadTask2,doInBackground方法是運(yùn)行在線程”AsyncTask #2”中的隅津,此時我們可能會認(rèn)為太好了诬垂,兩個AsyncTask實(shí)例分別在不同的線程中運(yùn)行劲室,實(shí)現(xiàn)了并行處理。此處真的是并行運(yùn)行的嗎结窘?

我們自己觀察控制臺輸出就可以發(fā)現(xiàn)很洋,downloadTask1的doInBackground方法執(zhí)行后,下載了五個文件隧枫,并五次觸發(fā)了onProgressUpdate喉磁,在這之后才執(zhí)行downloadTask2的doInBackground方法。我們對比上面的GIF圖也可以發(fā)現(xiàn)官脓,在downloadTask1按照順序下載完五篇文章之后协怒,downloadTask2才開始按照順序下載五篇文章卑笨。綜上所述斤讥,我們可以知道,默認(rèn)情況下如果創(chuàng)建了AsyncTask創(chuàng)建了多個實(shí)例湾趾,并同時執(zhí)行實(shí)例的各個execute方法芭商,那么這些實(shí)例的execute方法并不是并行執(zhí)行的,是串行執(zhí)行的搀缠,即在第一個實(shí)例的doInBackground完成任務(wù)后铛楣,第二個實(shí)例的doInBackgroud方法才會開始執(zhí)行,然后再執(zhí)行第三個實(shí)例的doInBackground方法… 那么你可能會問艺普,不對啊簸州,上面downloadTask1是運(yùn)行在”AsyncTask #1”線程中的,downloadTask2是運(yùn)行在”AsyncTask #2”線程中的歧譬,這明明是兩個線程鞍痘搿!其實(shí)AsyncTask為downloadTask1開辟了名為”AsyncTask #1”的工作線程瑰步,在其完成了任務(wù)之后可能就銷毀了矢洲,然后AsyncTask又為downloadTask2開辟了名為”AsyncTask #2”的工作線程。

AsyncTask在最早的版本中用一個單一的后臺線程串行執(zhí)行多個AsyncTask實(shí)例的任務(wù)缩焦,從Android 1.6(DONUT)開始读虏,AsyncTask用線程池并行執(zhí)行異步任務(wù),但是從Android 3.0(HONEYCOMB)開始為了避免并行執(zhí)行導(dǎo)致的常見錯誤袁滥,AsyncTask又開始默認(rèn)用單線程作為工作線程處理多個任務(wù)盖桥。

從Android 3.0開始AsyncTask增加了executeOnExecutor方法,用該方法可以讓AsyncTask并行處理任務(wù)题翻,該方法的方法簽名如下所示:

public final AsyncTask<Params, Progress, Result> executeOnExecutor (Executor exec, Params... params)

第一個參數(shù)表示exec是一個Executor對象揩徊,為了讓AsyncTask并行處理任務(wù),通常情況下我們此處傳入AsyncTask.THREAD_POOL_EXECUTOR即可,AsyncTask.THREAD_POOL_EXECUTOR是AsyncTask中內(nèi)置的一個線程池對象塑荒,當(dāng)然我們也可以傳入我們自己實(shí)例化的線程池對象熄赡。第二個參數(shù)params表示的是要執(zhí)行的任務(wù)的參數(shù)。

通過executeOnExecutor方法并行執(zhí)行任務(wù)的示例代碼如下所示:

public void onClick(View v) {
        if(Build.VERSION.SDK_INT >= 11){
            String[] urls = {
                    "http://blog.csdn.net/iispring/article/details/47115879",
                    "http://blog.csdn.net/iispring/article/details/47180325",
                    "http://blog.csdn.net/iispring/article/details/47300819",
                    "http://blog.csdn.net/iispring/article/details/47320407",
                    "http://blog.csdn.net/iispring/article/details/47622705"
            };

            DownloadTask downloadTask1 = new DownloadTask();
            downloadTask1.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, urls);

            DownloadTask downloadTask2 = new DownloadTask();
            downloadTask2.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, urls);
        }
    }

我們實(shí)例化了兩個DownloadTask的實(shí)例袜炕,然后執(zhí)行了這兩個實(shí)例的executeOnExecutor方法,并將AsyncTask.THREAD_POOL_EXECUTOR作為Executor傳入初家,二者都接收同樣的Url數(shù)組作為任務(wù)執(zhí)行的參數(shù)偎窘。

點(diǎn)擊下載按鈕后,運(yùn)行完的界面如下所示:


控制臺輸出如下所示:

通過控制臺的輸出結(jié)果我們可以看到溜在,在downloadTask1執(zhí)行了doInBackground方法后陌知,downloadTask2也立即執(zhí)行了doInBackground方法。并且通過程序運(yùn)行完的UI界面可以看到在一個DownloadTask實(shí)例下載了一篇文章之后掖肋,另一個DownloadTask實(shí)例也立即下載了一篇文章仆葡,兩個DownloadTask實(shí)例交叉按順序下載文件,可以看出這兩個AsyncTask的實(shí)例是并行執(zhí)行的志笼。
如果大家想了解AsyncTask的工作原理沿盅,可參見另一篇博文《源碼解析Android中AsyncTask的工作原理》
希望本文對大家使用AsyncTask的使用有所幫助纫溃!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末腰涧,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子紊浩,更是在濱河造成了極大的恐慌窖铡,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件坊谁,死亡現(xiàn)場離奇詭異费彼,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)口芍,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進(jìn)店門箍铲,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人鬓椭,你說我怎么就攤上這事虹钮。” “怎么了膘融?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵芙粱,是天一觀的道長。 經(jīng)常有香客問我氧映,道長春畔,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮律姨,結(jié)果婚禮上振峻,老公的妹妹穿的比我還像新娘。我一直安慰自己择份,他們只是感情好扣孟,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著荣赶,像睡著了一般凤价。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上拔创,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天利诺,我揣著相機(jī)與錄音,去河邊找鬼剩燥。 笑死慢逾,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的灭红。 我是一名探鬼主播侣滩,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼变擒!你這毒婦竟也來了胜卤?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤赁项,失蹤者是張志新(化名)和其女友劉穎葛躏,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體悠菜,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡舰攒,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了悔醋。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片摩窃。...
    茶點(diǎn)故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖芬骄,靈堂內(nèi)的尸體忽然破棺而出猾愿,到底是詐尸還是另有隱情,我是刑警寧澤账阻,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布蒂秘,位于F島的核電站,受9級特大地震影響淘太,放射性物質(zhì)發(fā)生泄漏姻僧。R本人自食惡果不足惜规丽,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望撇贺。 院中可真熱鬧赌莺,春花似錦、人聲如沸松嘶。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽翠订。三九已至巢音,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蕴轨,已是汗流浹背港谊。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工骇吭, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留橙弱,地道東北人。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓燥狰,卻偏偏與公主長得像棘脐,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子龙致,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評論 2 345

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