我所理解的Android組件化之通信機(jī)制

之前寫過一篇關(guān)于Android組件化的文章送爸,《Android組件化框架設(shè)計(jì)與實(shí)踐》铛嘱,之前沒看過的小伙伴可以先點(diǎn)擊閱讀。那篇文章是從實(shí)戰(zhàn)中進(jìn)行總結(jié)得來袭厂,是公司的一個(gè)真實(shí)項(xiàng)目進(jìn)行組件化架構(gòu)改造墨吓,粒度會(huì)分的更粗些,是對(duì)整體架構(gòu)實(shí)踐進(jìn)行相應(yīng)的總結(jié)纹磺,里面說了要打造一個(gè)組件化框架的話肛真,需要從以下7個(gè)方面入手:

代碼解耦。如何將一個(gè)龐大的工程分成有機(jī)的整體爽航?

組件單獨(dú)運(yùn)行蚓让。因?yàn)槊總€(gè)組件都是高度內(nèi)聚的,是一個(gè)完整的整體讥珍,如何讓其單獨(dú)運(yùn)行和調(diào)試历极?

組件間通信。由于每個(gè)組件具體實(shí)現(xiàn)細(xì)節(jié)都互相不了解衷佃,但每個(gè)組件都需要給其他調(diào)用方提供服務(wù)趟卸,那么主項(xiàng)目與組件珍特、組件與組件之間如何通信就變成關(guān)鍵扯键?

UI 跳轉(zhuǎn)。UI 跳轉(zhuǎn)指的是特殊的數(shù)據(jù)傳遞,跟組件間通信區(qū)別有什么不同浮定?

組件生命周期。這里的生命周期指的是組件在應(yīng)用中存在的時(shí)間瘫俊,組件是否可以做到按需峦失、動(dòng)態(tài)使用、因此就會(huì)涉及到組件加載筒严、卸載等管理問題丹泉。

集成調(diào)試。在開發(fā)階段如何做到按需編譯組件鸭蛙?一次調(diào)試中可能有一兩個(gè)組件參與集成摹恨,這樣編譯時(shí)間就會(huì)大大降低,提高開發(fā)效率娶视。

代碼隔離晒哄。組件之間的交互如果還是直接引用的話,那么組件之間根本沒有做到解耦肪获,如何從根本上避免組件之間的直接引用揩晴,也就是如何從根本上杜絕耦合的產(chǎn)生?

今天則會(huì)從更小細(xì)粒度入手贪磺,主要講講在組件化架構(gòu)下組件與組件之間通信機(jī)制是如何硫兰、包括所謂的UI跳轉(zhuǎn),其實(shí)也是組件化通信寒锚,只不過它稍微特殊點(diǎn)劫映,單獨(dú)抽取出來而已。學(xué)習(xí)知識(shí)的過程很常見的一個(gè)思路就是從整體概況入手刹前,首先對(duì)整體有個(gè)粗略的印象泳赋,然后再深入細(xì)節(jié),抽絲剝繭般去挖掘其中的內(nèi)在原理喇喉,一個(gè)點(diǎn)一個(gè)不斷去突破祖今,這樣就能建立起自己整個(gè)知識(shí)樹,所以今天我們就從通信機(jī)制這個(gè)點(diǎn)入手拣技,看看其中內(nèi)在玄機(jī)有哪些千诬。

思維導(dǎo)圖

同樣,在每寫一篇文章之前膏斤,放個(gè)思維導(dǎo)圖徐绑,這樣做的好處對(duì)于想寫的內(nèi)容有很好的梳理,邏輯和結(jié)構(gòu)上顯得清晰點(diǎn)莫辨。

主流方式

總所周知傲茄,Android提供了很多不同的信息的傳遞方式毅访,比如在四大組件中本地廣播、進(jìn)程間的AIDL盘榨、匿名間的內(nèi)存共享喻粹、Intent Bundle傳遞等等,那么在這么多傳遞方式草巡,哪種類型是比較適合組件與組件直接的傳遞呢守呜。

