全網(wǎng)最深入 Android Style/Theme/Attr/Styleable/TypedArray 清清楚楚明明白白

前言

回顧一下:自定義View的時候乒融,根據(jù)不同條件設(shè)置不同顏色详民,那么需要提供對外的方法設(shè)置顏色吁伺。而View可以在xml里引用逞带,我們想當(dāng)然的認(rèn)為是否能夠在xml里根據(jù)不同條件設(shè)置顏色屬性呢欺矫?這樣的話就很靈活了。當(dāng)然展氓,Android系統(tǒng)已經(jīng)為我們準(zhǔn)備好了穆趴,接下來我們來分析其解析原理及其使用。
通過本篇文章遇汞,你將了解到:

1未妹、自定義屬性基礎(chǔ)明晰
2簿废、自定義屬性使用
3、attr/style/theme聯(lián)系與區(qū)別
4络它、自定義屬性加載優(yōu)先級
5族檬、自定義屬性加載源碼分析

自定義屬性基礎(chǔ)明晰

attrs.xml

注 為表述方便,以下的"屬性聲明" 指的是該屬性聲明了但沒有賦值化戳;而"屬性定義”指的是該屬性被使用单料,也即被賦值了。

在res->values目錄下新建attrs.xml文件点楼,該文件用來聲明屬性名及其接受的數(shù)據(jù)格式:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <attr name="attr_str" format="string"></attr>
    <attr name="attr_bool" format="boolean"></attr>
    <attr name="attr_int" format="integer"></attr>
    <attr name="attr_ref" format="reference"></attr>
</resources>

其中 name表示屬性名扫尖,format表示其接受的輸入格式。
以上聲明了三個屬性掠廓,分別代表string换怖、boolean、integer却盘、reference格式狰域。reference指向其它資源。
format還有其它格式黄橘,如:

color -- 顏色值
dimension -- 尺寸
float -- 浮點值
fraction -- 百分比
enum -- 枚舉
flag -- 位或運算
混合類型 -- 多種format結(jié)合

enum和flag聲明(可以不指定format) 兆览,如下:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <attr name="attr_enum">
        <enum name="first" value="1"></enum>
        <enum name="second" value="2"></enum>
        <enum name="third" value="3"></enum>
    </attr>

    <attr name="attr_flag">
        <flag name="east" value="0x1"></flag>
        <flag name="west" value="0x2"></flag>
        <flag name="south" value="0x3"></flag>
        <flag name="north" value="0x4"></flag>
    </attr>
</resources>

自定義屬性使用

原始使用方式

public class MyAttrView extends View {
    private final String TAG = MyAttrView.class.getSimpleName();

    public MyAttrView(Context context) {
        super(context);
    }

    public MyAttrView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);

        for (int i = 0; i < attrs.getAttributeCount(); i++) {
            Log.d(TAG, "name:" + attrs.getAttributeName(i) + "  value:" + attrs.getAttributeValue(i));
        }
    }
}

定義View: MyAttrView,并在布局xml里引用此View:

    <com.fish.myapplication.attr.MyAttrView
        app:attr_str="hello world str"
        app:attr_bool="true"
        app:attr_int="99"
        app:attr_ref="@dimen/dp_100"
        android:layout_width="100px"
        android:layout_height="100px">
    </com.fish.myapplication.attr.MyAttrView>

在布局xml里引用了在attrs.xml聲明的4個屬性塞关,并在MyAttrView里解析抬探。
AttributeSet是個xml解析工具類,幫助我們從布局的xml里提取屬性名和屬性值帆赢,它是個接口小压,實現(xiàn)類是:XmlBlock里的子類Parser。
將屬性名和屬性值打印椰于,結(jié)果如下:


image.png

可以看出怠益,AttributeSet將布局xml下的屬性全部打印出來了,但是有兩個問題:

1瘾婿、attr_ref屬性想要的是一個整數(shù)尺寸蜻牢,卻返回了資源編號。
2偏陪、layout_width/layout_height 我們并不關(guān)心此屬性抢呆,我們只關(guān)心自定義屬性。如果能傳入關(guān)心的屬性集合笛谦,并返回其值抱虐,那最好不過了。

有沒有一種方式能夠解決上述兩種問題呢饥脑?答案是:TypedArray恳邀。

