關(guān)于Android架構(gòu),你是否還在生搬硬套壕吹?

前言

關(guān)于Android架構(gòu)著蛙,可能在很多人心里一直都是虛無(wú)縹緲的存在,似懂非懂耳贬、為了用而用踏堡、處處生搬硬套,這種情況使用的意義真的很有限咒劲。本人有多個(gè)項(xiàng)目重構(gòu)的經(jīng)驗(yàn)顷蟆,恰好對(duì)設(shè)計(jì)領(lǐng)域較為感興趣,今天我將毫無(wú)保留的將自己對(duì)架構(gòu)腐魂、設(shè)計(jì)的理解分享給大家帐偎。

本文不會(huì)具體去講什么是MVC、MVP蛔屹、MVVM削樊,但我描述的點(diǎn)應(yīng)該都是這些模式的基石,從本質(zhì)上講明白為什么這樣做兔毒,這樣做的好處是什么漫贞,有了這些底層思想的支持再去看對(duì)應(yīng)的架構(gòu)模式,相信會(huì)讓你有一種煥然一新的感覺眼刃。

知識(shí)儲(chǔ)備:需掌握Java面向?qū)ο笕葡健⒘笤O(shè)計(jì)原則摇肌,如果不理解也無(wú)妨擂红,我盡量將用到的設(shè)計(jì)原則加以詳細(xì)描述

目錄

  • 1. 模塊化的意義何在?
    • 1.1 基本概念以及底層思想
    • 1.2 我們要基于哪些特性去做模塊化劃分围小?
    • 1.3 Android如何做分層處理昵骤?
    • 1.4 Data Mapper或許是解藥
    • 1.5 無(wú)處安放的業(yè)務(wù)邏輯
  • 2. 合理分層是給 數(shù)據(jù)驅(qū)動(dòng)UI 做鋪墊
    • 2.1 什么是 控制反轉(zhuǎn)?
    • 2.2 什么是數(shù)據(jù)驅(qū)動(dòng)UI蛇券?
    • 2.3 為什么說數(shù)據(jù)驅(qū)動(dòng)UI底層思想是控制反轉(zhuǎn)杜耙?
    • 2.4 為什么引入Diff障癌?
  • 3. 為什么我建議使用 函數(shù)式編程
    • 3.1 什么是 函數(shù)式編程?
    • 3.2 Android視圖開發(fā)可以借鑒函數(shù)式編程思想

1. 模塊化的意義何在蹦玫?

1.1 基本概念以及底層思想

所有的模塊化都是為了滿足單一設(shè)計(jì)原則 (字面意思理解即可)赎婚,一個(gè)函數(shù)或者一個(gè)類再或者一個(gè)模塊,職責(zé)越單一復(fù)用性就越強(qiáng)樱溉,同時(shí)能夠間接降低耦合性

在軟件工程的背景下挣输,改動(dòng)就會(huì)有出錯(cuò)的可能,不要說"我注意一點(diǎn)就不會(huì)出錯(cuò)"這種話福贞,因?yàn)槿瞬皇菣C(jī)器撩嚼。我們能做的就是盡可能讓模塊更加單一,職責(zé)越單一影響到外層模塊的可能性就越小挖帘,這樣出錯(cuò)的概率也就越低完丽。

所以模塊化核心思想即:單一設(shè)計(jì)原則

1.2 我們要基于哪些特性去做模塊化劃分?

做模塊化處理的時(shí)候盡量基于兩種特性進(jìn)行功能特性拇舀、業(yè)務(wù)特性

功能特性

網(wǎng)絡(luò)逻族、圖片加載等等都可稱之為功能特性。比如網(wǎng)絡(luò):我們可以將網(wǎng)絡(luò)框架的集成骄崩、封裝等等寫到同一個(gè)模塊(module瓷耙、package等)當(dāng)中,這樣可以增強(qiáng)可讀性(同一目錄一目了然)刁赖、降低誤操作概率搁痛,方便于維護(hù)也更加安全。同時(shí)也可將模塊托管至遠(yuǎn)程如maven庫(kù)宇弛,可供多個(gè)項(xiàng)目使用鸡典,進(jìn)一步提升復(fù)用性

業(yè)務(wù)特性

業(yè)務(wù)特性字面意思理解即可,就是我們常常編寫的業(yè)務(wù)枪芒,需要以業(yè)務(wù)的特性進(jìn)行模塊劃分

