CrashHandler

目錄

認(rèn)識(shí)與作用

Crash的捕獲

Crash信息的獲取

Crash日志寫入上傳

使用方式

一些注意

最后

認(rèn)識(shí)與作用

CrashHandler: 崩潰處理器盒齿,捕獲Crash信息并作出相應(yīng)的處理

測(cè)試使用:應(yīng)用在日常的開發(fā)中边翁,我們經(jīng)常需要去Logcat測(cè)試我們的App符匾,但由于很多原因啊胶,Android Monitor會(huì)閃屏或者Crash信息丟失。 這個(gè)時(shí)候就需要一個(gè)CrashHandler來將Crash寫入到本地方便我們隨時(shí)隨地查看。

上線使用:應(yīng)用的崩潰率是用戶衡量篩選應(yīng)用的重要標(biāo)準(zhǔn)琳彩,那么應(yīng)用上線以后 我們無法向用戶借手機(jī)來分析崩潰原因露乏。為了減低崩潰率瘟仿,這個(gè)時(shí)候需要CrashHandler來幫我們將崩潰信息返回給后臺(tái)劳较,以便及時(shí)修復(fù)观蜗。

下面我們就手把手寫一個(gè)實(shí)用本地化抖仅、輕量級(jí)的CrashHandler吧撤卢。

Crash的捕獲

實(shí)現(xiàn)Thread.UncaughtExceptionHandler接口放吩,并重寫uncaughtException方法屎慢,此時(shí)你的CrashHandler就具備了接收處理異常的能力了腻惠。

調(diào)用Thread.setDefaultUncaughtExceptionHandler(CrashHandler),來使用我們自定義的CrashHandler來取代系統(tǒng)默認(rèn)的CrashHandler

結(jié)合單例模式

總體三步: 捕獲異常集灌、信息數(shù)據(jù)獲取欣喧、數(shù)據(jù)寫入和上傳

總體的初始化代碼如下:

private RCrashHandler(StringdirPath) {? ? ? ? mDirPath = dirPath;? ? ? ? File mDirectory =newFile(mDirPath);if(!mDirectory.exists()) {? ? ? ? ? ? mDirectory.mkdirs();? ? ? ? }? ? }? ? publicstaticRCrashHandler getInstance(StringdirPath) {if(INSTANCE ==null) {? ? ? ? ? ? synchronized (RCrashHandler.class) {if(INSTANCE ==null) {? ? ? ? ? ? ? ? ? ? INSTANCE =newRCrashHandler(dirPath);? ? ? ? ? ? ? ? }? ? ? ? ? ? }? ? ? ? }returnINSTANCE;? ? }