本地廣播,也就是LoacalBroadcastRecevier捷犹。更多是用在同一個(gè)應(yīng)用內(nèi)的不同系統(tǒng)規(guī)定的組件進(jìn)行通信弛饭,好處在于:發(fā)送的廣播只會(huì)在自己的APP內(nèi)傳播冕末,不會(huì)泄漏給其他的APP萍歉,其他APP無法向自己的APP發(fā)送廣播,不用被其他APP干擾档桃。本地廣播好比對(duì)講通信枪孩,成本低,效率高藻肄,但有個(gè)缺點(diǎn)就是兩者通信機(jī)制全部委托與系統(tǒng)負(fù)責(zé)蔑舞,我們無法干預(yù)傳輸途中的任何步驟,不可控制嘹屯,一般在組件化通信過程中采用比例不高攻询。

進(jìn)程間的AIDL。這個(gè)粒度在于進(jìn)程州弟,而我們組件化通信過程往往是在線程中钧栖,況且AIDL通信也是屬于系統(tǒng)級(jí)通信,底層以Binder機(jī)制婆翔,雖說Android提供模板供我們實(shí)現(xiàn)拯杠,但往往使用者不好理解,交互比較復(fù)雜啃奴,往往也不適用應(yīng)用于組件化通信過程中潭陪。

匿名的內(nèi)存共享。比如用Sharedpreferences最蕾,在處于多線程場(chǎng)景下依溯,往往會(huì)線程不安全,這種更多是存儲(chǔ)一一些變化很少的信息瘟则,比如說組件里的配置信息等等誓沸。

Intent

Bundle傳遞。包括顯性和隱性傳遞壹粟,顯性傳遞需要明確包名路徑拜隧,組件與組件往往是需要互相依賴宿百,這背離組件化中SOP(關(guān)注點(diǎn)分離原則),如果走隱性的話洪添,不僅包名路徑不能重復(fù)垦页,需要定義一套規(guī)則,只有一個(gè)包名路徑出錯(cuò)干奢,排查起來也稍顯麻煩痊焊,這個(gè)方式往往在組件間內(nèi)部傳遞會(huì)比較合適,組件外與其他組件打交道則使用場(chǎng)景不多忿峻。

說了這么多薄啥,那組件化通信什么機(jī)制比較適合呢?既然組件層中的模塊是相互獨(dú)立的逛尚,它們之間并不存在任何依賴垄惧。沒有依賴就無法產(chǎn)生關(guān)系,沒有關(guān)系绰寞,就無法傳遞消息到逊,那要如何才能完成這種交流?

目前主流做法之一就是引入第三者滤钱,比如圖中的Base Module觉壶。

組件層的模塊都依賴于基礎(chǔ)層,從而產(chǎn)生第三者聯(lián)系件缸,這種第三者聯(lián)系最終會(huì)編譯在APP Module中铜靶,那時(shí)將不會(huì)有這種隔閡,那么其中的Base Module就是跨越組件化層級(jí)的關(guān)鍵他炊,也是模塊間信息交流的基礎(chǔ)争剿。比較有代表性的組件化開源框架有得到DDComponentForAndroid阿里Arouter佑稠、聚美Router等等秒梅。

除了這種以通過引入第三者方式,還有一種解決方式是以事件總線方式舌胶,但這種方式目前開源的框架中使用比例不高捆蜀,如圖:

事件總線通過記錄對(duì)象,使用監(jiān)聽者模式來通知對(duì)象各種事件幔嫂,比如在現(xiàn)實(shí)生活中辆它,我們要去找房子,一般都去看小區(qū)的公告欄履恩,因?yàn)槟沁厱?huì)經(jīng)常發(fā)布一些出租信息锰茉,我們?nèi)ゲ榭吹倪^程中就形成了訂閱的關(guān)系,只不過這種是被動(dòng)去訂閱切心,因?yàn)橹挥凶约盒枰曳孔恿瞬湃タ挫綍r(shí)一般不會(huì)去看片吊。小區(qū)中的公告欄可以想象成一個(gè)事件總線發(fā)布點(diǎn),監(jiān)聽者則是哪些想要找房子的人协屡,當(dāng)有房東在公告欄上貼上出租房信息時(shí)俏脊,如果公告欄有訂閱信息功能,比如引入門衛(wèi)保安肤晓,已經(jīng)把之前來這個(gè)公告欄要查看的找房子人一一進(jìn)行電話登記爷贫,那么一旦有新出租消息產(chǎn)生,則門衛(wèi)會(huì)把這條消息一一進(jìn)行短信群發(fā)补憾,那么找房子人則會(huì)收到這條消息進(jìn)行后續(xù)的操作漫萄,是馬上過來看,還是延遲過來盈匾,則根據(jù)自己的實(shí)際情況進(jìn)行處理腾务。在目前開源庫(kù)中,有EventBus威酒、RxBus就是采用這種發(fā)布/訂閱模式窑睁,優(yōu)點(diǎn)是簡(jiǎn)化了Android組件之間的通信方式挺峡,實(shí)現(xiàn)解耦葵孤,讓業(yè)務(wù)代碼更加簡(jiǎn)潔,可以動(dòng)態(tài)設(shè)置事件處理線程和優(yōu)先級(jí)橱赠,缺點(diǎn)則是每個(gè)事件需要維護(hù)一個(gè)事件類尤仍,造成事件類太多,無形中加大了維護(hù)成本狭姨。那么在組件化開源框架中有ModuleBus宰啦、CC等等。

這兩者模式更詳細(xì)的對(duì)比饼拍,可以查看這篇文章多個(gè)維度對(duì)比一些有代表性的開源android組件化開發(fā)方案

實(shí)現(xiàn)方案

事件總線赡模,又可以叫做組件總線,路由+接口师抄,則相對(duì)好理解點(diǎn)漓柑,今天從閱讀它們框架源碼,我們來對(duì)比這兩種實(shí)現(xiàn)方案的不同之處叨吮。

組件總線

這邊選取的是ModuleBus框架辆布,這個(gè)方案特別之處在于其借鑒了EventBus的思想,組件的注冊(cè)/注銷和組件調(diào)用的事件發(fā)送都跟EventBus類似茶鉴,能夠傳遞一些基礎(chǔ)類型的數(shù)據(jù)锋玲,而并不需要在Base Moudel中添加額外的類。所以不會(huì)影響B(tài)ase模塊的架構(gòu)涵叮,但是無法動(dòng)態(tài)移除信息接收端的代碼惭蹂,而自定義的事件信息類型還是需要添加到Base Module中才能讓其他功能模塊索引伞插。

其中的核心代碼是在與ModuleBus類,其內(nèi)部維護(hù)了兩個(gè)ArrayMap鍵對(duì)值列表盾碗,如下:

/**

? ? * Object methodClass

? ? * String methodName蜂怎;

? ? * MethodInfo method info

? ? */privatestaticArrayMap> moduleEventMethods =newArrayMap<>();/**

? ? * Class IBaseClient.class

? ? * String methodName

? ? * Object methodClass

? ? */privatestaticArrayMap,ArrayMap>> moduleMethodClient =newArrayMap<>();

在使用方法上,在onCreate()和onDestroy()中需要注冊(cè)和解綁置尔,比如

ModuleBus.getInstance().register(this);ModuleBus.getInstance().unregister(this);

最終使用類似EventBus 中 post 方法一樣杠步,進(jìn)行兩個(gè)組件間的通信。這個(gè)框架的封裝的post 方法如下