為什么說業(yè)務(wù)特性優(yōu)先級(jí)要高于功能特性彻况?

舉個(gè)例子如下圖:

image.png

相信很多人見過或者正在使用這種分包方式,在業(yè)務(wù)層把所有的Adapter舅踪、Presenter纽甘、Activity等等都放在對(duì)應(yīng)的包中,這種方式合理嗎抽碌?先說答案不合理悍赢,首先這已經(jīng)是在業(yè)務(wù)層,我們做的所有事情其實(shí)都在為業(yè)務(wù)層服務(wù)货徙,所以業(yè)務(wù)的優(yōu)先級(jí)應(yīng)該是最高的左权,我們應(yīng)當(dāng)優(yōu)先根據(jù)業(yè)務(wù)特性將對(duì)應(yīng)的類放入到同一個(gè)包中。

功能模塊核心是功能痴颊,應(yīng)當(dāng)以功能進(jìn)行模塊劃分赏迟。業(yè)務(wù)模塊核心是業(yè)務(wù),應(yīng)當(dāng)優(yōu)先以業(yè)務(wù)進(jìn)行模塊劃分蠢棱,其次再以功能進(jìn)行模塊劃分锌杀。

1.3 Android如何做分層處理甩栈?

前端開發(fā)其實(shí)就是做數(shù)據(jù)搬運(yùn),再展示到視圖中糕再。數(shù)據(jù)視圖是兩個(gè)不同的概念谤职,為了提高復(fù)用性以及可維護(hù)性,我們應(yīng)當(dāng)根據(jù)單一設(shè)計(jì)原則我們應(yīng)當(dāng)將二者進(jìn)行分層處理亿鲜,所以無(wú)論是MVC允蜈、MVP還是MVVM最核心的點(diǎn)都是將數(shù)據(jù)視圖進(jìn)行分層。

絆腳石:

通常來(lái)講蒿柳,我們通過網(wǎng)絡(luò)請(qǐng)求拿到數(shù)據(jù)結(jié)構(gòu)都是后端定義的饶套,這也就意味著視圖層不得不直接使用后端定義的字段,一旦后端進(jìn)行業(yè)務(wù)調(diào)整會(huì)迫使我們前端從數(shù)據(jù)層-->視圖層都會(huì)進(jìn)行對(duì)應(yīng)的改動(dòng)垒探,如下偽代碼所示:

//原始邏輯
數(shù)據(jù)層
Model{
    title
}
UI層
View{
    textView = model.title
}

//后端調(diào)整后
數(shù)據(jù)層
Model{
    title
    prefix
}
UI層
View{
    textView = model.prefix + model.title
}

起初我們的textView顯示的是model中的title妓蛮,但后端調(diào)整后我們需要在model中加一個(gè)prefix字段,同時(shí)textView顯示內(nèi)容也要做一次字符串拼接圾叼。視圖層因?yàn)閿?shù)據(jù)層的改動(dòng)而被動(dòng)做了修改蛤克。既然做了分層我們想要的肯定是視圖、數(shù)據(jù)互不干擾夷蚊,如何解決构挤?往下看…

1.4 Data Mapper或許是解藥

Data Mapper是后端常用的一個(gè)概念,一般情況下他們是不會(huì)直接使用數(shù)據(jù)庫(kù)里面的字段惕鼓,而是加一個(gè)Data Mapper(數(shù)據(jù)映射)將數(shù)據(jù)庫(kù)表轉(zhuǎn)按需換成Java Bean,這樣做的好處也很明顯筋现,表結(jié)構(gòu)甭管怎么折騰都不會(huì)影響到業(yè)務(wù)層代碼。

對(duì)于前端我覺得可以適當(dāng)引入Data Mapper箱歧,將后端數(shù)據(jù)轉(zhuǎn)換成本地模型矾飞,本地模型只與設(shè)計(jì)圖對(duì)應(yīng),將后端業(yè)務(wù)視圖完全隔離呀邢。這也就解決了 1.3 面臨的問題洒沦,具體方式如下:

數(shù)據(jù)層
Model{
    title
    prefix
}
本地模型(與設(shè)計(jì)圖一一對(duì)應(yīng))
LocalModel{
    //將后端模型轉(zhuǎn)換為本地模型
    title = model.prefix + model.title
}
UI層
View{
    textView = localModel.title
}

LocalModel相當(dāng)于一個(gè)中間層,通過適配器模式將數(shù)據(jù)層與視圖層做隔離价淌。

