多線程斷點

Android多線程斷點續(xù)傳下載



原理

其實斷點續(xù)傳的原理很簡單存璃,從字面上理解,所謂斷點續(xù)傳就是從停止的地方重新下載雕拼。

斷點:線程停止的位置纵东。

續(xù)傳:從停止的位置重新下載。

用代碼解析就是:

斷點 : 當(dāng)前線程已經(jīng)下載完成的數(shù)據(jù)長度啥寇。

續(xù)傳 : 向服務(wù)器請求上次線程停止位置之后的數(shù)據(jù)偎球。

原理知道了洒扎,功能實現(xiàn)起來也簡單。每當(dāng)線程停止時就把已下載的數(shù)據(jù)長度寫入記錄文件衰絮,當(dāng)重新下載時袍冷,從記錄文件讀取已經(jīng)下載了的長度。而這個長度就是所需要的斷點猫牡。

續(xù)傳的實現(xiàn)也簡單胡诗,可以通過設(shè)置網(wǎng)絡(luò)請求參數(shù),請求服務(wù)器從指定的位置開始讀取數(shù)據(jù)淌友。

而要實現(xiàn)這兩個功能只需要使用到httpURLconnection里面的setRequestProperty方法便可以實現(xiàn).

publicvoidsetRequestProperty(String field, String newValue)

如下所示煌恢,便是向服務(wù)器請求500-1000之間的500個byte:

conn.setRequestProperty("Range","bytes="+500+"-"+1000);

以上只是續(xù)傳的一部分需求,當(dāng)我們獲取到下載數(shù)據(jù)時震庭,還需要將數(shù)據(jù)寫入文件瑰抵,而普通發(fā)File對象并不提供從指定位置寫入數(shù)據(jù)的功能,這個時候器联,就需要使用到RandomAccessFile來實現(xiàn)從指定位置給文件寫入數(shù)據(jù)的功能二汛。

publicvoidseek(longoffset)

如下所示,便是從文件的的第100個byte后開始寫入數(shù)據(jù)拨拓。

raFile.seek(100);

而開始寫入數(shù)據(jù)時還需要用到RandomAccessFile里面的另外一個方法

publicvoidwrite(byte[] buffer,intbyteOffset,intbyteCount)

該方法的使用和OutputStream的write的使用一模一樣...

以上便是斷點續(xù)傳的原理习贫。

多線程斷點續(xù)傳

而多線程斷點續(xù)傳便是在單線程的斷點續(xù)傳上延伸的,而多線程斷點續(xù)傳是把整個文件分割成幾個部分千元,每個部分由一條線程執(zhí)行下載,而每一條下載線程都要實現(xiàn)斷點續(xù)傳功能颤绕。

為了實現(xiàn)文件分割功能幸海,我們需要使用到httpURLconnection的另外一個方法:

publicintgetContentLength()

當(dāng)請求成功時,可以通過該方法獲取到文件的總長度奥务。

每一條線程下載大小 = fileLength / THREAD_NUM

如下圖所示物独,描述的便是多線程的下載模型:

多線程下載描述

在多線程斷點續(xù)傳下載中,有一點需要特別注意:

由于文件是分成多個部分是被不同的線程的同時下載的氯葬,這就需要挡篓,每一條線程都分別需要有一個斷點記錄,和一個線程完成狀態(tài)的記錄帚称;

如下圖所示:

多線程記錄

只有所有線程的下載狀態(tài)都處于完成狀態(tài)時官研,才能表示文件已經(jīng)下載完成。

實現(xiàn)記錄的方法多種多樣闯睹,我這里采用的是JDK自帶的Properties類來記錄下載參數(shù)戏羽。

斷點續(xù)傳結(jié)構(gòu)

通過原理的了解,便可以很快的設(shè)計出斷點續(xù)傳工具類的基本結(jié)構(gòu)圖

這里寫圖片描述

IDownloadListener.java