進階使用方式(TypedArray)

依舊在attrs.xml里改造:

<resources>
    <declare-styleable name="MyStyleable">
        <attr name="attr_str" format="string"></attr>
        <attr name="attr_bool" format="boolean"></attr>
        <attr name="attr_int" format="integer"></attr>
        <attr name="attr_ref" format="reference"></attr>
    </declare-styleable>
</resources>

相比我們剛開始聲明的屬性而言懦冰,增加了“declare-styleable”標(biāo)簽,意思是將若干個屬性聲明歸結(jié)到MyStyleable里轩娶,這些屬性聲明屬于"同一組"儿奶。
再來看看如何解析這些屬性。

    public MyAttrView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);

        //R.styleable.MyStyleable 指的是想要解析的屬性
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MyStyleable);
        //count 表示解析出來的個數(shù)
        int count = typedArray.getIndexCount();
        for (int i = 0; i < count; i++) {
            int indexValue = typedArray.getIndex(i);
            //通過屬性index找到屬性值
            switch (indexValue) {
                case R.styleable.MyStyleable_attr_str:
                    String strValue = typedArray.getString(indexValue);
                    Log.d(TAG, "str value:" + strValue);
                    break;
                case R.styleable.MyStyleable_attr_bool:
                    boolean boolValue = typedArray.getBoolean(indexValue, false);
                    Log.d(TAG, "bool value:" + boolValue);
                    break;
                case R.styleable.MyStyleable_attr_int:
                    int intValue = typedArray.getInt(indexValue, 0);
                    Log.d(TAG, "int value:" + intValue);
                    break;
                case R.styleable.MyStyleable_attr_ref:
                    float refValue = typedArray.getDimension(indexValue, 0);
                    Log.d(TAG, "float value:" + refValue);
                    break;
            }
        }
        //typedArray 存放在緩存池鳄抒,因此用完歸還到緩存池
        typedArray.recycle();
    }

運行效果如下:


image.png

看得出來闯捎,尺寸的結(jié)果已經(jīng)轉(zhuǎn)換為實際值了。

重點方法如下:
context.obtainStyledAttributes(attrs, R.styleable.MyStyleable)

    public final TypedArray obtainStyledAttributes(
            @Nullable AttributeSet set, @NonNull @StyleableRes int[] attrs) {
        return getTheme().obtainStyledAttributes(set, attrs, 0, 0);
    }

有兩個參數(shù):

AttributeSet set :當(dāng)前xml聲明的屬性集合
int[] attrs :想要取得屬性值的屬性名集合

可以看出R.styleable.MyStyleable實際上就是個整形數(shù)組许溅。與res目錄下的其它資源類似瓤鼻,其索引在編譯時期生成在R.java里。


image.png

數(shù)組里的元素值就是MyStyleable聲明里的屬性索引贤重,同樣的在R.java里找到其索引:
image.png

可以看出茬祷,R.styleable.MyStyleable就是我們想要解析的屬性名集合。
AttributeSet set 與 int attrs[]關(guān)系:
image.png

obtainStyledAttributes 方法返回值類型:TypedArray并蝗。該類型記錄了獲取到的屬性值集合(記錄在數(shù)組里)祭犯,而通過數(shù)組下標(biāo)索引即可找到對應(yīng)的屬性值。索引下標(biāo)通過R.styleable.MyStyleable_xx獲取滚停,"xx"表示屬性名沃粗,一般命名為"styleable名" + "_" + "屬性名"。同樣的键畴,這些值也記錄在R.java里:


image.png

在R.java里
MyStyleable_attr_bool 代表數(shù)組索引下標(biāo)
MyStyleable 代表屬性數(shù)組
attr_bool 代表屬性
總結(jié)來說:通過下標(biāo)取數(shù)組里屬性

綜上所述最盅,TypedArray很好地解決了我們在使用"原始方式"獲取屬性遇到的問題。

attr/style/theme聯(lián)系與區(qū)別

style 由來與作用

在res->values目錄下起惕,找到styles.xml文件(沒有則新建):

<resources>
    <style name="myStyle">
        <item name="attr_str">str in myStyle</item>
        <item name="attr_bool">true</item>
    </style>
</resources>