前端引入Data Mapper后可以脫離后端進(jìn)行開發(fā)申眼,只要需求明確就可以做視圖層的開發(fā),完全不需要擔(dān)心后端返回什么結(jié)構(gòu)输钩、字段豺型。并且這種做法是一勞永逸的,比如后端需要對(duì)某些字段做調(diào)整买乃,我們可以不暇思索直奔數(shù)據(jù)層,涉及到的調(diào)整100%不會(huì)影響到視圖層

注意點(diǎn):

當(dāng)下有一部分公司為了將前后端分離更徹底钓辆,由前端開發(fā)人員提供Java Bean(相當(dāng)于LocalModel)的結(jié)構(gòu)剪验,好處也很明顯肴焊,更多的業(yè)務(wù)內(nèi)聚到后端,很大程度提升了業(yè)務(wù)的靈活性功戚,畢竟App發(fā)一次版成本還是比較大的娶眷。面對(duì)這種情況我們其實(shí)沒必要再編寫Data Mapper。所以任何架構(gòu)設(shè)計(jì)都要結(jié)合實(shí)際情況啸臀,適合自己的才是最好的届宠。

1.5 無(wú)處安放的業(yè)務(wù)邏輯

關(guān)于業(yè)務(wù)邏輯其實(shí)是一個(gè)很籠統(tǒng)的概念,甚至可以將任意一行代碼稱之為業(yè)務(wù)邏輯乘粒,如此寬泛的概念我們?cè)撊绾稳ダ斫馔阕ⅲ课蚁却笾聦⑺譃閮蓚€(gè)方面:

  • 界面交互邏輯:視圖層的交互邏輯,比如手勢(shì)控制灯萍、吸頂懸浮等等都是根據(jù)業(yè)務(wù)需要實(shí)現(xiàn)的轧铁,所以嚴(yán)格來(lái)說這部分也屬于業(yè)務(wù)邏輯。但這部分業(yè)務(wù)邏輯一般在視圖層實(shí)現(xiàn)旦棉。
  • 數(shù)據(jù)邏輯:這部分是大家常說的業(yè)務(wù)邏輯齿风,屬于強(qiáng)業(yè)務(wù)邏輯,比如根據(jù)不同用戶類型獲取不同數(shù)據(jù)绑洛、展示不同界面救斑,加上Data Mapper一系列操作其實(shí)就是給后端兜底,幫他們補(bǔ)全剩余邏輯而已真屯。為了方便大家理解下文我將數(shù)據(jù)邏輯統(tǒng)稱為業(yè)務(wù)邏輯系谐。

前面我們說到,Android開發(fā)應(yīng)該具備數(shù)據(jù)層視圖層讨跟,那業(yè)務(wù)邏輯放在哪一層比較合適呢纪他?比如MVVM模式下大家都說將業(yè)務(wù)邏輯放到ViewModel處理,這么說也沒有太大的問題晾匠,但如果一個(gè)界面足夠復(fù)雜那對(duì)應(yīng)的ViewModel代碼可能會(huì)有成百上千行茶袒,看起來(lái)會(huì)很臃腫可讀性也非常差。最重要的一點(diǎn)這些業(yè)務(wù)很難編寫單元測(cè)試用例凉馆。

關(guān)于業(yè)務(wù)邏輯我建議單獨(dú)寫一個(gè)use case處理薪寓。

use case通常放在ViewModel/Presenter數(shù)據(jù)層之間,業(yè)務(wù)邏輯以及Data Mapper都應(yīng)該放在use case中澜共,每一個(gè)行為對(duì)應(yīng)一個(gè)use case向叉。這樣就解決了ViewModel/Presenter臃腫的問題,同時(shí)更方便編寫測(cè)試用例嗦董。

注意點(diǎn):

好的設(shè)計(jì)都是特定場(chǎng)景解決特定問題母谎,過度設(shè)計(jì)不僅解決不了任何問題反而會(huì)增加開發(fā)成本。以我目前經(jīng)驗(yàn)來(lái)看Android開發(fā)至少一半的場(chǎng)景都很簡(jiǎn)單:請(qǐng)求-->拿數(shù)據(jù)-->渲染視圖最多再加個(gè)Data Mapper京革,流程很單一并且后期改動(dòng)的可能也不太大奇唤,這種情況就沒必要寫一個(gè)use case幸斥,Data Mapper扔到數(shù)據(jù)層即可。