/**

* 初始化

*

* @param context? ? ? 上下文

* @param crashUploader 崩潰信息上傳接口回調(diào)

*/publicvoidinit(Context context, CrashUploader crashUploader) {? ? ? ? mCrashUploader = crashUploader;? ? ? ? mContext = context;//保存一份系統(tǒng)默認(rèn)的CrashHandlermDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();//使用我們自定義的異常處理器替換程序默認(rèn)的Thread.setDefaultUncaughtExceptionHandler(this);? ? }/**

* 這個(gè)是最關(guān)鍵的函數(shù)唆阿,當(dāng)程序中有未被捕獲的異常驯鳖,系統(tǒng)將會(huì)自動(dòng)調(diào)用uncaughtException方法

*

* @param t 出現(xiàn)未捕獲異常的線程

* @param e 未捕獲的異常浅辙,有了這個(gè)ex,我們就可以得到異常信息

*/@Override? ? publicvoiduncaughtException(Thread t, Throwable e) {if(!catchCrashException(e) && mDefaultHandler !=null) {//沒有自定義的CrashHandler的時(shí)候就調(diào)用系統(tǒng)默認(rèn)的異常處理方式mDefaultHandler.uncaughtException(t, e);? ? ? ? }else{//退出應(yīng)用killProcess();? ? ? ? }? ? }/**

* 自定義錯(cuò)誤處理,收集錯(cuò)誤信息 發(fā)送錯(cuò)誤報(bào)告等操作均在此完成.

*

* @param ex

* @return true:如果處理了該異常信息;否則返回false.

*/private boolean catchCrashException(Throwable ex) {if(ex ==null) {returnfalse;? ? ? ? }newThread() {? ? ? ? ? ? publicvoidrun() {//? ? ? ? ? ? ? ? Looper.prepare();//? ? ? ? ? ? ? ? Toast.makeText(mContext, "很抱歉,程序出現(xiàn)異常,即將退出", 0).show();//? ? ? ? ? ? ? ? Looper.loop();Intent intent =newIntent();? ? ? ? ? ? ? ? intent.setClass(mContext, CrashActivity.class);? ? ? ? ? ? ? ? intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);? ? ? ? ? ? ? ? ActivityCollector.finishAll();? ? ? ? ? ? ? ? mContext.startActivity(intent);? ? ? ? ? ? }? ? ? ? }.start();//收集設(shè)備參數(shù)信息collectInfos(mContext, ex);//保存日志文件saveCrashInfo2File();//上傳崩潰信息uploadCrashMessage(infos);returntrue;? ? }/**

* 退出應(yīng)用

*/publicstaticvoidkillProcess() {//結(jié)束應(yīng)用newThread(newRunnable() {? ? ? ? ? ? @Override? ? ? ? ? ? publicvoidrun() {? ? ? ? ? ? ? ? Looper.prepare();? ? ? ? ? ? ? ? ToastUtils.showLong("哎呀,程序發(fā)生異常啦...");? ? ? ? ? ? ? ? Looper.loop();? ? ? ? ? ? }? ? ? ? }).start();try{? ? ? ? ? ? Thread.sleep(2000);? ? ? ? }catch(InterruptedException ex) {? ? ? ? ? ? RLog.e("CrashHandler.InterruptedException--->"+ ex.toString());? ? ? ? }//退出程序Process.killProcess(Process.myPid());? ? ? ? System.exit(1);? ? }

Crash信息的獲取

獲取異常信息

/**

* 獲取捕獲異常的信息

*

* @param ex

*/privateStringcollectExceptionInfos(Throwable ex) {? ? ? ? Writer mWriter =newStringWriter();? ? ? ? PrintWriter mPrintWriter =newPrintWriter(mWriter);? ? ? ? ex.printStackTrace(mPrintWriter);? ? ? ? ex.printStackTrace();? ? ? ? Throwable mThrowable = ex.getCause();// 迭代棧隊(duì)列把所有的異常信息寫入writer中while(mThrowable !=null) {? ? ? ? ? ? mThrowable.printStackTrace(mPrintWriter);// 換行 每個(gè)個(gè)異常棧之間換行mPrintWriter.append("\r\n");? ? ? ? ? ? mThrowable = mThrowable.getCause();? ? ? ? }// 記得關(guān)閉mPrintWriter.close();returnmWriter.toString();? ? }

獲取應(yīng)用信息

/**

* 獲取應(yīng)用包參數(shù)信息

*/privatevoidcollectPackageInfos(Context context) {try{// 獲得包管理器PackageManager mPackageManager = context.getPackageManager();// 得到該應(yīng)用的信息,即主ActivityPackageInfo mPackageInfo = mPackageManager.getPackageInfo(context.getPackageName(), PackageManager.GET_ACTIVITIES);if(mPackageInfo !=null) {StringversionName = mPackageInfo.versionName ==null?"null": mPackageInfo.versionName;StringversionCode = mPackageInfo.versionCode +"";? ? ? ? ? ? ? ? mPackageInfos.put(VERSION_NAME, versionName);? ? ? ? ? ? ? ? mPackageInfos.put(VERSION_CODE, versionCode);? ? ? ? ? ? }? ? ? ? }catch(PackageManager.NameNotFoundException e) {? ? ? ? ? ? e.printStackTrace();? ? ? ? }? ? }

獲取設(shè)備硬件信息(針對(duì)不同機(jī)型的用戶更有效地定位Bug)

/**

* 從系統(tǒng)屬性中提取設(shè)備硬件和版本信息

*/privatevoidcollectBuildInfos() {// 反射機(jī)制Field[] mFields = Build.class.getDeclaredFields();// 迭代Build的字段key-value 此處的信息主要是為了在服務(wù)器端手機(jī)各種版本手機(jī)報(bào)錯(cuò)的原因for(Field field : mFields) {try{? ? ? ? ? ? ? ? field.setAccessible(true);? ? ? ? ? ? ? ? mDeviceInfos.put(field.getName(), field.get("").toString());? ? ? ? ? ? }catch(IllegalArgumentException e) {? ? ? ? ? ? ? ? e.printStackTrace();? ? ? ? ? ? }catch(IllegalAccessException e) {? ? ? ? ? ? ? ? e.printStackTrace();? ? ? ? ? ? }? ? ? ? }? ? }

獲取系統(tǒng)常規(guī)信息(針對(duì)不同設(shè)定的用戶更有效定位Bug)

/**

* 獲取系統(tǒng)常規(guī)設(shè)定屬性

*/privatevoidcollectSystemInfos() {? ? ? ? Field[] fields = Settings.System.class.getFields();for(Field field : fields) {if(!field.isAnnotationPresent(Deprecated.class)? ? ? ? ? ? ? ? ? ? && field.getType() ==String.class) {try{Stringvalue = Settings.System.getString(mContext.getContentResolver(), (String) field.get(null));if(value !=null) {? ? ? ? ? ? ? ? ? ? ? ? mSystemInfos.put(field.getName(), value);? ? ? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? }catch(IllegalAccessException e) {? ? ? ? ? ? ? ? ? ? e.printStackTrace();? ? ? ? ? ? ? ? }? ? ? ? ? ? }? ? ? ? }? ? }

獲取安全設(shè)置信息

/**

* 獲取系統(tǒng)安全設(shè)置信息

*/privatevoidcollectSecureInfos() {? ? ? ? Field[] fields = Settings.Secure.class.getFields();for(Field field : fields) {if(!field.isAnnotationPresent(Deprecated.class)? ? ? ? ? ? ? ? ? ? && field.getType() ==String.class? ? ? ? ? ? ? ? ? ? && field.getName().startsWith("WIFI_AP")) {try{Stringvalue = Settings.Secure.getString(mContext.getContentResolver(), (String) field.get(null));if(value !=null) {? ? ? ? ? ? ? ? ? ? ? ? mSecureInfos.put(field.getName(), value);? ? ? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? }catch(IllegalAccessException e) {? ? ? ? ? ? ? ? ? ? e.printStackTrace();? ? ? ? ? ? ? ? }? ? ? ? ? ? }? ? ? ? }? ? }

獲取應(yīng)用內(nèi)存信息(需要權(quán)限)

/**

* 獲取內(nèi)存信息

*/privateStringcollectMemInfos() {? ? ? ? BufferedReader br =null;? ? ? ? StringBuffer sb =newStringBuffer();? ? ? ? ArrayList commandLine =newArrayList<>();? ? ? ? commandLine.add("dumpsys");? ? ? ? commandLine.add("meminfo");? ? ? ? commandLine.add(Integer.toString(Process.myPid()));try{? ? ? ? ? ? java.lang.Process process = Runtime.getRuntime()? ? ? ? ? ? ? ? ? ? .exec(commandLine.toArray(newString[commandLine.size()]));? ? ? ? ? ? br =newBufferedReader(newInputStreamReader(process.getInputStream()),8192);while(true) {Stringline = br.readLine();if(line ==null) {break;? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? sb.append(line);? ? ? ? ? ? ? ? sb.append("\n");? ? ? ? ? ? }? ? ? ? }catch(IOException e) {? ? ? ? ? ? e.printStackTrace();? ? ? ? }finally{if(br !=null) {try{? ? ? ? ? ? ? ? ? ? br.close();? ? ? ? ? ? ? ? }catch(IOException e) {? ? ? ? ? ? ? ? ? ? e.printStackTrace();? ? ? ? ? ? ? ? }? ? ? ? ? ? }? ? ? ? }returnsb.toString();? ? }

最后將這些信息儲(chǔ)存到infos中豪筝,以便之后我們回傳給上傳具體功能時(shí)候更加方便,有了這些數(shù)據(jù)敲街,我們應(yīng)該能夠快速定位崩潰的原因了

/**

* 獲取設(shè)備參數(shù)信息

*

* @param context

*/privatevoidcollectInfos(Context context, Throwable ex) {? ? ? ? mExceptionInfos = collectExceptionInfos(ex);? ? ? ? collectPackageInfos(context);? ? ? ? collectBuildInfos();? ? ? ? collectSystemInfos();? ? ? ? collectSecureInfos();? ? ? ? mMemInfos = collectMemInfos();//將信息儲(chǔ)存到一個(gè)總的Map中提供給上傳動(dòng)作回調(diào)infos.put(EXCEPETION_INFOS_STRING, mExceptionInfos);? ? ? ? infos.put(PACKAGE_INFOS_MAP, mPackageInfos);? ? ? ? infos.put(BUILD_INFOS_MAP, mDeviceInfos);? ? ? ? infos.put(SYSTEM_INFOS_MAP, mSystemInfos);? ? ? ? infos.put(SECURE_INFOS_MAP, mSecureInfos);? ? ? ? infos.put(MEMORY_INFOS_STRING, mMemInfos);? ? }

Crash日志寫入

將崩潰數(shù)據(jù)寫入到本地文件中(這里我只收集了異常信息應(yīng)用信息多艇,具體情況可以根據(jù)自己需求來拼接其他數(shù)據(jù))

/**

* 將崩潰日志信息寫入本地文件

*/privateStringsaveCrashInfo2File() {? ? ? ? StringBuffer mStringBuffer = getInfosStr(mPackageInfos);? ? ? ? mStringBuffer.append(mExceptionInfos);// 保存文件峻黍,設(shè)置文件名StringmTime = formatter.format(newDate());StringmFileName ="CrashLog-"+ mTime +".log";if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {try{? ? ? ? ? ? ? ? File mDirectory =newFile(mDirPath);? ? ? ? ? ? ? ? Log.v(TAG, mDirectory.toString());if(!mDirectory.exists())? ? ? ? ? ? ? ? ? ? mDirectory.mkdirs();? ? ? ? ? ? ? ? FileOutputStream mFileOutputStream =newFileOutputStream(mDirectory + File.separator + mFileName);? ? ? ? ? ? ? ? mFileOutputStream.write(mStringBuffer.toString().getBytes());? ? ? ? ? ? ? ? mFileOutputStream.close();returnmFileName;? ? ? ? ? ? }catch(FileNotFoundException e) {? ? ? ? ? ? ? ? e.printStackTrace();? ? ? ? ? ? }catch(IOException e) {? ? ? ? ? ? ? ? e.printStackTrace();? ? ? ? ? ? }? ? ? ? }returnnull;? ? }/**

* 將HashMap遍歷轉(zhuǎn)換成StringBuffer

*/@NonNull? ? publicstaticStringBuffer getInfosStr(ConcurrentHashMap infos) {? ? ? ? StringBuffer mStringBuffer =newStringBuffer();for(Map.Entry entry : infos.entrySet()) {Stringkey = entry.getKey();Stringvalue = entry.getValue();? ? ? ? ? ? mStringBuffer.append(key +"="+ value +"\r\n");? ? ? ? }returnmStringBuffer;? ? }

由于每一個(gè)應(yīng)用上傳的服務(wù)器或者數(shù)據(jù)類型都不同,所以為了更好的延展性骨饿,我們使用接口回調(diào)台腥,將獲取的全部數(shù)據(jù)拋給應(yīng)用具體去實(shí)現(xiàn)(我這里為了演示黎侈,使用了Bmob后端云)

/**

* 上傳崩潰信息到服務(wù)器

*/publicvoiduploadCrashMessage(ConcurrentHashMap infos) {? ? ? ? mCrashUploader.uploadCrashMessage(infos);? ? }/**

* 崩潰信息上傳接口回調(diào)

*/public interface CrashUploader {voiduploadCrashMessage(ConcurrentHashMap infos);? ? }

使用方式

/**

* 初始化崩潰處理器

*/

privatevoidinitCrashHandler() {? ? ? ? mCrashUploader =newRCrashHandler.CrashUploader() {? ? ? ? ? ? @Override? ? ? ? ? ? publicvoiduploadCrashMessage(ConcurrentHashMap infos) {? ? ? ? ? ? ? ? CrashMessage cm =newCrashMessage();? ? ? ? ? ? ? ? ConcurrentHashMap packageInfos = (ConcurrentHashMap) infos.get(RCrashHandler.PACKAGE_INFOS_MAP);? ? ? ? ? ? ? ? cm.setDate(DateTimeUitl.getCurrentWithFormate(DateTimeUitl.sysDateFormate));? ? ? ? ? ? ? ? cm.setVersionName(packageInfos.get(RCrashHandler.VERSION_NAME));? ? ? ? ? ? ? ? cm.setVersionCode(packageInfos.get(RCrashHandler.VERSION_CODE));? ? ? ? ? ? ? ? cm.setExceptionInfos(((String) infos.get(RCrashHandler.EXCEPETION_INFOS_STRING)));? ? ? ? ? ? ? ? cm.setMemoryInfos((String) infos.get(RCrashHandler.MEMORY_INFOS_STRING));? ? ? ? ? ? ? ? cm.setDeviceInfos(RCrashHandler.getInfosStr((ConcurrentHashMap) infos? ? ? ? ? ? ? ? ? ? ? ? .get(RCrashHandler.BUILD_INFOS_MAP)).toString());? ? ? ? ? ? ? ? cm.setSystemInfoss(RCrashHandler.getInfosStr((ConcurrentHashMap) infos? ? ? ? ? ? ? ? ? ? ? ? .get(RCrashHandler.SYSTEM_INFOS_MAP)).toString());? ? ? ? ? ? ? ? cm.setSecureInfos(RCrashHandler.getInfosStr((ConcurrentHashMap) infos? ? ? ? ? ? ? ? ? ? ? ? .get(RCrashHandler.SECURE_INFOS_MAP)).toString());? ? ? ? ? ? ? ? cm.save(newSaveListener() {? ? ? ? ? ? ? ? ? ? @Override? ? ? ? ? ? ? ? ? ? publicvoiddone(Strings, BmobException e) {if(e ==null) {? ? ? ? ? ? ? ? ? ? ? ? ? ? RLog.e("上傳成功箕母!");? ? ? ? ? ? ? ? ? ? ? ? }else{? ? ? ? ? ? ? ? ? ? ? ? ? ? RLog.e("上傳Bmob失敗 錯(cuò)誤碼:"+ e.getErrorCode());? ? ? ? ? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? });? ? ? ? ? ? }? ? ? ? };? ? ? ? RCrashHandler.getInstance(FileUtils.getRootFilePath() +"EasySport/crashLog")? ? ? ? ? ? ? ? .init(mAppContext, mCrashUploader);? ? }

一些注意

使用過程中發(fā)現(xiàn)Process.killProcess(Process.myPid());和System.exit(1);會(huì)導(dǎo)致應(yīng)用自動(dòng)重啟嘶是,會(huì)影響一點(diǎn)用戶體驗(yàn)

所以我們使用了一個(gè)土方法聂喇,就是讓它去打開一個(gè)我們自己設(shè)定的CrashActivity來提高我們應(yīng)用的用戶體驗(yàn)

/**

* 自定義錯(cuò)誤處理,收集錯(cuò)誤信息 發(fā)送錯(cuò)誤報(bào)告等操作均在此完成.

*

* @param ex

* @return true:如果處理了該異常信息;否則返回false.

*/private boolean catchCrashException(Throwable ex) {if(ex ==null) {returnfalse;? ? ? ? }//啟動(dòng)我們自定義的頁面newThread() {? ? ? ? ? ? publicvoidrun() {//? ? ? ? ? ? ? ? Looper.prepare();//? ? ? ? ? ? ? ? Toast.makeText(mContext, "很抱歉,程序出現(xiàn)異常,即將退出", 0).show();//? ? ? ? ? ? ? ? Looper.loop();Intent intent =newIntent();? ? ? ? ? ? ? ? intent.setClass(mContext, CrashActivity.class);? ? ? ? ? ? ? ? intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);? ? ? ? ? ? ? ? ActivityCollector.finishAll();? ? ? ? ? ? ? ? mContext.startActivity(intent);? ? ? ? ? ? }? ? ? ? }.start();//收集設(shè)備參數(shù)信息collectInfos(mContext, ex);//保存日志文件saveCrashInfo2File();//上傳崩潰信息uploadCrashMessage(infos);returntrue;? ? }

CrashActivity的話就看個(gè)人需求了希太,可以使一段Sorry的文字或者一些交互的反饋操作都是可以的誊辉。

最后

CrashHandler整個(gè)寫下來思路是三步 :

1堕澄、異常捕獲

2霉咨、信息數(shù)據(jù)采集

3、 數(shù)據(jù)寫入本地和上傳服務(wù)器

轉(zhuǎn)載其他文章坑傅,但格式貌似有問題唁毒,如果需要看原文星爪,點(diǎn)擊https://juejin.im/post/59342ddd0ce46300571d95b5

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末室谚,一起剝皮案震驚了整個(gè)濱河市崔泵,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌入篮,老刑警劉巖潮售,帶你破解...
    沈念sama閱讀 211,743評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異鞍泉,居然都是意外死亡咖驮,警方通過查閱死者的電腦和手機(jī)训枢,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門睦刃,熙熙樓的掌柜王于貴愁眉苦臉地迎上來十酣,“玉大人,你說我怎么就攤上這事吃环∮羟幔” “怎么了文留?”我有些...
    開封第一講書人閱讀 157,285評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵骑篙,是天一觀的道長森书。 經(jīng)常有香客問我,道長杨名,這世上最難降的妖魔是什么台谍? 我笑而不...
    開封第一講書人閱讀 56,485評(píng)論 1 283
  • 正文 為了忘掉前任趁蕊,我火速辦了婚禮,結(jié)果婚禮上掷伙,老公的妹妹穿的比我還像新娘炎咖。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,581評(píng)論 6 386
  • 文/花漫 我一把揭開白布绸栅。 她就那樣靜靜地躺著粹胯,像睡著了一般辰企。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上竹观,一...
    開封第一講書人閱讀 49,821評(píng)論 1 290
  • 那天臭增,我揣著相機(jī)與錄音竹习,去河邊找鬼。 笑死拗窃,一個(gè)胖子當(dāng)著我的面吹牛泌辫,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播逃魄,決...
    沈念sama閱讀 38,960評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼伍俘,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了癌瘾?” 一聲冷哼從身側(cè)響起妨退,我...
    開封第一講書人閱讀 37,719評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤咬荷,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后幸乒,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體罕扎,經(jīng)...
    沈念sama閱讀 44,186評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡腔召,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,516評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了亲桦。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片烙肺。...
    茶點(diǎn)故事閱讀 38,650評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡桃笙,死狀恐怖沙绝,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情星著,我是刑警寧澤粗悯,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布,位于F島的核電站铺遂,受9級(jí)特大地震影響茎刚,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜粮坞,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,936評(píng)論 3 313
  • 文/蒙蒙 一莫杈、第九天 我趴在偏房一處隱蔽的房頂上張望奢入。 院中可真熱鬧,春花似錦、人聲如沸柴我。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,757評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽界睁。三九已至翻斟,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間访惜,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,991評(píng)論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留幼苛,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,370評(píng)論 2 360
  • 正文 我出身青樓配并,卻偏偏與公主長得像霍转,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子低滩,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,527評(píng)論 2 349

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