packagecom.arialyy.frame.http.inf;importjava.net.HttpURLConnection;/**

? ? * 在這里面編寫你的業(yè)務(wù)邏輯

? ? */publicinterfaceIDownloadListener{/**

? ? ? ? * 取消下載

? ? ? ? */publicvoidonCancel();/**

? ? ? ? * 下載失敗

? ? ? ? */publicvoidonFail();/**

? ? ? ? * 下載預(yù)處理,可通過HttpURLConnection獲取文件長度

? ? ? ? */publicvoidonPreDownload(HttpURLConnection connection);/**

? ? ? ? * 下載監(jiān)聽

? ? ? ? */publicvoidonProgress(longcurrentLocation);/**

? ? ? ? * 單一線程的結(jié)束位置

? ? ? ? */publicvoidonChildComplete(longfinishLocation);/**

? ? ? ? * 開始

? ? ? ? */publicvoidonStart(longstartLocation);/**

? ? ? ? * 子程恢復(fù)下載的位置

? ? ? ? */publicvoidonChildResume(longresumeLocation);/**

? ? ? ? * 恢復(fù)位置

? ? ? ? */publicvoidonResume(longresumeLocation);/**

? ? ? ? * 停止

? ? ? ? */publicvoidonStop(longstopLocation);/**

? ? ? ? * 下載完成

? ? ? ? */publicvoidonComplete();? ? }

該類是下載監(jiān)聽接口

DownloadListener.java

importjava.net.HttpURLConnection;/**

* 下載監(jiān)聽

*/publicclassDownloadListenerimplementsIDownloadListener{@OverridepublicvoidonResume(longresumeLocation){? ? }@OverridepublicvoidonCancel(){? ? }@OverridepublicvoidonFail(){? ? }@OverridepublicvoidonPreDownload(HttpURLConnection connection){? ? }@OverridepublicvoidonProgress(longcurrentLocation){? ? }@OverridepublicvoidonChildComplete(longfinishLocation){? ? }@OverridepublicvoidonStart(longstartLocation){? ? }@OverridepublicvoidonChildResume(longresumeLocation){? ? }@OverridepublicvoidonStop(longstopLocation){? ? }@OverridepublicvoidonComplete(){? ? }}

下載參數(shù)實體

