多文件多線程斷點(diǎn)下載

最近因?yàn)橐恍┰虮萌枰玫蕉辔募嗑€程斷點(diǎn)下載文件烟很,所以四處查找資料然后做了一個(gè)Demo. 本項(xiàng)目主要參考的是簡(jiǎn)書寶塔上的貓-《Android實(shí)戰(zhàn):多線程多文件斷點(diǎn)續(xù)傳下載+通知欄控制》
本項(xiàng)目GitHub地址:https://github.com/JonyZeng/JonyDownload
對(duì)于多線程下載文件,我們應(yīng)該首先需要了解單線程下載文件的原理师枣,多線程下載就是把文件分為幾份冒掌,每一份由一個(gè)線程去下載。然后將每一個(gè)線程單獨(dú)下載的文件保存在一起就實(shí)現(xiàn)了多線程下載铣猩。
斷點(diǎn)下載相對(duì)于理解比較輕松躁垛,每一次暫停線程的時(shí)候寄猩,將當(dāng)前下載的進(jìn)度保存,下次繼續(xù)從保存的進(jìn)度進(jìn)行下載芥牌。
而多文件多線程下載的原理是基于多線程單文件下載的基礎(chǔ)上贿肩,首先確定多文件同時(shí)下載需要多少個(gè)線程峦椰,然后再確定每一個(gè)文件多線程同時(shí)下載的線程數(shù)。
本項(xiàng)目是采用MVP模式進(jìn)行架構(gòu)的汰规,因?yàn)楸救藢?duì)MVP也是剛了解汤功,所以選擇它來(lái)進(jìn)行架構(gòu)。

image.png
  1. 首先在布局文件中進(jìn)行主界面activity_main的布局控轿。
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
   xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto"
   xmlns:tools="http://schemas.android.com/tools"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   tools:context="com.example.jonyz.jonydownload.MainActivity">

   <ListView
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       android:id="@+id/LV_down"
     >

   </ListView>

</android.support.constraint.ConstraintLayout>

然后設(shè)置listView條目的布局item.xml

<LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        >
        <TextView
            android:id="@+id/Tv_fileName"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:hint="下載的文件名"
            />

        <ProgressBar
            android:id="@+id/Pb_down"
            style="?android:attr/progressBarStyleHorizontal"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_below="@+id/file_textview" />
    </LinearLayout>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        >
        <Button
            android:id="@+id/Btn_start"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@+id/progressBar2"
            android:layout_toLeftOf="@+id/stop_button"
            android:text="開(kāi)始" />

        <Button
            android:id="@+id/Btn_stop"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:layout_below="@+id/progressBar2"
            android:text="暫停" />
    </LinearLayout>

2.布局完成之后冤竹,按照國(guó)際慣例拂封,我們需要給ListView設(shè)置適配器,并優(yōu)化鹦蠕。由于我們listView是需要顯示下載文件的信息冒签。所以我們需要?jiǎng)?chuàng)建一個(gè)參數(shù)類型是FileBean的list。 這里簡(jiǎn)單的貼一些FileBean(需要序列化)的參數(shù)代碼