2. 合理分層是給 數(shù)據(jù)驅(qū)動(dòng)UI 做鋪墊

先說結(jié)論:數(shù)據(jù)驅(qū)動(dòng)UI的本質(zhì)是控制反轉(zhuǎn)

2.1 什么是 控制反轉(zhuǎn)咬扇?

控制即對(duì)程序流程的控制甲葬,一般由我們開發(fā)者承擔(dān),此過程為控制懈贺。但開發(fā)者是人所以不可避免出現(xiàn)錯(cuò)誤经窖,此時(shí)可以將角色做一個(gè)反轉(zhuǎn)由成熟的框架負(fù)責(zé)整個(gè)流程,程序員只需要在框架預(yù)留的擴(kuò)展點(diǎn)上梭灿,添加跟自己的業(yè)務(wù)代碼画侣,就可以利用框架來(lái)驅(qū)動(dòng)整個(gè)程序流程的執(zhí)行,此過程為反轉(zhuǎn)胎源。

控制反轉(zhuǎn)概念和設(shè)計(jì)原則中的依賴倒置很相似棉钧,只是少了一個(gè)依賴抽象

打個(gè)比方:

現(xiàn)有一個(gè)HTTP請(qǐng)求的需求涕蚤,如果想自己維護(hù)HTTT鏈接宪卿、自己管理TCP Socket、自己處理HTTP緩存…..就是整個(gè)HTTP協(xié)議全部自己封裝万栅,先不說這個(gè)工程能不能靠個(gè)人實(shí)現(xiàn)佑钾,就算實(shí)現(xiàn)也是漏洞百出,此時(shí)可以換個(gè)思路:通過OkHttp去實(shí)現(xiàn)烦粒,OkHttp是一個(gè)成熟的框架用它基本上不會(huì)出錯(cuò)休溶。個(gè)人封裝HTTP協(xié)議到使用OkHttp框架,這個(gè)過程在控制HTTP的角色上發(fā)生了一個(gè)反轉(zhuǎn)扰她,個(gè)人--->成熟的框架OkHttp即控制反轉(zhuǎn)兽掰,好處也很明顯,框架出錯(cuò)的概率遠(yuǎn)低于個(gè)人徒役。

2.2 什么是數(shù)據(jù)驅(qū)動(dòng)UI孽尽?

通俗一點(diǎn)說就是當(dāng)數(shù)據(jù)改變時(shí)對(duì)應(yīng)的UI也要跟著變,反過來(lái)說當(dāng)需要改變UI只需要改變對(duì)應(yīng)的數(shù)據(jù)即可∮俏穑現(xiàn)在比較流行的UI框架如Flutter杉女、ComposeVue其本質(zhì)都是基于函數(shù)式編程實(shí)現(xiàn)數(shù)據(jù)驅(qū)動(dòng)UI鸳吸,它們共同的目的都是為了解決數(shù)據(jù)熏挎,UI一致性問題。

在當(dāng)前的Android中可以使用DataBinding實(shí)現(xiàn)同樣的效果晌砾,以Jetpack MVVM為例:ViewModelRepository拿到數(shù)據(jù)暫存到ViewModel對(duì)應(yīng)的ObservableFiled即可實(shí)現(xiàn)數(shù)據(jù)驅(qū)動(dòng)UI坎拐,但前提是從Repository拿到的數(shù)據(jù)可以直接用,如果在Activity或者Adapter做數(shù)據(jù)二次處理再notify UI,已經(jīng)違背數(shù)據(jù)驅(qū)動(dòng)UI核心思想廉白。所以想實(shí)現(xiàn)數(shù)據(jù)驅(qū)動(dòng)UI必須要有合理的分層(UI層拿到的數(shù)據(jù)無(wú)需處理个初,可以直接用)乖寒,Data Mapper恰好解決這一問題猴蹂,同時(shí)也可規(guī)避大量編寫BindAdapter的現(xiàn)狀。

DataBinding并非函數(shù)式編程楣嘁,它只是通過AbstractProcessor生成中間代碼磅轻,將數(shù)據(jù)映射到XML中

2.3 為什么說數(shù)據(jù)驅(qū)動(dòng)UI底層思想是控制反轉(zhuǎn)?

當(dāng)前Android生態(tài)能實(shí)現(xiàn)數(shù)據(jù)綁定UI的框架只有兩個(gè):DataBinding逐虚、Compose(暫不討論)

