大話AOP與Android的愛(ài)恨情仇

1. AOP與OOP的區(qū)別

平時(shí)我接觸多的就是OOP(Object Oriented Programming面向?qū)ο螅┪北OP(Aspect Oriented Programming面向切面)這兩種編程方式,我用自己的語(yǔ)言來(lái)解釋一下這兩者的區(qū)別:
OOP:

專業(yè)術(shù)語(yǔ): OOP(面向?qū)ο缶幊蹋┽槍?duì)業(yè)務(wù)處理過(guò)程的實(shí)體及其屬性和行為進(jìn)行抽象封裝轻专,以獲得更加清晰高效的邏輯單元?jiǎng)澐帧?br> 面向?qū)ο髠?cè)重靜態(tài)棉安,名詞苏章,狀態(tài),組織顾复,數(shù)據(jù)班挖,載體是空間;

大白話: OOP面向?qū)ο蟮娜筇卣?: 封裝 , 繼承 , 多態(tài) 芯砸。這些特征也說(shuō)明了OOP是面向?qū)ο蟮南糗剑覀冏鍪裁炊际强紤]一個(gè)對(duì)象,我們需要完成一個(gè)任務(wù)的時(shí)候一般都想著把一些操作封裝成一個(gè)類假丧,所有的變量和操作都封裝到一個(gè)類里面双揪,那么這個(gè)類就是我們的對(duì)象,我們要實(shí)現(xiàn)某個(gè)特定的功能包帚,首先也想想著在這個(gè)對(duì)象里面去實(shí)現(xiàn)渔期。
面向?qū)ο笠彩怯忻黠@缺點(diǎn)的,比如我們想實(shí)現(xiàn)某些不是常用的功能渴邦,我們需要去在需要的對(duì)象中去一一實(shí)現(xiàn)這些功能疯趟,并我們要不斷去維護(hù)這些功能,一旦多了我們就會(huì)很累的谋梭。
比如Android中一些按鍵統(tǒng)計(jì)迅办、生命周期統(tǒng)計(jì),特定統(tǒng)計(jì)都是比較瑣碎的事情章蚣,要利用面向?qū)ο蟮乃枷肴?shí)現(xiàn)都不是很完美站欺,這就要求去一一實(shí)現(xiàn)姨夹,顯得很瑣碎。

AOP:

專業(yè)術(shù)語(yǔ): AOP則是針對(duì)業(yè)務(wù)處理過(guò)程中的切面進(jìn)行提取矾策,它所面對(duì)的是處理過(guò)程中的某個(gè)步驟或階段磷账,以獲得邏輯過(guò)程中各部分之間低耦合性的隔離效果。

大白話: AOP面向切面贾虽,我在使用的時(shí)候是關(guān)注具體的方法和功能切入點(diǎn)逃糟,不需要知道也不用關(guān)心所在什么類或者是什么對(duì)象,我們只關(guān)注功能的實(shí)現(xiàn)蓬豁,具體對(duì)象是誰(shuí)绰咽,愛(ài)誰(shuí)誰(shuí)!

網(wǎng)上很流行的說(shuō)明段子:

舉個(gè)簡(jiǎn)單的例子地粪,對(duì)于“雇員”這樣一個(gè)業(yè)務(wù)實(shí)體進(jìn)行封裝取募,自然是OOP/OOD的任務(wù),我們可以為其建立一個(gè)“Employee”類蟆技,并將“雇員”相關(guān)的屬性和行為封裝其中玩敏。而用AOP設(shè)計(jì)思想對(duì)“雇員”進(jìn)行封裝將無(wú)從談起。同樣质礼,對(duì)于“權(quán)限檢查”這一動(dòng)作片斷進(jìn)行劃分旺聚,則是AOP的目標(biāo)領(lǐng)域。而通過(guò)OOD/OOP對(duì)一個(gè)動(dòng)作進(jìn)行封裝眶蕉,則有點(diǎn)不倫不類砰粹。換而言之,OOD/OOP面向名詞領(lǐng)域造挽,AOP面向動(dòng)詞領(lǐng)域伸眶。
如果說(shuō)面向?qū)ο缶幊淌顷P(guān)注將需求功能劃分為不同的并且相對(duì)獨(dú)立,封裝良好的類刽宪,并讓它們有著屬于自己的行為,依靠繼承和多態(tài)等來(lái)定義彼此的關(guān)系的話界酒;那么面向方面編程則是希望能夠?qū)⑼ㄓ眯枨蠊δ軓牟幌嚓P(guān)的類當(dāng)中分離出來(lái)圣拄,能夠使得很多類共享一個(gè)行為,一旦發(fā)生變化毁欣,不必修改很多類庇谆,而只需要修改這個(gè)行為即可。
面向方面編程和面向?qū)ο缶幊滩坏皇腔ハ喔?jìng)爭(zhēng)的技術(shù)而且彼此還是很好的互補(bǔ)凭疮。面向?qū)ο缶幊讨饕糜跒橥粚?duì)象層次的公用行為建模饭耳。它的弱點(diǎn)是將公共行為應(yīng)用于多個(gè)無(wú)關(guān)對(duì)象模型之間。而這恰恰是面向方面編程適合的地方执解。有了 AOP寞肖,我們可以定義交叉的關(guān)系,并將這些關(guān)系應(yīng)用于跨模塊的、彼此不同的對(duì)象模型新蟆。AOP 同時(shí)還可以讓我們層次化功能性而不是嵌入功能性觅赊,從而使得代碼有更好的可讀性和易于維護(hù)。它會(huì)和面向?qū)ο缶幊毯献鞯煤芎谩?/p>

上面的段子不知道誰(shuí)說(shuō)的琼稻,很流行吮螺,但確實(shí)說(shuō)得很明白!

2. AOP的Java實(shí)現(xiàn)方式

上面說(shuō)過(guò)帕翻,AOP關(guān)注的方法功能點(diǎn)鸠补,事先不知道所在對(duì)象是誰(shuí),當(dāng)然程序的運(yùn)行都是需要拿到對(duì)象在運(yùn)行的嘀掸,要在知道方法功能點(diǎn)的前提下拿到對(duì)象并執(zhí)行紫岩,這就需要用到Java的動(dòng)態(tài)代理。
在java的動(dòng)態(tài)代理機(jī)制中横殴,有兩個(gè)重要的類或接口被因,一個(gè)是 InvocationHandler(Interface)逊朽、另一個(gè)則是 Proxy(Class)事富,我們可以自己寫代碼去定義自己的動(dòng)態(tài)代理,去實(shí)現(xiàn)AOP未舟,但是太麻煩了文狱。Java有很多AOP實(shí)現(xiàn)的庫(kù)粥鞋,JavaWeb里面有JBoss、SpringFramework瞄崇、AspectJ等等呻粹。Android我熟悉,Android中基于AOP實(shí)現(xiàn)的庫(kù)有ButterKnife苏研、dagger2等浊、EventBus3.0、Retrofit 2.0等等摹蘑,不是說(shuō)這些庫(kù)完全基于AOP實(shí)現(xiàn)筹燕,只是說(shuō)里面部分功能基于AOP。

3. Java Annotation

Java Annotation是JDK5.0引入的一種注釋機(jī)制衅鹿。Java源代碼里面有自己的注解撒踪,我們還是很常見(jiàn)的:

java中的Annotation:

@Deprecated  -- @Deprecated 所標(biāo)注內(nèi)容,不再被建議使用大渤。
@Override    -- @Override 只能標(biāo)注方法制妄,表示該方法覆蓋父類中的方法。
@Documented  -- @Documented 所標(biāo)注內(nèi)容泵三,可以出現(xiàn)在javadoc中耕捞。
@Inherited   -- @Inherited只能被用來(lái)標(biāo)注“Annotation類型”衔掸,它所標(biāo)注的Annotation具有繼承性。
@Retention   -- @Retention只能被用來(lái)標(biāo)注“Annotation類型”砸脊,而且它被用來(lái)指定Annotation的RetentionPolicy屬性具篇。
@Target      -- @Target只能被用來(lái)標(biāo)注“Annotation類型”,而且它被用來(lái)指定Annotation的ElementType屬性凌埂。
@SuppressWarnings -- @SuppressWarnings 所標(biāo)注內(nèi)容產(chǎn)生的警告驱显,編譯器會(huì)對(duì)這些警告保持靜默。