publicvoidpost(Class<?> clientClass,String methodName,Object...args){if(clientClass ==null|| methodName ==null||methodName.length() ==0)return;? ? ? ? ArrayList clientList = getClient(clientClass,methodName);if(clientList ==null)return;try{for(Object c: clientList){try{? ? ? ? ? ? ? ? ? ? ArrayMap methods = moduleEventMethods.get(c);? ? ? ? ? ? ? ? ? ? Method method = methods.get(methodName).m;if(method ==null){? ? ? ? ? ? ? ? ? ? ? ? Log.e(TAG,"cannot find client method"+methodName +"for args["+args.length+"]"+ Arrays.toString(args));return;? ? ? ? ? ? ? ? ? ? }elseif(method.getParameterTypes() ==null){? ? ? ? ? ? ? ? ? ? ? ? Log.e(TAG,"cannot find client method param:"+method.getParameterTypes() +"for args["+args.length+"]"+ Arrays.toString(args));return;? ? ? ? ? ? ? ? ? ? }elseif(method.getParameterTypes().length != args.length){? ? ? ? ? ? ? ? ? ? ? ? Log.e(TAG,"method "+methodName +" param number not matched:method("+method.getParameterTypes().length+"), args("+ args.length+")");return;? ? ? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? ? ? method.invoke(c,args);? ? ? ? ? ? ? ? }catch(Throwable e){? ? ? ? ? ? ? ? ? ? Log.e(TAG,"Notifiy client method invoke error.",e);? ? ? ? ? ? ? ? }? ? ? ? ? ? }? ? ? ? }catch(Throwable e){? ? ? ? ? ? Log.e(TAG,"Notify client error",e);? ? ? ? }? ? }

可以看到榜轿,它是通過遍歷之前內(nèi)部的ArrayMap幽歼,把注冊(cè)在里面的方法找出,根據(jù)傳入的參數(shù)進(jìn)行匹配谬盐,使用反射調(diào)用甸私。

接口+路由

接口+路由實(shí)現(xiàn)方式則相對(duì)容易理解點(diǎn),我之前實(shí)踐的一個(gè)項(xiàng)目就是通過這種方式實(shí)現(xiàn)的飞傀。具體地址如下:DemoComponent實(shí)現(xiàn)思路是專門抽取一個(gè)LibModule作為路由服務(wù)皇型,每個(gè)組件聲明自己提供的服務(wù) Service API,這些 Service 都是一些接口砸烦,組件負(fù)責(zé)將這些 Service 實(shí)現(xiàn)并注冊(cè)到一個(gè)統(tǒng)一的路由 Router 中去弃鸦,如果要使用某個(gè)組件的功能,只需要向Router 請(qǐng)求這個(gè) Service 的實(shí)現(xiàn)幢痘,具體的實(shí)現(xiàn)細(xì)節(jié)我們?nèi)徊魂P(guān)心唬格,只要能返回我們需要的結(jié)果就可以了。

比如定義兩個(gè)路由地址颜说,一個(gè)登陸組件购岗,一個(gè)設(shè)置組件,核心代碼:

publicclassRouterPath{//注意路由的命名门粪,路徑第一個(gè)開頭需要不一致喊积,保證唯一性//Login ServicepublicstaticfinalString ROUTER_PATH_TO_LOGIN_SERVICE ="/login/service";//Setting ServicepublicstaticfinalString ROUTER_PATH_TO_SETTING_SERVICE ="/setting/service";}

那么就相應(yīng)著就有兩個(gè)接口API,如下:

publicinterfaceILoginProviderextendsIProvider{voidgoToLogin(Activity activity);}publicinterfaceISettingProviderextendsIProvider{voidgoToSetting(Activity activity);}

這兩個(gè)接口API對(duì)應(yīng)著是向外暴露這兩個(gè)組件的能提供的通信能力玄妈,然后每個(gè)組件對(duì)接口進(jìn)行實(shí)現(xiàn)乾吻,如下:

@Route(path = RouterPath.ROUTER_PATH_TO_LOGIN_SERVICE, name ="登陸頁(yè)面")publicclassLoginServiceimplementsILoginProvider{@Overridepublicvoidinit(Context context){}@OverridepublicvoidgoToLogin(Activity activity){? ? ? ? Intent loginIntent =newIntent(activity, LoginActivity.class);? ? ? ? activity.startActivity(loginIntent);? ? }}

這其中使用的到了阿里的ARouter頁(yè)面跳轉(zhuǎn)方式,內(nèi)部本質(zhì)也是接口+實(shí)現(xiàn)方式進(jìn)行組件間通信措近。

調(diào)用則很簡(jiǎn)單了溶弟,如下:

ILoginProvider loginService = (ILoginProvider) ARouter.getInstance().build(RouterPath.ROUTER_PATH_TO_LOGIN_SERVICE).navigation();if(loginService !=null){? ? loginService.goToLogin(MainActivity.this);}

還有一個(gè)組件化框架,就是ModularizationArchitecture瞭郑,它本質(zhì)實(shí)現(xiàn)方式也是接口+實(shí)現(xiàn)辜御,但是封裝形式稍微不一樣點(diǎn),它是每個(gè)功能模塊中需要使用注解建立Action事件屈张,每個(gè)Action完成一個(gè)事件動(dòng)作擒权。invoke只是方法名為反射袱巨,并未用到反射,而是使用接口方式調(diào)用碳抄,參數(shù)是通過HashMap傳遞的愉老,無法傳遞對(duì)象。具體詳解可以看這篇文章Android架構(gòu)思考(模塊化剖效、多進(jìn)程)嫉入。

頁(yè)面跳轉(zhuǎn)

頁(yè)面跳轉(zhuǎn)也算是一種組件間的通信,只不過它相對(duì)粒度更細(xì)化點(diǎn)璧尸,之前我們描述的組件間通信粒度會(huì)更抽象點(diǎn)咒林,頁(yè)面跳轉(zhuǎn)則是定位到某個(gè)組件的某個(gè)頁(yè)面,可能是某個(gè)Activity爷光,或者某個(gè)Fragment垫竞,要跳轉(zhuǎn)到另外一個(gè)組件的Activity或Fragment,是這兩者之間的通信蛀序。甚至在一般沒有進(jìn)行組件化架構(gòu)的工程項(xiàng)目中欢瞪,往往也會(huì)封裝頁(yè)面之間的跳轉(zhuǎn)代碼類,往往也會(huì)有路由中心的概念徐裸。不過一般

UI 跳轉(zhuǎn)基本都會(huì)單獨(dú)處理遣鼓,一般通過短鏈的方式來跳轉(zhuǎn)到具體的 Activity。每個(gè)組件可以注冊(cè)自己所能處理的短鏈的 Scheme 和

Host倦逐,并定義傳輸數(shù)據(jù)的格式譬正,然后注冊(cè)到統(tǒng)一的 UIRouter 中宫补,UIRouter 通過 Scheme 和 Host

的匹配關(guān)系負(fù)責(zé)分發(fā)路由檬姥。但目前比較主流的做法是通過在每個(gè) Activity 上添加注解,然后通過 APT 形成具體的邏輯代碼粉怕。

下面簡(jiǎn)單介紹目前比較主流的兩個(gè)框架核心實(shí)現(xiàn)思路:

ARouter

ARouter

核心實(shí)現(xiàn)思路是健民,我們?cè)诖a里加入的@Route注解,會(huì)在編譯時(shí)期通過apt生成一些存儲(chǔ)path和activityClass映射關(guān)系的類文件贫贝,然后app進(jìn)程啟動(dòng)的時(shí)候會(huì)拿到這些類文件秉犹,把保存這些映射關(guān)系的數(shù)據(jù)讀到內(nèi)存里(保存在map里),然后在進(jìn)行路由跳轉(zhuǎn)的時(shí)候稚晚,通過build()方法傳入要到達(dá)頁(yè)面的路由地址崇堵,ARouter會(huì)通過它自己存儲(chǔ)的路由表找到路由地址對(duì)應(yīng)的Activity.class(activity.class

= map.get(path)),然后new

Intent()客燕,當(dāng)調(diào)用ARouter的withString()方法它的內(nèi)部會(huì)調(diào)用intent.putExtra(String name,

String

value)鸳劳,調(diào)用navigation()方法,它的內(nèi)部會(huì)調(diào)用startActivity(intent)進(jìn)行跳轉(zhuǎn)也搓,這樣便可以實(shí)現(xiàn)兩個(gè)相互沒有依賴的module順利的啟動(dòng)對(duì)方的Activity了赏廓。

ActivityRouter

ActivityRouter 核心實(shí)現(xiàn)思路是涵紊,它是通過路由 +

靜態(tài)方法來實(shí)現(xiàn),在靜態(tài)方法上加注解來暴露服務(wù)幔摸,但不支持返回值摸柄,且參數(shù)固定位(context,

bundle),基于apt技術(shù)既忆,通過注解方式來實(shí)現(xiàn)URL打開Activity功能驱负,并支持在WebView和外部瀏覽器使用,支持多級(jí)Activity跳轉(zhuǎn)患雇,支持Bundle电媳、Uri參數(shù)注入并轉(zhuǎn)換參數(shù)類型。它實(shí)現(xiàn)相對(duì)簡(jiǎn)單點(diǎn)庆亡,也是比較早期比較流行的做法匾乓,不過學(xué)習(xí)它也是很有參考意義的。