public class FileBean implements Serializable {
    public String fileName;
    public Integer fileSize;
    public Integer filePause;//下載暫停位置
    public Integer DownSize; //finished
    public Integer id;
    public String Url;
    /**
     *
     * @param fileName 文件名
     * @param fileSize 文件大小
     * @param downSize 文件下載
     * @param id       文件ID
     * @param url       文件下載地址
     */
    public FileBean(Integer id,String fileName, Integer fileSize, Integer downSize,  String url) {
        this.fileName = fileName;
        this.fileSize = fileSize;
        DownSize = downSize;
        this.id = id;
        Url = url;
    }

之后就到了最精彩的地方了钟病。對(duì)getView的優(yōu)化和對(duì)控件的賦值萧恕。

/**
     * 進(jìn)行數(shù)據(jù)和View的適配
     *
     * @param i
     * @param view
     * @param viewGroup
     * @return
     */
    @Override
    public View getView(int i, View view, ViewGroup viewGroup) {
        final FileBean fileBean=list.get(i);
        if (view==null){
            view=inflater.inflate(R.layout.item,null);
            viewHolder = new MyViewHolder();
            viewHolder.mTvfileName=(TextView)view.findViewById(R.id.Tv_fileName);
            viewHolder.mBarDown=(ProgressBar)view.findViewById(R.id.Pb_down);
            viewHolder.mBtnstart=(Button)view.findViewById(R.id.Btn_start);
            viewHolder.mBtnstop=(Button) view.findViewById(R.id.Btn_stop);
            viewHolder.mTvfileName.setText(list.get(i).getFileName());
            viewHolder.mBarDown.setProgress(fileBean.getDownSize());
            viewHolder.mBtnstart.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    //// TODO: 2017/8/23 開(kāi)始下載
                    presenter = new DownloadPresenter();
                    presenter.startDownload(fileBean,context);
                    Log.d(TAG, "onClick:開(kāi)始");
                    Toast.makeText(context, "點(diǎn)擊了開(kāi)始", Toast.LENGTH_SHORT).show();

                }
            });
            viewHolder.mBtnstop.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    //// TODO: 2017/8/23 暫停下載
                    presenter.stopDownload(fileBean,context);
                    Log.d(TAG, "onClick:暫停");
                    Toast.makeText(context, "點(diǎn)擊了暫停", Toast.LENGTH_SHORT).show();
                }
            });
            view.setTag(viewHolder);
        }else {
            viewHolder= (MyViewHolder) view.getTag();
        }

        viewHolder.mBarDown.setProgress(fileBean.getDownSize());
        return view;

    }

根據(jù)ListView的優(yōu)化需求,需要?jiǎng)?chuàng)建一個(gè)靜態(tài)的ViewHolder

/**
     * 靜態(tài)的View ,避免重復(fù)加載
     */
    static class MyViewHolder {
        TextView mTvfileName;
        ProgressBar mBarDown;
        Button mBtnstart;
        Button mBtnstop;
    }

兩個(gè)按鈕的點(diǎn)擊事件的邏輯代碼是通過(guò)MVP的實(shí)現(xiàn)的肠阱。所以需要?jiǎng)?chuàng)建一個(gè)Contrast類設(shè)置接口票唆,在model層實(shí)現(xiàn)代碼的邏輯實(shí)現(xiàn)。

image.png

屹徘。
最終在model層里面開(kāi)啟服務(wù)走趋。通過(guò)intent傳遞值過(guò)去

private static final String TAG = DownloadModel.class.getSimpleName();
    private Intent intent;

    @Override
    public void startDownload(FileBean fileBean, Context context) {
        //開(kāi)始下載
        intent = new Intent(context,DownloadService.class);
        intent.setAction(Config.ACTION_START);
        intent.putExtra("fileBean",fileBean);
        Log.d(TAG, "startDownload: 開(kāi)啟下載的服務(wù)");
        context.startService(intent);

    }

    @Override
    public void stopDownload(FileBean fileBean, Context context) {
        //暫停下載
        Intent intent = new Intent(context, DownloadService.class);
        intent.setAction(Config.ACTION_STOP);
        intent.putExtra("fileBean", fileBean);
        Log.d(TAG, "stopDownload: 停止下載服務(wù)");
        context.startService(intent);
    }
  1. 多線程斷點(diǎn)下載服務(wù)。創(chuàng)建一個(gè)類繼承Service噪伊,在AndroidMainfest.xml中聲明簿煌。重寫onStartCommand方法,在里面根據(jù)不同的intent值進(jìn)行不同的操作鉴吹。在開(kāi)始下載的時(shí)候姨伟,需要通過(guò)線程池開(kāi)啟一個(gè)線程,所以我們需要自定義一個(gè)類繼承Thread豆励,在里面實(shí)現(xiàn)下載的代碼夺荒。
    自定義線程類所需要的參數(shù)