/**

? ? * 子線程下載信息類

? ? */privateclassDownloadEntity{//文件總長度longfileSize;//下載鏈接String downloadUrl;//線程IdintthreadId;//起始下載位置longstartLocation;//結(jié)束下載的文章longendLocation;//下載文件File tempFile;? ? ? ? Context context;publicDownloadEntity(Context context,longfileSize, String downloadUrl, File file,intthreadId,longstartLocation,longendLocation){this.fileSize = fileSize;this.downloadUrl = downloadUrl;this.tempFile = file;this.threadId = threadId;this.startLocation = startLocation;this.endLocation = endLocation;this.context = context;? ? ? ? }? ? }

該類是下載信息配置類楼吃,每一條子線程的下載都需要一個下載實體來配置下載信息始花。

下載任務(wù)線程

/**

? ? * 多線程下載任務(wù)類

? ? */privateclassDownLoadTaskimplementsRunnable{privatestaticfinalString TAG ="DownLoadTask";privateDownloadEntity dEntity;privateString configFPath;publicDownLoadTask(DownloadEntity downloadInfo){this.dEntity = downloadInfo;? ? ? ? ? ? configFPath = dEntity.context.getFilesDir().getPath() +"/temp/"+ dEntity.tempFile.getName() +".properties";? ? ? ? }@Overridepublicvoidrun(){try{? ? ? ? ? ? ? ? L.d(TAG,"線程_"+ dEntity.threadId +"_正在下載【"+"開始位置 : "+ dEntity.startLocation +"妄讯,結(jié)束位置:"+ dEntity.endLocation +"】");? ? ? ? ? ? ? ? URL url =newURL(dEntity.downloadUrl);? ? ? ? ? ? ? ? HttpURLConnection conn = (HttpURLConnection) url.openConnection();//在頭里面請求下載開始位置和結(jié)束位置conn.setRequestProperty("Range","bytes="+ dEntity.startLocation +"-"+ dEntity.endLocation);? ? ? ? ? ? ? ? conn.setRequestMethod("GET");? ? ? ? ? ? ? ? conn.setRequestProperty("Charset","UTF-8");? ? ? ? ? ? ? ? conn.setConnectTimeout(TIME_OUT);? ? ? ? ? ? ? ? conn.setRequestProperty("User-Agent","Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)");? ? ? ? ? ? ? ? conn.setRequestProperty("Accept","image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/xaml+xml, application/vnd.ms-xpsdocument, application/x-ms-xbap, application/x-ms-application, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*");? ? ? ? ? ? ? ? conn.setReadTimeout(2000);//設(shè)置讀取流的等待時間,必須設(shè)置該參數(shù)InputStream is = conn.getInputStream();//創(chuàng)建可設(shè)置位置的文件RandomAccessFile file =newRandomAccessFile(dEntity.tempFile,"rwd");//設(shè)置每條線程寫入文件的位置file.seek(dEntity.startLocation);byte[] buffer =newbyte[1024];intlen;//當(dāng)前子線程的下載位置longcurrentLocation = dEntity.startLocation;while((len = is.read(buffer)) != -1) {if(isCancel) {? ? ? ? ? ? ? ? ? ? ? ? L.d(TAG,"++++++++++ thread_"+ dEntity.threadId +"_cancel ++++++++++");break;? ? ? ? ? ? ? ? ? ? }if(isStop) {break;? ? ? ? ? ? ? ? ? ? }//把下載數(shù)據(jù)數(shù)據(jù)寫入文件file.write(buffer,0, len);synchronized(DownLoadUtil.this) {? ? ? ? ? ? ? ? ? ? ? ? mCurrentLocation += len;? ? ? ? ? ? ? ? ? ? ? ? mListener.onProgress(mCurrentLocation);? ? ? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? ? ? currentLocation += len;? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? file.close();? ? ? ? ? ? ? ? is.close();if(isCancel) {synchronized(DownLoadUtil.this) {? ? ? ? ? ? ? ? ? ? ? ? mCancelNum++;if(mCancelNum == THREAD_NUM) {? ? ? ? ? ? ? ? ? ? ? ? ? ? File configFile =newFile(configFPath);if(configFile.exists()) {? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? configFile.delete();? ? ? ? ? ? ? ? ? ? ? ? ? ? }if(dEntity.tempFile.exists()) {? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? dEntity.tempFile.delete();? ? ? ? ? ? ? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? ? ? ? ? ? ? L.d(TAG,"++++++++++++++++ onCancel +++++++++++++++++");? ? ? ? ? ? ? ? ? ? ? ? ? ? isDownloading =false;? ? ? ? ? ? ? ? ? ? ? ? ? ? mListener.onCancel();? ? ? ? ? ? ? ? ? ? ? ? ? ? System.gc();? ? ? ? ? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? ? ? }return;? ? ? ? ? ? ? ? }//停止?fàn)顟B(tài)不需要刪除記錄文件if(isStop) {synchronized(DownLoadUtil.this) {? ? ? ? ? ? ? ? ? ? ? ? mStopNum++;? ? ? ? ? ? ? ? ? ? ? ? String location = String.valueOf(currentLocation);? ? ? ? ? ? ? ? ? ? ? ? L.i(TAG,"thread_"+ dEntity.threadId +"_stop, stop location ==> "+ currentLocation);? ? ? ? ? ? ? ? ? ? ? ? writeConfig(dEntity.tempFile.getName() +"_record_"+ dEntity.threadId, location);if(mStopNum == THREAD_NUM) {? ? ? ? ? ? ? ? ? ? ? ? ? ? L.d(TAG,"++++++++++++++++ onStop +++++++++++++++++");? ? ? ? ? ? ? ? ? ? ? ? ? ? isDownloading =false;? ? ? ? ? ? ? ? ? ? ? ? ? ? mListener.onStop(mCurrentLocation);? ? ? ? ? ? ? ? ? ? ? ? ? ? System.gc();? ? ? ? ? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? ? ? }return;? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? L.i(TAG,"線程【"+ dEntity.threadId +"】下載完畢");? ? ? ? ? ? ? ? writeConfig(dEntity.tempFile.getName() +"_state_"+ dEntity.threadId,1+"");? ? ? ? ? ? ? ? mListener.onChildComplete(dEntity.endLocation);? ? ? ? ? ? ? ? mCompleteThreadNum++;if(mCompleteThreadNum == THREAD_NUM) {? ? ? ? ? ? ? ? ? ? File configFile =newFile(configFPath);if(configFile.exists()) {? ? ? ? ? ? ? ? ? ? ? ? configFile.delete();? ? ? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? ? ? mListener.onComplete();? ? ? ? ? ? ? ? ? ? isDownloading =false;? ? ? ? ? ? ? ? ? ? System.gc();? ? ? ? ? ? ? ? }? ? ? ? ? ? }catch(MalformedURLException e) {? ? ? ? ? ? ? ? e.printStackTrace();? ? ? ? ? ? ? ? isDownloading =false;? ? ? ? ? ? ? ? mListener.onFail();? ? ? ? ? ? }catch(IOException e) {? ? ? ? ? ? ? ? FL.e(this,"下載失敗【"+ dEntity.downloadUrl +"】"+ FL.getPrintException(e));? ? ? ? ? ? ? ? isDownloading =false;? ? ? ? ? ? ? ? mListener.onFail();? ? ? ? ? ? }catch(Exception e) {? ? ? ? ? ? ? ? FL.e(this,"獲取流失敗"+ FL.getPrintException(e));? ? ? ? ? ? ? ? isDownloading =false;? ? ? ? ? ? ? ? mListener.onFail();? ? ? ? ? ? }? ? ? ? }

這個是每條下載子線程的下載任務(wù)類,子線程通過下載實體對每一條線程進行下載配置酷宵,由于在多斷點續(xù)傳的概念里亥贸,停止表示的是暫停狀態(tài),而恢復(fù)表示的是線程從記錄的斷點重新進行下載浇垦,所以炕置,線程處于停止?fàn)顟B(tài)時是不能刪除記錄文件的。

下載入口

/**? ? * 多線程斷點續(xù)傳下載文件溜族,暫停和繼續(xù)? ? *? ? *@paramcontext? ? ? ? ? 必須添加該參數(shù)讹俊,不能使用全局變量的context? ? *@paramdownloadUrl? ? ? 下載路徑? ? *@paramfilePath? ? ? ? 保存路徑? ? *@paramdownloadListener 下載進度監(jiān)聽 {@linkDownloadListener}? ? */publicvoiddownload(finalContext context, @NonNullfinalString downloadUrl, @NonNullfinalString filePath,? ? ? ? ? ? ? ? ? ? ? ? @NonNullfinalDownloadListener downloadListener){? ? ? ? isDownloading =true;? ? ? ? mCurrentLocation =0;? ? ? ? isStop =false;? ? ? ? isCancel =false;? ? ? ? mCancelNum =0;? ? ? ? mStopNum =0;finalFile dFile =newFile(filePath);//讀取已完成的線程數(shù)finalFile configFile =newFile(context.getFilesDir().getPath() +"/temp/"+ dFile.getName() +".properties");try{if(!configFile.exists()) {//記錄文件被刪除,則重新下載newTask =true;? ? ? ? ? ? ? ? FileUtil.createFile(configFile.getPath());? ? ? ? ? ? }else{? ? ? ? ? ? ? ? newTask =false;? ? ? ? ? ? }? ? ? ? }catch(Exception e) {? ? ? ? ? ? e.printStackTrace();? ? ? ? ? ? mListener.onFail();return;? ? ? ? }? ? ? ? newTask = !dFile.exists();newThread(newRunnable() {@Overridepublicvoidrun(){try{? ? ? ? ? ? ? ? ? ? mListener = downloadListener;? ? ? ? ? ? ? ? ? ? URL url =newURL(downloadUrl);? ? ? ? ? ? ? ? ? ? HttpURLConnection conn = (HttpURLConnection) url.openConnection();? ? ? ? ? ? ? ? ? ? conn.setRequestMethod("GET");? ? ? ? ? ? ? ? ? ? conn.setRequestProperty("Charset","UTF-8");? ? ? ? ? ? ? ? ? ? conn.setConnectTimeout(TIME_OUT);? ? ? ? ? ? ? ? ? ? conn.setRequestProperty("User-Agent","Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)");? ? ? ? ? ? ? ? ? ? conn.setRequestProperty("Accept","image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/xaml+xml, application/vnd.ms-xpsdocument, application/x-ms-xbap, application/x-ms-application, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*");? ? ? ? ? ? ? ? ? ? conn.connect();intlen = conn.getContentLength();if(len <0) {//網(wǎng)絡(luò)被劫持時會出現(xiàn)這個問題mListener.onFail();return;? ? ? ? ? ? ? ? ? ? }intcode = conn.getResponseCode();if(code ==200) {intfileLength = conn.getContentLength();//必須建一個文件FileUtil.createFile(filePath);? ? ? ? ? ? ? ? ? ? ? ? RandomAccessFile file =newRandomAccessFile(filePath,"rwd");//設(shè)置文件長度file.setLength(fileLength);? ? ? ? ? ? ? ? ? ? ? ? mListener.onPreDownload(conn);//分配每條線程的下載區(qū)間Properties pro =null;? ? ? ? ? ? ? ? ? ? ? ? pro = Util.loadConfig(configFile);intblockSize = fileLength / THREAD_NUM;? ? ? ? ? ? ? ? ? ? ? ? SparseArray tasks =newSparseArray<>();for(inti =0; i < THREAD_NUM; i++) {longstartL = i * blockSize, endL = (i +1) * blockSize;? ? ? ? ? ? ? ? ? ? ? ? ? ? Object state = pro.getProperty(dFile.getName() +"_state_"+ i);if(state !=null&& Integer.parseInt(state +"") ==1) {//該線程已經(jīng)完成mCurrentLocation += endL - startL;? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? L.d(TAG,"++++++++++ 線程_"+ i +"_已經(jīng)下載完成 ++++++++++");? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? mCompleteThreadNum++;if(mCompleteThreadNum == THREAD_NUM) {if(configFile.exists()) {? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? configFile.delete();? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? mListener.onComplete();? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? isDownloading =false;? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? System.gc();return;? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }continue;? ? ? ? ? ? ? ? ? ? ? ? ? ? }//分配下載位置Object record = pro.getProperty(dFile.getName() +"_record_"+ i);if(!newTask && record !=null&& Long.parseLong(record +"") >0) {//如果有記錄煌抒,則恢復(fù)下載Long r = Long.parseLong(record +"");? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? mCurrentLocation += r - startL;? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? L.d(TAG,"++++++++++ 線程_"+ i +"_恢復(fù)下載 ++++++++++");? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? mListener.onChildResume(r);? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? startL = r;? ? ? ? ? ? ? ? ? ? ? ? ? ? }if(i == (THREAD_NUM -1)) {? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? endL = fileLength;//如果整個文件的大小不為線程個數(shù)的整數(shù)倍仍劈,則最后一個線程的結(jié)束位置即為文件的總長度}? ? ? ? ? ? ? ? ? ? ? ? ? ? DownloadEntity entity =newDownloadEntity(context, fileLength, downloadUrl, dFile, i, startL, endL);? ? ? ? ? ? ? ? ? ? ? ? ? ? DownLoadTask task =newDownLoadTask(entity);? ? ? ? ? ? ? ? ? ? ? ? ? ? tasks.put(i,newThread(task));? ? ? ? ? ? ? ? ? ? ? ? }if(mCurrentLocation >0) {? ? ? ? ? ? ? ? ? ? ? ? ? ? mListener.onResume(mCurrentLocation);? ? ? ? ? ? ? ? ? ? ? ? }else{? ? ? ? ? ? ? ? ? ? ? ? ? ? mListener.onStart(mCurrentLocation);? ? ? ? ? ? ? ? ? ? ? ? }for(inti =0, count = tasks.size(); i < count; i++) {? ? ? ? ? ? ? ? ? ? ? ? ? ? Thread task = tasks.get(i);if(task !=null) {? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? task.start();? ? ? ? ? ? ? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? ? ? }else{? ? ? ? ? ? ? ? ? ? ? ? FL.e(TAG,"下載失敗,返回碼:"+ code);? ? ? ? ? ? ? ? ? ? ? ? isDownloading =false;? ? ? ? ? ? ? ? ? ? ? ? System.gc();? ? ? ? ? ? ? ? ? ? ? ? mListener.onFail();? ? ? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? }catch(IOException e) {? ? ? ? ? ? ? ? ? ? FL.e(this,"下載失敗【downloadUrl:"+ downloadUrl +"】\n【filePath:"+ filePath +"】"+ FL.getPrintException(e));? ? ? ? ? ? ? ? ? ? isDownloading =false;? ? ? ? ? ? ? ? ? ? mListener.onFail();? ? ? ? ? ? ? ? }? ? ? ? ? ? }? ? ? ? }).start();? ? }

其實也沒啥好說的寡壮,注釋已經(jīng)很完整了贩疙,需要注意兩點

1、恢復(fù)下載時:已下載的文件大小 = 該線程的上一次斷點的位置 - 該線程起始下載位置况既;

2这溅、為了保證下載文件的完整性,只要記錄文件不存在就需要重新進行下載棒仍;

最終效果

最終效果

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末悲靴,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子莫其,更是在濱河造成了極大的恐慌癞尚,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,576評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件乱陡,死亡現(xiàn)場離奇詭異浇揩,居然都是意外死亡,警方通過查閱死者的電腦和手機憨颠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,515評論 3 399
  • 文/潘曉璐 我一進店門胳徽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人爽彤,你說我怎么就攤上這事养盗。” “怎么了淫茵?”我有些...
    開封第一講書人閱讀 168,017評論 0 360
  • 文/不壞的土叔 我叫張陵爪瓜,是天一觀的道長。 經(jīng)常有香客問我匙瘪,道長铆铆,這世上最難降的妖魔是什么蝶缀? 我笑而不...
    開封第一講書人閱讀 59,626評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮薄货,結(jié)果婚禮上翁都,老公的妹妹穿的比我還像新娘。我一直安慰自己谅猾,他們只是感情好柄慰,可當(dāng)我...
    茶點故事閱讀 68,625評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著税娜,像睡著了一般坐搔。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上敬矩,一...
    開封第一講書人閱讀 52,255評論 1 308
  • 那天概行,我揣著相機與錄音,去河邊找鬼弧岳。 笑死凳忙,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的禽炬。 我是一名探鬼主播涧卵,決...
    沈念sama閱讀 40,825評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼腹尖!你這毒婦竟也來了柳恐?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,729評論 0 276
  • 序言:老撾萬榮一對情侶失蹤热幔,失蹤者是張志新(化名)和其女友劉穎胎撤,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體断凶,經(jīng)...
    沈念sama閱讀 46,271評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,363評論 3 340
  • 正文 我和宋清朗相戀三年巫俺,在試婚紗的時候發(fā)現(xiàn)自己被綠了认烁。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,498評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡介汹,死狀恐怖却嗡,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情嘹承,我是刑警寧澤窗价,帶...
    沈念sama閱讀 36,183評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站叹卷,受9級特大地震影響撼港,放射性物質(zhì)發(fā)生泄漏坪它。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,867評論 3 333
  • 文/蒙蒙 一帝牡、第九天 我趴在偏房一處隱蔽的房頂上張望往毡。 院中可真熱鬧,春花似錦靶溜、人聲如沸开瞭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,338評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽嗤详。三九已至,卻和暖如春瓷炮,著一層夾襖步出監(jiān)牢的瞬間葱色,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,458評論 1 272
  • 我被黑心中介騙來泰國打工崭别, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留冬筒,地道東北人。 一個月前我還...
    沈念sama閱讀 48,906評論 3 376
  • 正文 我出身青樓茅主,卻偏偏與公主長得像舞痰,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子诀姚,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,507評論 2 359

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

  • 什么是多線程下載 舉例: 一個裝有水的水桶(要下載的資源)响牛,出水口(下載線程),出水口越多赫段,水流的越快呀打。即多個線程...
    ccplay5grate閱讀 277評論 0 2
  • 前言 安卓技術(shù)學(xué)習(xí)圖譜(持續(xù)更新中,歡迎關(guān)注)https://github.com/Sakuragi/androi...
    AIl_Blue閱讀 2,681評論 0 27
  • 最近閑的比較蛋疼糯笙,原本軟件計劃招20個人的贬丛,現(xiàn)在14個人的團隊都是一半在打醬油给涕,這跟全國經(jīng)濟形勢有關(guān)豺憔,我們也沒太大...
    solary2016閱讀 1,825評論 0 7
  • 有時候想說的話有很多恭应,當(dāng)我想記錄下來的時候,卻又不知該如何下筆耘眨。或許只是想說些什么剔难,屬于自己一個人的秘密胆屿。我愛你,...
    小袁籽兒閱讀 250評論 0 0
  • 不知不覺莺掠,寫寶貝的故事已經(jīng)兩百多天了,看著寶貝一天天的成長彻秆,點點滴滴的感動常常涌現(xiàn)心里楔绞。 今天午后唇兑,寶爸在午休酒朵,因...
    悅清兒閱讀 255評論 0 0