可以看出style批量定義了一批屬性涡贱。這樣做的好處顯而易見:利于復(fù)用屬性集合。
比如我們自定義的MyAttrView作為公共控件使用:

    <com.fish.myapplication.attr.MyAttrView
        app:attr_str="hello world str"
        app:attr_bool="true"
        android:layout_width="100px"
        android:layout_height="100px">
    </com.fish.myapplication.attr.MyAttrView>

使用的屬性值都是一樣的惹想,那么可以將這些屬性提取出來作為一個style項问词,在引用的時候引用style即可,不用到處重復(fù)定義屬性嘀粱。

    <com.fish.myapplication.attr.MyAttrView
        style="@style/myStyle"
        android:layout_width="100px"
        android:layout_height="100px">
    </com.fish.myapplication.attr.MyAttrView>

theme 由來與作用

在res->values目錄下激挪,找到themes.xml文件(沒有則新建)

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="myTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <item name="attr_str">str in myTheme</item>
        <item name="attr_bool">true</item>
    </style>
</resources>

theme實際上也是用了style語法,parent表示其父類主題草穆,子類繼承父類屬性灌灾。theme如何使用呢搓译?
之前說過style為了View之間復(fù)用屬性集悲柱,那么theme是為了Activity/Application復(fù)用屬性集。因此些己,我們將theme配置給Activity或者Application豌鸡。


image.png

可以看出引用theme是通過style引用的嘿般,因此我們可以直接將style條目作為theme使用,只是一般為了直觀定義了themes.xml文件涯冠,該文件里的style作為theme使用炉奴。
總結(jié)來說三者關(guān)系:

style 是定義屬性的集合,使用style標(biāo)簽蛇更,作用于View
theme 是定義屬性的集合瞻赶,使用style標(biāo)簽,作用于Application/Activity
declare-styleable 是聲明屬性的集合派任,使用declare-styleable標(biāo)簽

自定義屬性加載優(yōu)先級

通過上述分析砸逊,定義屬性的方式目前看來有以下3種:

1、在布局文件里定義屬性
2掌逛、在style里定義屬性
3师逸、在theme里定義屬性

再重新來看看obtainStyledAttributes(xx)方法:

    public final TypedArray obtainStyledAttributes(
            @Nullable AttributeSet set, @NonNull @StyleableRes int[] attrs) {
        return getTheme().obtainStyledAttributes(set, attrs, 0, 0);
    }

    public TypedArray obtainStyledAttributes(@Nullable AttributeSet set,
                                             @NonNull @StyleableRes int[] attrs, @AttrRes int defStyleAttr,
                                             @StyleRes int defStyleRes) {
        return mThemeImpl.obtainStyledAttributes(this, set, attrs, defStyleAttr, defStyleRes);
    }

第二個方法有4個參數(shù),前面兩個前面分析過豆混,來看看后邊兩個:

@AttrRes int defStyleAttr 形參限制為AttrRes篓像,說明是屬性類型
@StyleRes int defStyleRes 形參限制為StyleRes,說明是style類型
從形參名字來看皿伺,顯然是默認(rèn)的屬性與默認(rèn)的style员辩。

由此看出,obtainStyledAttributes(xx)方法負(fù)責(zé)解析了來自5個地方的屬性:

1心傀、在布局文件里定義屬性
2屈暗、在style里定義屬性
3、在theme里定義屬性
4脂男、默認(rèn)的屬性
5养叛、默認(rèn)的style

問題來了:如果上述5個來處都定義了同一個屬性,那么該以哪個屬性值為準(zhǔn)呢宰翅?在真相尚未揭開之前弃甥,用最基本的方法,一一測試來看規(guī)律汁讼。
首先先將各個屬性來處定義淆攻,以"attr_str"屬性為例:
1、在布局里定義屬性并使用:

#layout.xml 定義并使用
    <com.fish.myapplication.attr.MyAttrView
        app:attr_str="str in myLayout"
        android:layout_width="100px"
        android:layout_height="100px">
    </com.fish.myapplication.attr.MyAttrView>

2嘿架、在style定義屬性并使用:

#styles.xml 定義
    <style name="myStyle">
        <item name="attr_str">str in myStyle</item>
    </style>

#layout.xml 里使用style
    <com.fish.myapplication.attr.MyAttrView
        style="@style/myStyle"
        android:layout_width="100px"
        android:layout_height="100px">
    </com.fish.myapplication.attr.MyAttrView>