private URL url;
        private int responseCode;
        private int length = 0;   //判斷長(zhǎng)度
        private RandomAccessFile randomAccessFile;
        private FileBean fileBean = null;

在重寫的run方法中,進(jìn)行對(duì)當(dāng)前點(diǎn)擊下載文件的進(jìn)行獲取和設(shè)置下載文件的路徑良蒸。

url = new URL(fileBean.getUrl());
                connection = (HttpURLConnection) url.openConnection();
                connection.setConnectTimeout(2000);
                connection.setRequestMethod("GET");
                Log.i(TAG, "run:獲取網(wǎng)絡(luò)請(qǐng)求");
                responseCode = connection.getResponseCode();
                if (responseCode == HttpURLConnection.HTTP_OK) {
                    length = connection.getContentLength();
                }else{
                    Toast.makeText(DownloadService.this, "請(qǐng)檢查網(wǎng)絡(luò)情況", Toast.LENGTH_SHORT).show();
                }
                if (length <= 0) {//說(shuō)明下載文件不存在
                    return;
                }
                //文件存在技扼,開(kāi)始下載
                //判斷文件路徑是否存在
                File dir = new File(Config.DownloadPath);
                if (!dir.exists()) {
                    dir.mkdir();
                }

通過(guò)RandomAccessFile在內(nèi)存中根據(jù)當(dāng)前文件大小進(jìn)行占位。

 File file = new File(dir, fileBean.getFileName());
                randomAccessFile = new RandomAccessFile(file, "rwd");//隨機(jī)訪問(wèn)诚啃,隨時(shí)讀寫
                randomAccessFile.setLength(length);
                fileBean.setDownSize(length);   //設(shè)置文件的大小

將通過(guò)handler將fileBean傳遞淮摔。

Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
        switch (msg.what){
            case Config.MSG_INIT://開(kāi)始下載
                //調(diào)用DownloadTask的download下載
                fileBean= (FileBean) msg.obj;
                DownloadTask task = new DownloadTask(DownloadService.this, fileBean, 3);
                task.download();
                taskMap.put(fileBean.getId(),task);
                Intent intent = new Intent(Config.ACTION_START);
                intent.putExtra("fileBean",fileBean);
                sendBroadcast(intent);
        }
        }
    };

創(chuàng)建一個(gè)下載任務(wù)類DownloadTask,在里面執(zhí)行下載任務(wù)始赎。
DownloadTask所需要的一些參數(shù)

    private static final String TAG = DownloadTask.class.getSimpleName();
    public static ExecutorService cachedThreadPool = Executors.newCachedThreadPool();  //創(chuàng)建一個(gè)線程池,每次開(kāi)啟線程通過(guò)線程池調(diào)用仔燕。
    public List<UrlBean> urlBeanList;  //一個(gè)UrlBean的list集合造垛。
    private FileBean fileBean;    //下載文件的信息類
    public DBUtil dbUtil;          //數(shù)據(jù)庫(kù)操作工具類
    private ThreadUtil threadUtil;    //下載線程的信息類
    public int threadCount=1;  
    public Context context;
    private List<DownloadList> downloadLists=null;
    private UrlBean urlBean;
    public boolean isonPause=false;//判斷是否暫停