在引入DataBinding之前渲染一條數(shù)據(jù)通常需要兩步聋溜,如下:

var title = "iOS"
fun setTitle(){
     //第一步更改數(shù)據(jù)源
     title = "Android"
     //第二個(gè)更改UI
     textView = title
}

共需要兩步更改數(shù)據(jù)源、更改UI叭爱,數(shù)據(jù)源UI有一個(gè)忘記修改便會(huì)出現(xiàn)BUG撮躁,千萬(wàn)不要說:“兩個(gè)我都不會(huì)忘記修改”,當(dāng)面臨復(fù)雜的邏輯以及十幾個(gè)甚至幾十個(gè)的數(shù)據(jù)源很難保證不出錯(cuò)买雾。這種問題可以通過DataBinding解決把曼,只需更改對(duì)應(yīng)的ObservableFiledUI便會(huì)同步修改,控制UI狀態(tài)也從個(gè)人反轉(zhuǎn)到的DataBinding漓穿,個(gè)人疏忽的事情DataBinding可不會(huì)嗤军。

所以說數(shù)據(jù)驅(qū)動(dòng)UI底層思想是控制反轉(zhuǎn)

2.4 為什么引入Diff?

引入diff之前:

RecyclerView想要實(shí)現(xiàn)動(dòng)態(tài)刪除晃危、添加叙赚、更新需要分別手動(dòng)更新數(shù)據(jù)和UI,這樣在中間插了一道并且分別更新數(shù)據(jù)和UI已經(jīng)違背了前面所說的數(shù)據(jù)驅(qū)動(dòng)UI僚饭,而我們想要的是不管刪除震叮、添加或者更新只有一個(gè)入口,只要改變數(shù)據(jù)源就會(huì)驅(qū)動(dòng)UI做更新鳍鸵,想要滿足這一原則只能改變數(shù)據(jù)源后對(duì)RecyclerView做全部刷新苇瓣,但這樣會(huì)造成性能問題,復(fù)雜的界面會(huì)感到明顯的卡頓权纤。

引入diff之后:

Diff算法通過對(duì)oldItemnewItem做差異化比對(duì)钓简,會(huì)自動(dòng)更新改變的item,同時(shí)支持刪除汹想、添加的動(dòng)畫效果外邓,這一特性解決了RecyclerView需要實(shí)現(xiàn)數(shù)據(jù)驅(qū)動(dòng)UI的性能問題

3 為什么我建議使用 函數(shù)式編程

3.1 什么是 函數(shù)式編程?

  • 一個(gè)入口古掏,一個(gè)出口损话。
  • 不在函數(shù)鏈內(nèi)部執(zhí)行與運(yùn)算本身無(wú)關(guān)的操作
  • 不在函數(shù)鏈內(nèi)部使用外部變量(實(shí)際上這一條很難遵守,可以適當(dāng)突破)

說的通俗點(diǎn)就是給定一個(gè)初始值,經(jīng)過函數(shù)鏈的運(yùn)行會(huì)得到一個(gè)目標(biāo)值丧枪,運(yùn)算的過程中外部沒有插手的權(quán)限光涂,同時(shí)不做與本身無(wú)關(guān)的操作,從根本上解決了不可預(yù)期錯(cuò)誤的產(chǎn)生拧烦。

舉個(gè)例子:

//Kotlin代碼

listOf(10, 20).map {
   it + 1
}.forEach {
   Log.i("list", "$it")
}

上面這種鏈?zhǔn)骄幊叹褪菢?biāo)準(zhǔn)的函數(shù)式編程忘闻,輸入到輸出之間開發(fā)者根本沒有插手的機(jī)會(huì)(即Log.i(..)之前開發(fā)者沒有權(quán)限處理list),所以整個(gè)流程是100%安全的恋博,RxJava齐佳、Flow鏈?zhǔn)礁唠A函數(shù)都是標(biāo)準(zhǔn)的函數(shù)式編程债沮,它們從規(guī)范層面解決數(shù)據(jù)安全問題炼吴。所以我建議在Kotlin中 碰到數(shù)據(jù)處理盡量使用鏈?zhǔn)礁唠A函數(shù)(RxJava、Kotlin Flow亦然)疫衩。

3.2 Android視圖開發(fā)可以借鑒函數(shù)式編程思想