3瓶珊、使用默認(rèn)屬性:

#themes.xml定義
#attr_ref 是引用類型的屬性,這里指向style
    <style name="myTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <item name="attr_ref">@style/myDefaultAttr</item>
    </style>

#styles.xml
    <style name="myDefaultAttr">
        <item name="attr_str">str in myDefaultAttr</item>
    </style>

#MyAttrView.java 里解析 傳入R.attr.attr_ref耸彪,最終找到myDefaultAttr里的attr_str屬性

context.obtainStyledAttributes(attrs, R.styleable.MyStyleable, R.attr.attr_ref, 0);

4伞芹、使用默認(rèn)style:

#在styles.xml里定義
    <style name="myDefaultStyle">
        <item name="attr_str">str in myDefaultStyle</item>
    </style>

#MyAttrView.java 里解析 傳入R.style.myDefaultStyle,最終找到myDefaultStyle里的attr_str屬性
context.obtainStyledAttributes(attrs, R.styleable.MyStyleable, 0, R.style.myDefaultStyle);

5、使用theme里定義的屬性:

#themes.xml里定義
    <style name="myTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <item name="attr_str">str in myTheme</item>
    </style>

context.obtainStyledAttributes(attrs, R.styleable.MyStyleable, 0, 0);

為了區(qū)分屬性值取自哪唱较,我們在不同的地方打印了相應(yīng)的關(guān)鍵字扎唾。上面定義了
1~ 5個不同來處的屬性,現(xiàn)在倒序從5 ~ 1依次添加這些屬性定義南缓。使用TypedArray解析出屬性值:

    public MyAttrView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);

        //R.styleable.MyStyleable 指的是想要解析的屬性
        TypedArray typedArray = context.obtainStyledAttributes(attrs, null, 0, R.style.myDefaultStyle);
        //count 表示解析出來的個數(shù)
        int count = typedArray.getIndexCount();
        for (int i = 0; i < count; i++) {
            int indexValue = typedArray.getIndex(i);
            //通過屬性index找到屬性值
            switch (indexValue) {
                case R.styleable.MyStyleable_attr_str:
                    String strValue = typedArray.getString(indexValue);
                    Log.d(TAG, "str value:" + strValue);
                    break;
            }
        }
        typedArray.recycle();
    }

五次運行結(jié)果如下:


image.png

我們依次添加的屬性定義胸遇,后面添加的將前面覆蓋了,說明后面添加的優(yōu)先級更高汉形,因此總結(jié)來說纸镊,自定義屬性優(yōu)先級自高到低是:

1、在布局文件里定義屬性
2概疆、在style里定義屬性
3薄腻、在theme里定義屬性
4、默認(rèn)的屬性
5届案、默認(rèn)的style

自定義屬性加載源碼分析

雖然以上通過測試說明了屬性是如何解析及其解析的優(yōu)先級庵楷,但是為了更好地理解其實際運作過程,我們需要分析源碼楣颠。從TypedArray和obtainStyledAttributes(xx)方法入手尽纽。
來看看obtainStyledAttributes(xx)調(diào)用流程:


image.png

applyStyle調(diào)用了native方法:

 nativeApplyStyle(mObject, themePtr, defStyleAttr, defStyleRes,
                    parser != null ? parser.mParseState : 0, inAttrs, outValuesAddress,
                    outIndicesAddress);

注意到最后兩個參數(shù),分別對應(yīng)TypedArray兩個參數(shù):

outValuesAddress --> int[] mData;
outIndicesAddress --> int[] mIndices

最終調(diào)用了AttributeResolution.cpp 的ApplyStyle(xx)方法:

void ApplyStyle(Theme* theme, ResXMLParser* xml_parser, uint32_t def_style_attr,
                uint32_t def_style_resid, const uint32_t* attrs, size_t attrs_length,
                uint32_t* out_values, uint32_t* out_indices) {
  //省略...
  int indices_idx = 0;
  uint32_t def_style_flags = 0u;
  //如果傳入了默認(rèn)屬性
  if (def_style_attr != 0) {
    Res_value value;
    //加載默認(rèn)屬性
    if (theme->GetAttribute(def_style_attr, &value, &def_style_flags) != kInvalidCookie) {
      if (value.dataType == Res_value::TYPE_REFERENCE) {
        //并將值賦值給默認(rèn)style童漩,可以看出默認(rèn)屬性優(yōu)先級高于默認(rèn)style
        def_style_resid = value.data;
      }
    }
  }

  //遍歷屬性名集合弄贿,也就是declare-styleable 聲明的屬性集合
  for (size_t ii = 0; ii < attrs_length; ii++) {
    //1、先加載XM里定義的屬性
    if (xml_attr_idx != xml_attr_finder.end()) {
      // We found the attribute we were looking for.
      xml_parser->getAttributeValue(xml_attr_idx, &value);
    }

    if (value.dataType == Res_value::TYPE_NULL && value.data != Res_value::DATA_NULL_EMPTY) {
      //2矫膨、上一步如果沒找到差凹,繼續(xù)在xml里的style里找
      if (entry != xml_style_attr_finder.end()) {
        // We found the attribute we were looking for.
        cookie = entry->cookie;
        type_set_flags = style_flags;
        value = entry->value;
        value_source_resid = entry->style;
      }
    }

    if (value.dataType == Res_value::TYPE_NULL && value.data != Res_value::DATA_NULL_EMPTY) {
      //3、還是沒找到侧馅,找默認(rèn)style
      //這里需要注意的是危尿,上面用默認(rèn)attr賦值給默認(rèn)style,因此如果attr不為空馁痴,那么先加載了attr
      //如果為空谊娇,那么加載默認(rèn)style
      if (entry != def_style_attr_finder.end()) {
        cookie = entry->cookie;
        type_set_flags = def_style_flags;
        value = entry->value;
      }
    }

    if (value.dataType != Res_value::TYPE_NULL) {
      //省略
    } else if (value.data != Res_value::DATA_NULL_EMPTY) {
      ApkAssetsCookie new_cookie = theme->GetAttribute(cur_ident, &value, &type_set_flags);
      if (new_cookie != kInvalidCookie) {
        //4、前面步驟都找不到罗晕,最后嘗試加載theme里的屬性
        new_cookie =
            assetmanager->ResolveReference(new_cookie, &value, &config, &type_set_flags, &resid);
        if (new_cookie != kInvalidCookie) {
          cookie = new_cookie;
        }
      }
    }
   //out_values存放類型济欢、屬性值,資源id小渊,密度等
    out_values[STYLE_TYPE] = value.dataType;
    out_values[STYLE_DATA] = value.data;
    out_values[STYLE_ASSET_COOKIE] = ApkAssetsCookieToJavaCookie(cookie);
    out_values[STYLE_RESOURCE_ID] = resid;
    out_values[STYLE_CHANGING_CONFIGURATIONS] = type_set_flags;
    out_values[STYLE_DENSITY] = config.density;
    out_values[STYLE_SOURCE_RESOURCE_ID] = value_source_resid;
    if (value.dataType != Res_value::TYPE_NULL || value.data == Res_value::DATA_NULL_EMPTY) {
      indices_idx++;
      //記錄數(shù)組的值法褥,ii即為屬性名的
      out_indices[indices_idx] = ii;
    }
    //步長,out_values存放屬性值酬屉,類型等半等,因此需要步長來區(qū)分某個屬性存放塊的開始
    out_values += STYLE_NUM_ENTRIES;
  }

  //out_indices 的第一個元素存放著找到有效屬性值的個數(shù)
  out_indices[0] = indices_idx;
}

該方法比較長,省略了一些地方,主要做了兩件事:

1酱鸭、上面的1~4步驟實際上就是確定了加載屬性的優(yōu)先級
2、記錄查詢到的屬性值放在TypedArray里垛吗。

來看看和TypedArray關(guān)系
typedArray.getIndexCount():

    public int getIndexCount() {
        if (mRecycled) {
            throw new RuntimeException("Cannot make calls to a recycled instance!");
        }
        //這個值存放的是加載到有效屬性個數(shù)
        return mIndices[0];
    }

typedArray.getIndex(i);

    public int getIndex(int at) {
        //第一個元素記錄著個數(shù)凹髓,因此往后+1
        return mIndices[1+at];
    }

mIndices[]記錄著屬性名索引,還記得之前說過的在R.java里生成的

    public static final int MyStyleable_attr_bool=0;
    public static final int MyStyleable_attr_int=1;
    public static final int MyStyleable_attr_ref=2;
    public static final int MyStyleable_attr_str=3;