創(chuàng)建一個(gè)數(shù)據(jù)庫(kù)線程下載幫助類,里面實(shí)現(xiàn)線程對(duì)數(shù)據(jù)庫(kù)的增刪查改晰搀。查詢數(shù)據(jù)庫(kù)線程的方法

 /**
     * 查詢數(shù)據(jù)庫(kù)線程
     * @param url
     * @return
     */
    public synchronized List<UrlBean>queryThread(String url){
        Log.i(TAG, "queryThread: url: " + url);
        readableDatabase=dbUtil.getReadableDatabase();
        List<UrlBean> list=new ArrayList<>();
        Cursor cursor=readableDatabase.query("download_info", null, "url = ?", new String[] { url }, null, null, null);
        while (cursor.moveToNext()){
            UrlBean urlBean= new UrlBean();
            urlBean.setId(cursor.getInt(cursor.getColumnIndex("thread_id")));
            urlBean.setUrl(cursor.getString(cursor.getColumnIndex("url")));
            urlBean.setStart(cursor.getInt(cursor.getColumnIndex("start")));
            urlBean.setEnd(cursor.getInt(cursor.getColumnIndex("end")));
            urlBean.setFinished(cursor.getInt(cursor.getColumnIndex("finished")));
            list.add(urlBean);
        }

        cursor.close();
        readableDatabase.close();

        //readableDatabase.query("urlBean",)
        return list;
    }

創(chuàng)建一個(gè)download方法五辽,方便其他地方調(diào)用。在這個(gè)方法里面實(shí)現(xiàn)查詢文件的大小和開(kāi)啟多個(gè)線程外恕,分塊下載杆逗。

    public void download(){
        Log.i(TAG, "download:"+fileBean.getUrl());
        urlBeanList =threadUtil.queryThread(fileBean.getUrl());
        //獲取到數(shù)據(jù)庫(kù)里面查詢的list
        if (urlBeanList.size()==0){ //數(shù)據(jù)庫(kù)中不存在乡翅,第一次下載
            //獲取文件大小
            int length=fileBean.getDownSize();
            //獲取需要分的模塊
            int block=length/threadCount;

            for (int i = 0; i < threadCount; i++) {
                //確定開(kāi)始下載的位置
                int star=block*i;
                //確定結(jié)束下載的位置
                int end=(i+1)*block-1;
                if (i==threadCount-1){  // //最后一個(gè)線程下載結(jié)束的位置。
                    end=length-1;
                }
                //開(kāi)啟線程
                urlBean = new UrlBean(fileBean.getUrl(),i,star,end,0);
                urlBeanList.add(urlBean);
            }
        }
        Log.d(TAG, "download:");
        //下載文件線程的內(nèi)部類
        downloadLists = new ArrayList<>();
        for (UrlBean urlBean:urlBeanList) {
            DownloadList dowmload=new DownloadList(urlBean);
            DownloadTask.cachedThreadPool.execute(dowmload);
            downloadLists.add(dowmload);
            threadUtil.insertThread(urlBean);
        }
    }

創(chuàng)建一個(gè)內(nèi)部類罪郊,用于將下載下來(lái)的文件蠕蚜,寫入到內(nèi)存中去。
部分參數(shù)

        private HttpURLConnection urlConnection=null;
        private RandomAccessFile accessFile=null;
        private InputStream inputStream=null;

        private File file;
        private Integer finished=0;
        private Intent intent;

        private UrlBean urlBean;
        private boolean isFinished=false;