當(dāng)然我們也可以自定義注解瞳抓,只是我們自定的注解需要我們自己去反射或者動(dòng)態(tài)代理來(lái)處理注解一次來(lái)實(shí)現(xiàn)AOP埃疫,自己處理還是比較麻煩,反射也是比較耗費(fèi)性能的孩哑,不建議使用栓霜,最好是Annotation+APT來(lái)做,把注解翻譯成Java代碼横蜒,避免性能損耗胳蛮,APT后面會(huì)說(shuō)到。

Java Annotation的本質(zhì)是使用了java的動(dòng)態(tài)代理丛晌,Annotation并不代表AOP仅炊,Java的AOP實(shí)現(xiàn)可以基于Java動(dòng)態(tài)代理,也可以基于Annotation澎蛛,但是自定義的Annotation需要結(jié)合 Java的動(dòng)態(tài)代理才可以實(shí)現(xiàn)AOP抚垄。

雖然源代碼我沒(méi)看過(guò),JavaWeb的一些庫(kù)JBoss谋逻、SpringFramework呆馁、AspectJ等等也是有使用Java Annotation,不可能所有的AOP都是完全自己去用動(dòng)態(tài)代理實(shí)現(xiàn)毁兆,不然寫起來(lái)也費(fèi)勁浙滤,用起來(lái)也不方便。
Java的Class類中有一系列支持Annotation和反射的實(shí)現(xiàn):

這里寫圖片描述

[點(diǎn)擊查看大圖]

里面有一個(gè)很關(guān)鍵的接口:AnnotatedElement气堕,里面是Class反射時(shí)對(duì)Annotation支持的一系列方法:

這里寫圖片描述

[點(diǎn)擊查看大圖]

具體的功能我就不解釋了纺腊,自己去查一下。
基于java的Annotation中的Target和Retention結(jié)合類似反射原理我們可以實(shí)現(xiàn)自己的AOP送巡。很多Android的AOP實(shí)現(xiàn)也是這么玩的。

4. Annotation的Android實(shí)現(xiàn)方式

Android是用Java寫的盒卸,上面說(shuō)到了的上面Java Annotation 動(dòng)態(tài)代理當(dāng)然都適用于Android骗爆,但是Android也有自己的AOP實(shí)現(xiàn)方式,但是Android的AOP實(shí)現(xiàn)原理跟Java的實(shí)現(xiàn)原理是一樣的蔽介。

再次強(qiáng)調(diào):

Java Annotation的本質(zhì)是使用了java的動(dòng)態(tài)代理摘投,Annotation并不代表AOP煮寡,Java的AOP實(shí)現(xiàn)可以基于Java動(dòng)態(tài)代理,也可以基于Annotation犀呼,但是自定義的Annotation需要結(jié)合 Java的動(dòng)態(tài)代理才可以實(shí)現(xiàn)AOP幸撕。

4.1 Android自帶基于Annotation的AOP實(shí)現(xiàn)

Android源碼中也有Google官方自定義的AndroidAnnotations,下面是代碼結(jié)構(gòu):

這里寫圖片描述

[點(diǎn)擊查看大圖]

右邊代碼展示的是Android自帶的Keep注解外臂,就是防止代碼混淆用到的坐儿,可以看到Keep同樣是基于Java Annotation自定義的而來(lái)的。源代碼我沒(méi)去看宋光,Android自定的注解實(shí)現(xiàn)也是基于Annotation和APT(注解處理工具)的AOP操作貌矿。

4.2 自定義Annotation加反射實(shí)現(xiàn)findViewById

自己的Annotation:

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface  ViewInject{
    int value();
}

Annotation反射處理工具:

public class AnnotateUtils {
    public static void injectViews(Activity activity) {
        Class<? extends Activity> object = activity.getClass(); // 獲取activity的Class
        Field[] fields = object.getDeclaredFields(); // 通過(guò)Class獲取activity的所有字段
        for (Field field : fields) { // 遍歷所有字段
            // 獲取字段的注解,如果沒(méi)有ViewInject注解罪佳,則返回null
            ViewInject viewInject = field.getAnnotation(ViewInject.class); 
            if (viewInject != null) {
                int viewId = viewInject.value(); // 獲取字段注解的參數(shù)逛漫,這就是我們傳進(jìn)去控件Id
                if (viewId != -1) {
                    try {
                        // 獲取類中的findViewById方法,參數(shù)為int
                        Method method = object.getMethod("findViewById", int.class);
                        // 執(zhí)行該方法赘艳,返回一個(gè)Object類型的View實(shí)例
                        Object resView = method.invoke(activity, viewId);
                        field.setAccessible(true);
                        // 把字段的值設(shè)置為該View的實(shí)例
                        field.set(activity, resView);
                    } catch (NoSuchMethodException e) {
                        e.printStackTrace();
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    } catch (InvocationTargetException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}

使用示例:

@ViewInject(R.id.buy)
private Button buy;
@ViewInject(R.id.money)
private TextView money;
@ViewInject(R.id.tv_power)
private TextView power;
@ViewInject(R.id.tv_life)
private TextView life;
@ViewInject(R.id.tv_dex)
private TextView dex;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    AnnotateUtils.injectViews(this);
}

4.3 Android開源庫(kù)使用Java Annotation

下面是 butterknife使用的注解:

這里寫圖片描述

[點(diǎn)擊查看大圖]

左邊是butterknife的注解酌毡,右邊是最常用的View綁定注解BindView,可以看到也是使用了java的Annotation中的@Retention()和@Target()蕾管。
其他的庫(kù)其實(shí)也差不多枷踏,這里就不一一截圖驗(yàn)證了。

雖然Java Annotation并不是AOP娇掏,但是為了方便使用AOP呕寝,為了更好的使用我們往往需要使用Annotation來(lái)輔助。具體體現(xiàn)就是這些開源庫(kù)的各種注解婴梧。

黃金天然不是貨幣下梢,而貨幣天然是黃金,是不是可以這樣撕逼一下:Annotation天然不是AOP塞蹭,而AOP天然是Annotation孽江。

5. 大話AOP與Android的愛(ài)恨情仇之AOP三大精鋼

三大精鋼分別是:APT、AspectJ番电、Javassist
下面是這三個(gè)的作用時(shí)間:


這里寫圖片描述

5.1 APT

APT用來(lái)在編譯時(shí)期掃描處理源代碼中的注解信息岗屏,我們可以根據(jù)注解信息生成一些文件,比如Java文件漱办。利用APT為我們生成的Java代碼这刷,實(shí)現(xiàn)冗余的代碼功能,這樣就減少手動(dòng)的代碼輸入娩井,提升了編碼效率暇屋,而且使源代碼看起來(lái)更清晰簡(jiǎn)潔。

請(qǐng)參考:利用APT實(shí)現(xiàn)Android編譯時(shí)注解

Dagger洞辣、ButterKnife咐刨、AndroidAnnotation昙衅、EventBus的注解實(shí)現(xiàn)AOP為什么非要使用APT?
如果不使用用APT基于注解動(dòng)態(tài)生成java代碼定鸟,那么就需要在運(yùn)行的時(shí)候使用反射或者動(dòng)態(tài)代理而涉,那么耗費(fèi)了不必要的性能,本來(lái)就是為了方便的庫(kù)反而更加耗費(fèi)性能那就沒(méi)人用了联予,使用APT增加了代碼量啼县,但是不耗費(fèi)性能,用起來(lái)方便高性能無(wú)察覺(jué)躯泰。

可以說(shuō)基于Java Annotation的自定義注解配合APT實(shí)現(xiàn)了很多簡(jiǎn)單易用性能優(yōu)越的AOP用法的開源庫(kù)谭羔。

5.2 AspectJ

  1. AspectJ是一個(gè)代碼生成工具(Code Generator)。

  2. AspectJ語(yǔ)法就是用來(lái)定義代碼生成規(guī)則的語(yǔ)法麦向。

Aspectj一個(gè)易用的瘟裸、功能強(qiáng)大的aop編程語(yǔ)言,AspectJ是AOP的Java語(yǔ)言的實(shí)現(xiàn)诵竭,AspectJ是一個(gè)代碼生成工具(Code Generator)话告。
使用AspectJ有兩種方法:

  1. 完全使用AspectJ的語(yǔ)言。這語(yǔ)言一點(diǎn)也不難卵慰,和Java幾乎一樣沙郭,也能在AspectJ中調(diào)用Java的任何類庫(kù)。AspectJ只是多了一些關(guān)鍵詞罷了裳朋。
  2. 或者使用純Java語(yǔ)言開發(fā)病线,然后使用AspectJ注解,簡(jiǎn)稱@AspectJ鲤嫡。

使用AspectJ用java開發(fā)時(shí)使用的AspectJ注解其實(shí)也是基于Java Annotation的送挑,下面看結(jié)構(gòu)圖:

這里寫圖片描述

[點(diǎn)擊查看大圖]

左邊是所有的AspectJ注解,右邊是AspectJ注解中最關(guān)鍵的Aspect注解暖眼,可以看到也是使用了java的Annotation中的@Retention()和@Target()惕耕。
這是我之前做的基于AspectJ做的統(tǒng)計(jì),生命周期監(jiān)聽和click監(jiān)聽:
https://github.com/Dawish/CustomViews/tree/master/Aoplib
請(qǐng)參考牛逼的文章:http://blog.csdn.net/innost/article/details/49387395

關(guān)鍵詞 說(shuō)明
Before 切入點(diǎn)之前執(zhí)行诫肠,切入點(diǎn)執(zhí)行之前我們可以先執(zhí)行我們的方法司澎,可以攔截切入點(diǎn)的執(zhí)行,比如攔截需要用戶支付或者登陸的操作
after 切入點(diǎn)之后執(zhí)行 栋豫,比如記錄用戶行為的操作
around 包含切入點(diǎn)的前后挤安,切入點(diǎn)的執(zhí)行可以控制。比如需要條件判斷再執(zhí)行丧鸯,執(zhí)行完成后給用戶提示的操作

需要著重說(shuō)一下Advice蛤铜,Advice就是我們插入的代碼以何種方式插入,有Before還有After、Around昂羡。

關(guān)鍵詞 說(shuō)明
Before 切入點(diǎn)之前執(zhí)行,切入點(diǎn)執(zhí)行之前我們可以先執(zhí)行我們的方法摔踱,可以攔截切入點(diǎn)的執(zhí)行虐先,比如攔截需要用戶支付或者登陸的操作
after 切入點(diǎn)之后執(zhí)行 ,比如記錄用戶行為的操作
around 包含切入點(diǎn)的前后派敷,切入點(diǎn)的執(zhí)行可以控制蛹批。比如需要條件判斷再執(zhí)行,執(zhí)行完成后給用戶提示的操作

示例:

    /**下面第一個(gè)*號(hào)表示被切入的方法不限定返回類型**/
    @Before("execution(* android.view.View.OnClickListener.onClick(..))")
    public void onUserAction(JoinPoint joinPoint){
        Log.e(TAG, "aop statistics click");
        Object[] args = joinPoint.getArgs();
        if(args == null || args.length == 0){
            return;
        }
        View clickView = (View) args[0];
        //你想做的操作
    }

上面是在執(zhí)行onClick之前切入篮愉,我們可以根據(jù)JoinPoint 來(lái)獲取onClick(View v)方法本身的參數(shù)腐芍,來(lái)對(duì)點(diǎn)擊的View做操作,我們也可以根據(jù)用戶的連續(xù)點(diǎn)擊間隔時(shí)間來(lái)防止點(diǎn)擊速度過(guò)快導(dǎo)致的雙擊试躏。
是不是很強(qiáng)大猪勇。
我們可以用JoinPoint 參數(shù)來(lái)獲取更多的內(nèi)容:

  • java.lang.Object[] getArgs():獲取連接點(diǎn)方法運(yùn)行時(shí)的入?yún)⒘斜恚?/li>
  • Signature getSignature() :獲取連接點(diǎn)的方法簽名對(duì)象;
  • java.lang.Object getTarget() :獲取連接點(diǎn)所在的目標(biāo)對(duì)象颠蕴;
  • java.lang.Object getThis() :獲取代理對(duì)象本身泣刹;

有了Before、After犀被、Around和JoinPoint 的四者配合椅您,真是6得飛起,可上天入地啊寡键,可以很方便完成Android開發(fā)中很惡心很繁瑣的任務(wù)掀泳。


這里寫圖片描述

來(lái),我們走一個(gè)西轩!

5.3 Javassist

Javassist是一個(gè)開源的分析员舵、編輯和創(chuàng)建Java字節(jié)碼的類庫(kù)。是由東京工業(yè)大學(xué)的數(shù)學(xué)和計(jì)算機(jī)科學(xué)系的 Shigeru Chiba
(千葉 滋)所創(chuàng)建的遭商。它已加入了開放源代碼JBoss
應(yīng)用服務(wù)器項(xiàng)目固灵,通過(guò)使用Javassist對(duì)字節(jié)碼操作為JBoss實(shí)現(xiàn)動(dòng)態(tài)"AOP"框架。 -- 百度百科

代表框架:熱修復(fù)框架HotFix 劫流、Savior(InstantRun)等

Javassist作用是在編譯器間修改class文件巫玻,與之相似的ASM(熱修復(fù)框架女媧)也有這個(gè)功能,可以讓我們直接修改編譯后的class二進(jìn)制代碼祠汇,首先我們得知道什么時(shí)候編譯完成仍秤,并且我們要趕在class文件被轉(zhuǎn)化為dex文件之前去修改。在Transfrom這個(gè)api出來(lái)之前可很,想要在項(xiàng)目被打包成dex之前對(duì)class進(jìn)行操作诗力,必須自定義一個(gè)Task,然后插入到predex或者dex之前我抠,在自定義的Task中可以使用javassist或者asm對(duì)class進(jìn)行操作苇本。而Transform則更為方便袜茧,Transfrom會(huì)有他自己的執(zhí)行時(shí)機(jī),不需要我們插入到某個(gè)Task前面瓣窄。Tranfrom一經(jīng)注冊(cè)便會(huì)自動(dòng)添加到Task執(zhí)行序列中笛厦,并且正好是項(xiàng)目被打包成dex之前。 來(lái)自--- http://www.reibang.com/p/dca3e2c8608a

Android熱補(bǔ)丁動(dòng)態(tài)修復(fù)技術(shù)請(qǐng)參考:http://blog.csdn.net/u010386612/article/details/51131642

Javassist我本身不是很熟俺夕,我就不多說(shuō)了裳凸,反正都TMD超級(jí)牛逼的東西。

本人家技術(shù)有限劝贸,上面很多都是自己基于自己的知識(shí)面說(shuō)的姨谷,不足不對(duì)之處還望各位同行不吝指教。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末映九,一起剝皮案震驚了整個(gè)濱河市梦湘,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌件甥,老刑警劉巖践叠,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異嚼蚀,居然都是意外死亡禁灼,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門轿曙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)弄捕,“玉大人,你說(shuō)我怎么就攤上這事导帝∈匚剑” “怎么了?”我有些...
    開封第一講書人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵您单,是天一觀的道長(zhǎng)斋荞。 經(jīng)常有香客問(wèn)我,道長(zhǎng)虐秦,這世上最難降的妖魔是什么平酿? 我笑而不...
    開封第一講書人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮悦陋,結(jié)果婚禮上蜈彼,老公的妹妹穿的比我還像新娘。我一直安慰自己俺驶,他們只是感情好幸逆,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般还绘。 火紅的嫁衣襯著肌膚如雪楚昭。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,631評(píng)論 1 305
  • 那天拍顷,我揣著相機(jī)與錄音哪替,去河邊找鬼。 笑死菇怀,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的晌块。 我是一名探鬼主播爱沟,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼匆背!你這毒婦竟也來(lái)了呼伸?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤钝尸,失蹤者是張志新(化名)和其女友劉穎括享,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體珍促,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡铃辖,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了猪叙。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片娇斩。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖穴翩,靈堂內(nèi)的尸體忽然破棺而出犬第,到底是詐尸還是另有隱情,我是刑警寧澤芒帕,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布歉嗓,位于F島的核電站,受9級(jí)特大地震影響背蟆,放射性物質(zhì)發(fā)生泄漏鉴分。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一带膀、第九天 我趴在偏房一處隱蔽的房頂上張望冠场。 院中可真熱鬧,春花似錦本砰、人聲如沸碴裙。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)舔株。三九已至莺琳,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間载慈,已是汗流浹背惭等。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留办铡,地道東北人辞做。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像寡具,于是被迫代替她去往敵國(guó)和親秤茅。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355

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