Android視圖開發(fā)大都遵循如下流程:請(qǐng)求–>處理數(shù)據(jù)–>渲染UI硅蹦,這一流程可以借鑒函數(shù)式編程,將請(qǐng)求作為入口闷煤,渲染做為出口童芹,在這個(gè)流程中盡量不做與當(dāng)前行為無(wú)關(guān)的事(這也要求ViewModel,Repository中的函數(shù)要符合單一原則)。這樣說有點(diǎn)籠統(tǒng)曹傀,下面舉個(gè)反例:

    View{
        //刷新
        fun refresh(){
            ViewModel.load(true)
        }
        //加載更多
        fun loadMore(){
            ViewModel.load(false)
        }
    }

    ViewModel{
        //加載數(shù)據(jù)
        load(isRefresh){
            if (isRefresh){
                //刷新
            }else{
                //加載更多
            }
        }
    }

View層有刷新辐脖、加載更多兩種行為,load(isRefresh)一個(gè)入口皆愉,兩個(gè)出口嗜价。面臨的問題很明顯,修改刷新加載更多都會(huì)對(duì)對(duì)方產(chǎn)生影響幕庐,違反開閉原則中的閉(對(duì)修改關(guān)閉:行為沒變不準(zhǔn)修改源代碼)久锥,導(dǎo)致存在不可預(yù)期的問題產(chǎn)生∫彀可以借鑒函數(shù)式編程思想對(duì)其進(jìn)行改進(jìn)瑟由,將ViewModelload函數(shù)拆分成refreshloadMore,這樣刷新加載更多兩種行為冤寿、兩個(gè)入口歹苦、兩個(gè)出口互不干涉,通過函數(shù)的銜接形成兩條獨(dú)立的業(yè)務(wù)鏈條督怜。

函數(shù)式編程可以約束我們寫出規(guī)范的代碼殴瘦,面對(duì)不能使用函數(shù)式編程的場(chǎng)景,我們可以嘗試自我約束往函數(shù)式編程方向靠攏号杠,大致也能實(shí)現(xiàn)相同的效果蚪腋。

綜上所述

  • 合理的分層可以提升復(fù)用性丰歌、降低模塊間耦合性
  • Data Mapper 可以讓視圖層脫離于后端進(jìn)行開發(fā)
  • 復(fù)雜的業(yè)務(wù)邏輯應(yīng)該寫到use case中
  • 數(shù)據(jù)驅(qū)動(dòng)UI的本質(zhì)是控制反轉(zhuǎn)
  • 通過函數(shù)式編程可以寫出更加安全的代碼

原文章地址

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市屉凯,隨后出現(xiàn)的幾起案子立帖,更是在濱河造成了極大的恐慌,老刑警劉巖悠砚,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件晓勇,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡哩簿,警方通過查閱死者的電腦和手機(jī)宵蕉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門酝静,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)节榜,“玉大人,你說我怎么就攤上這事别智∽诓裕” “怎么了?”我有些...
    開封第一講書人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵薄榛,是天一觀的道長(zhǎng)讳窟。 經(jīng)常有香客問我,道長(zhǎng)敞恋,這世上最難降的妖魔是什么丽啡? 我笑而不...
    開封第一講書人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮硬猫,結(jié)果婚禮上补箍,老公的妹妹穿的比我還像新娘。我一直安慰自己啸蜜,他們只是感情好坑雅,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著衬横,像睡著了一般裹粤。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蜂林,一...
    開封第一講書人閱讀 49,031評(píng)論 1 285
  • 那天遥诉,我揣著相機(jī)與錄音,去河邊找鬼噪叙。 笑死矮锈,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的构眯。 我是一名探鬼主播愕难,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了猫缭?” 一聲冷哼從身側(cè)響起葱弟,我...
    開封第一講書人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎猜丹,沒想到半個(gè)月后芝加,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡射窒,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年藏杖,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片脉顿。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蝌麸,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出艾疟,到底是詐尸還是另有隱情来吩,我是刑警寧澤,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布蔽莱,位于F島的核電站弟疆,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏盗冷。R本人自食惡果不足惜怠苔,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望仪糖。 院中可真熱鬧柑司,春花似錦、人聲如沸乓诽。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)鸠天。三九已至讼育,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間稠集,已是汗流浹背奶段。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留剥纷,地道東北人痹籍。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像晦鞋,于是被迫代替她去往敵國(guó)和親蹲缠。 傳聞我的和親對(duì)象是個(gè)殘疾皇子棺克,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

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