記錄著就是如上的值怯屉。而這些又可以索引到具體的屬性:

    public static final int[] MyStyleable={
      0x7f02002b, 0x7f02002c, 0x7f02002d, 0x7f02002e
    };

再來看看獲取屬性值:
indexValue = typedArray.getIndex(i);
typedArray.getString(indexValue);
最終從TypedArray int[] mData里尋找蔚舀,該數(shù)組在上面的ApplyStyle里填充。
最后來直觀理解typedArray.getIndexCount()與TypedArray的mLength關(guān)系

    <com.fish.myapplication.attr.MyAttrView
        app:attr_str="str in myLayout"
        app:attr_bool="true"
        android:layout_width="100px"
        android:layout_height="100px">
    </com.fish.myapplication.attr.MyAttrView>

#attrs.xml
    <declare-styleable name="MyStyleable">
        <attr name="attr_str" format="string"></attr>
        <attr name="attr_bool" format="boolean"></attr>
        <attr name="attr_int" format="integer"></attr>
        <attr name="attr_ref" format="reference"></attr>
    </declare-styleable>

以上我們只是定義了兩個屬性锨络,而MyStyleable里聲明了4個屬性赌躺,因此TypedArray mIndices[] 有效屬性個數(shù)為2。而mLength 表示mIndices[]數(shù)組長度羡儿。
值得注意的是:

TypedArray 實例是可以復(fù)用的礼患,mIndices[] 長度只會變長。因此也許你調(diào)試的時候發(fā)現(xiàn)mIndices[] 并不一定等于4掠归,有可能更大缅叠。

以上就是自定義屬性相關(guān)的分析。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末虏冻,一起剝皮案震驚了整個濱河市肤粱,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌厨相,老刑警劉巖领曼,帶你破解...
    沈念sama閱讀 216,591評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異蛮穿,居然都是意外死亡庶骄,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評論 3 392
  • 文/潘曉璐 我一進店門践磅,熙熙樓的掌柜王于貴愁眉苦臉地迎上來瓢姻,“玉大人,你說我怎么就攤上這事音诈』眉睿” “怎么了?”我有些...
    開封第一講書人閱讀 162,823評論 0 353
  • 文/不壞的土叔 我叫張陵细溅,是天一觀的道長褥傍。 經(jīng)常有香客問我,道長喇聊,這世上最難降的妖魔是什么恍风? 我笑而不...
    開封第一講書人閱讀 58,204評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上朋贬,老公的妹妹穿的比我還像新娘凯楔。我一直安慰自己,他們只是感情好锦募,可當(dāng)我...
    茶點故事閱讀 67,228評論 6 388
  • 文/花漫 我一把揭開白布摆屯。 她就那樣靜靜地躺著,像睡著了一般糠亩。 火紅的嫁衣襯著肌膚如雪虐骑。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,190評論 1 299
  • 那天赎线,我揣著相機與錄音廷没,去河邊找鬼。 笑死垂寥,一個胖子當(dāng)著我的面吹牛颠黎,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播滞项,決...
    沈念sama閱讀 40,078評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼盏缤,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了蓖扑?” 一聲冷哼從身側(cè)響起唉铜,我...
    開封第一講書人閱讀 38,923評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎律杠,沒想到半個月后潭流,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,334評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡柜去,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,550評論 2 333
  • 正文 我和宋清朗相戀三年灰嫉,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片嗓奢。...
    茶點故事閱讀 39,727評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡讼撒,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出股耽,到底是詐尸還是另有隱情根盒,我是刑警寧澤,帶...
    沈念sama閱讀 35,428評論 5 343
  • 正文 年R本政府宣布物蝙,位于F島的核電站炎滞,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏诬乞。R本人自食惡果不足惜册赛,卻給世界環(huán)境...
    茶點故事閱讀 41,022評論 3 326
  • 文/蒙蒙 一钠导、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧森瘪,春花似錦牡属、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至痰驱,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間瞳浦,已是汗流浹背担映。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留叫潦,地道東北人蝇完。 一個月前我還...
    沈念sama閱讀 47,734評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像矗蕊,于是被迫代替她去往敵國和親短蜕。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,619評論 2 354

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