小結(jié)

總的來說又谋,組件間的通信機(jī)制在組件化編程和組件化架構(gòu)中是很重要的一個(gè)環(huán)節(jié)拼缝,可能在每個(gè)組件獨(dú)自開發(fā)階段,不需要與其他組件進(jìn)行通信彰亥,只需要在內(nèi)部通信即可咧七,當(dāng)處于組件集成階段,那就需要大量組件進(jìn)行互相通信任斋,體現(xiàn)在每個(gè)業(yè)務(wù)互相協(xié)作继阻,如果組件間設(shè)計(jì)的不好,打開一個(gè)頁(yè)面或調(diào)用一個(gè)方法废酷,想當(dāng)耗時(shí)或響應(yīng)慢瘟檩,那么體現(xiàn)的則是這個(gè)APP使用比較卡頓,僅僅打開一個(gè)頁(yè)面就是需要好幾秒才能打開澈蟆,則嚴(yán)重影響使用者的體驗(yàn)了墨辛,甚至一些大型APP,可能組件分化更小趴俘,種類更多睹簇,那么組件間的通信則至關(guān)重要了。所以寥闪,要打造一個(gè)良好的組件化框架太惠,如何設(shè)計(jì)一個(gè)更適合自己本身的業(yè)務(wù)類型的通信機(jī)制,就需要多多進(jìn)行思考了疲憋。

參考文章:

1凿渊,https://github.com/luckybilly/AndroidComponentizeLibs

2,http://blog.spinytech.com/2016/12/28/android_modularization/

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市嗽元,隨后出現(xiàn)的幾起案子敛纲,更是在濱河造成了極大的恐慌,老刑警劉巖剂癌,帶你破解...
    沈念sama閱讀 216,651評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件淤翔,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡佩谷,警方通過查閱死者的電腦和手機(jī)旁壮,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來谐檀,“玉大人抡谐,你說我怎么就攤上這事⊥┾” “怎么了麦撵?”我有些...
    開封第一講書人閱讀 162,931評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)溃肪。 經(jīng)常有香客問我免胃,道長(zhǎng),這世上最難降的妖魔是什么惫撰? 我笑而不...
    開封第一講書人閱讀 58,218評(píng)論 1 292
  • 正文 為了忘掉前任羔沙,我火速辦了婚禮,結(jié)果婚禮上厨钻,老公的妹妹穿的比我還像新娘扼雏。我一直安慰自己,他們只是感情好夯膀,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,234評(píng)論 6 388
  • 文/花漫 我一把揭開白布诗充。 她就那樣靜靜地躺著,像睡著了一般棍郎。 火紅的嫁衣襯著肌膚如雪其障。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,198評(píng)論 1 299
  • 那天涂佃,我揣著相機(jī)與錄音,去河邊找鬼蜈敢。 笑死辜荠,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的抓狭。 我是一名探鬼主播伯病,決...
    沈念sama閱讀 40,084評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了午笛?” 一聲冷哼從身側(cè)響起惭蟋,我...
    開封第一講書人閱讀 38,926評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎药磺,沒想到半個(gè)月后告组,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,341評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡癌佩,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,563評(píng)論 2 333
  • 正文 我和宋清朗相戀三年木缝,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片围辙。...
    茶點(diǎn)故事閱讀 39,731評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡我碟,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出姚建,到底是詐尸還是另有隱情矫俺,我是刑警寧澤,帶...
    沈念sama閱讀 35,430評(píng)論 5 343
  • 正文 年R本政府宣布掸冤,位于F島的核電站恳守,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏贩虾。R本人自食惡果不足惜催烘,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,036評(píng)論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望缎罢。 院中可真熱鬧伊群,春花似錦、人聲如沸策精。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,676評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)咽袜。三九已至丸卷,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間询刹,已是汗流浹背谜嫉。 一陣腳步聲響...
    開封第一講書人閱讀 32,829評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留凹联,地道東北人沐兰。 一個(gè)月前我還...
    沈念sama閱讀 47,743評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像蔽挠,于是被迫代替她去往敵國(guó)和親住闯。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,629評(píng)論 2 354