重寫run 方法悔橄,在里面請(qǐng)求網(wǎng)絡(luò)靶累,并且將請(qǐng)求下來(lái)的數(shù)據(jù)通過(guò)RandomAccessFile寫入到內(nèi)存中去。

 @Override
        public void run() {//執(zhí)行下載耗時(shí)操作
            //獲取http對(duì)象
            try {
                URL url= new URL(fileBean.getUrl());
                try {
                    urlConnection = (HttpURLConnection) url.openConnection();
                    urlConnection.setConnectTimeout(2000);
                    urlConnection.setRequestMethod("GET");
                    //設(shè)置下載的頭部
                    int start=urlBean.getStart()+urlBean.getFinished();
                    //設(shè)置下載結(jié)束的位置
                    urlConnection.setRequestProperty("Range", "bytes=" + start + "-" + urlBean.getEnd());
                    //新建文件對(duì)象
                    file = new File(Config.DownloadPath, fileBean.getFileName());
                    //隨機(jī)訪問(wèn)讀寫對(duì)象
                    accessFile = new RandomAccessFile(file, "rwd");
                    accessFile.seek(start);
                    //刷新當(dāng)前以及下載的大小
                    finished +=urlBean.getFinished();
                    intent = new Intent();
                    intent.setAction(Config.ACTION_UPDATE);
                    int respCode=urlConnection.getResponseCode();
                    if (respCode==HttpURLConnection.HTTP_PARTIAL){  //請(qǐng)求成功
                        //獲取輸入流對(duì)象
                        inputStream = urlConnection.getInputStream();
                        //設(shè)置一個(gè)byte數(shù)組癣疟,中轉(zhuǎn)數(shù)據(jù)
                        byte[] bytes = new byte[1024];
                        int length=-1;
                        //定義UI刷新時(shí)間
                        long time=System.currentTimeMillis();
                        while ((length=inputStream.read(bytes))!=-1){
                            accessFile.write(bytes,0,length);
                            //實(shí)時(shí)獲取下載進(jìn)度挣柬,刷新UI
                            finished+=length;
                            urlBean.setFinished(urlBean.getFinished()+length);
                            if (System.currentTimeMillis()-time>500){
                                time=System.currentTimeMillis();
                                intent.putExtra("finished",finished);
                                Log.d(TAG, "finished:"+finished);
                                intent.putExtra("id",fileBean.getId());
                                Log.d(TAG, "finished"+fileBean.getId());
                                context.sendBroadcast(intent);
                            }
                            if (isonPause){
                                threadUtil.updateThread(urlBean);
                                return;
                            }

                        }


                    }
                    //當(dāng)前線程是否下載完成
                    isFinished = true;
                    //判斷所有線程是否下載完成
                    checkAllFinished();

判斷所有的線是否已經(jīng)下載完成。

private synchronized void checkAllFinished() {
            boolean allFinished=true;
            for (DownloadList down:downloadLists) {
                if (!down.isFinished)
                allFinished=false;
                break;
            }
            if (allFinished==true){
                Log.d(TAG, "checkAllFinished: 下載完成");
                threadUtil.delThread(fileBean.getUrl());
                intent=new Intent(Config.ACTION_FINISHED);
                intent.putExtra("urlBean",urlBean);
                context.sendBroadcast(intent);
            }
        }

4.好了睛挚,終于到最后MainActivity里面的一些邏輯實(shí)現(xiàn)了邪蛔。


    private static final String TAG = MainActivity.class.getSimpleName();
    ListView listView;
    private FileAdapter mAdapter;
    private UrlBean urlBean;
    private List<FileBean> list;
    private UIRecive mRecive;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        init();
    }

    /**
     * 初始化
     */
    private void init() {
        initData();
        initView();
        mAdapter = new FileAdapter(this, list);
        listView.setAdapter(mAdapter);
        mRecive=new UIRecive();
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(Config.ACTION_UPDATE);
        intentFilter.addAction(Config.ACTION_FINISHED);
        intentFilter.addAction(Config.ACTION_START);
        registerReceiver(mRecive, intentFilter);
    }

    /**
     * 初始化控件
     */
    private void initView() {
        listView = (ListView) findViewById(R.id.LV_down);

    }

    /**
     * 初始化數(shù)據(jù)
     */
    private void initData() {
        //文件類集合
        list = new ArrayList<>();
        list.add(new FileBean(0,getfileName(Config.URLONE),0,0,Config.URLONE)); //(文件ID,文件名扎狱,文件大小店溢,已經(jīng)下載大小,URL)
        list.add(new FileBean(1,getfileName(Config.URLTWO),0,0,Config.URLTWO)); //(文件ID,文件名委乌,文件大小床牧,已經(jīng)下載大小,URL)
        list.add(new FileBean(2,getfileName(Config.URLTHREE),0,0,Config.URLTHREE)); //(文件ID,文件名遭贸,文件大小戈咳,已經(jīng)下載大小,URL)
        list.add(new FileBean(3,getfileName(Config.URLFOUR),0,0,Config.URLFOUR)); //(文件ID,文件名壕吹,文件大小著蛙,已經(jīng)下載大小,URL)
    }

    @Override
    public String getfileName(String url) {
        return url.substring(url.lastIndexOf("/") + 1);
    }

    @Override
    protected void onDestroy() {
        unregisterReceiver(mRecive);
        super.onDestroy();
    }
    /**
     * 刷新Ui
     */
    private class UIRecive extends BroadcastReceiver{


        @Override
        public void onReceive(Context context, Intent intent) {  //接收到傳遞過(guò)來(lái)的數(shù)據(jù)
            if (Config.ACTION_UPDATE.equals(intent.getAction())) {
                // 更新進(jìn)度條的時(shí)候
                int finished = intent.getIntExtra("finished", 0);
                Log.d(TAG, "onReceive:finsihed"+finished);
                int id = intent.getIntExtra("id", 0);
                mAdapter.updataProgress(id, finished);

            } else if (Config.ACTION_FINISHED.equals(intent.getAction())){
                // 下載結(jié)束的時(shí)候
                FileBean fileBean = (FileBean) intent.getSerializableExtra("fileBean");    
                mAdapter.updataProgress(fileBean.getId(), 0);
                Toast.makeText(MainActivity.this, list.get(fileBean.getId()).getFileName() + "下載完畢", Toast.LENGTH_SHORT).show();
            }
        }
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市耳贬,隨后出現(xiàn)的幾起案子踏堡,更是在濱河造成了極大的恐慌,老刑警劉巖咒劲,帶你破解...
    沈念sama閱讀 212,294評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件顷蟆,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡腐魂,警方通過(guò)查閱死者的電腦和手機(jī)帐偎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,493評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)蛔屹,“玉大人削樊,你說(shuō)我怎么就攤上這事。” “怎么了漫贞?”我有些...
    開(kāi)封第一講書人閱讀 157,790評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵甸箱,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我迅脐,道長(zhǎng)芍殖,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 56,595評(píng)論 1 284
  • 正文 為了忘掉前任仪际,我火速辦了婚禮围小,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘树碱。我一直安慰自己肯适,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,718評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布成榜。 她就那樣靜靜地躺著框舔,像睡著了一般。 火紅的嫁衣襯著肌膚如雪赎婚。 梳的紋絲不亂的頭發(fā)上刘绣,一...
    開(kāi)封第一講書人閱讀 49,906評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音挣输,去河邊找鬼纬凤。 笑死,一個(gè)胖子當(dāng)著我的面吹牛撩嚼,可吹牛的內(nèi)容都是我干的停士。 我是一名探鬼主播,決...
    沈念sama閱讀 39,053評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼完丽,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼恋技!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起逻族,我...
    開(kāi)封第一講書人閱讀 37,797評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤蜻底,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后聘鳞,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體薄辅,經(jīng)...
    沈念sama閱讀 44,250評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,570評(píng)論 2 327
  • 正文 我和宋清朗相戀三年搁痛,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了长搀。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,711評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡鸡典,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出枪芒,到底是詐尸還是另有隱情彻况,我是刑警寧澤谁尸,帶...
    沈念sama閱讀 34,388評(píng)論 4 332
  • 正文 年R本政府宣布,位于F島的核電站纽甘,受9級(jí)特大地震影響良蛮,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜悍赢,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,018評(píng)論 3 316
  • 文/蒙蒙 一决瞳、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧左权,春花似錦皮胡、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,796評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至锌杀,卻和暖如春甩栈,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背糕再。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,023評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工量没, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人突想。 一個(gè)月前我還...
    沈念sama閱讀 46,461評(píng)論 2 360
  • 正文 我出身青樓殴蹄,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親蒿柳。 傳聞我的和親對(duì)象是個(gè)殘疾皇子饶套,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,595評(píng)論 2 350

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