Android Studio自定義模板之MVPActivity

前言

Android開發(fā)中經(jīng)常需要?jiǎng)?chuàng)建Activity递惋。一般情況下,咱們都是"New"->Java Class/Activity溺忧。但是Android Studio自帶的Activity模板都比較簡(jiǎn)單突梦,未必符合我們所需的模板樣式。例如在MVP框架下笛辟,需創(chuàng)建Activity功氨、Present、Contract手幢、Model等文件捷凄,并關(guān)聯(lián)關(guān)系,初始化围来、author跺涤、統(tǒng)一的網(wǎng)絡(luò)請(qǐng)求寫法匈睁。所以我們需要自定義模板,幫我們省去這一系列重復(fù)操作桶错。

舉個(gè)栗子航唆,創(chuàng)建自定義MVP模板(本文較長,趕時(shí)間的小伙伴可以到底部下載源碼)


演示MVP.gif

圖解1 配置創(chuàng)建信息

MVP Name為紅框標(biāo)記部分統(tǒng)一命名(Activity牛曹、Layout佛点、Contract、Model黎比、Present)超营。由Generate MVP File選擇框決定是否在生成activity的同時(shí)生成Contract、Model和Presenter等Java類阅虫。


創(chuàng)建MVPActivity

圖解2 文件結(jié)構(gòu)

點(diǎn)擊Finish完成創(chuàng)建后演闭,可以看到自動(dòng)生成的文件(如下圖)


自動(dòng)生成的文件

這里我們主要看自動(dòng)生成的HomePageActivity。其他仨請(qǐng)看開頭Gif颓帝,這里就不一一截圖了


HomeMvpActivity

以上內(nèi)容均為自動(dòng)生成米碰,使用過MVP的小伙伴是不是很熟悉?是不是很方便购城?媽媽再也不用擔(dān)心我的CV大法導(dǎo)致代碼區(qū)域亂七八糟了吕座。

PS:每個(gè)項(xiàng)目MVP有或多或少差異,大家可以根據(jù)項(xiàng)目實(shí)際編寫合適的模板瘪板。

附上Activity分區(qū)注釋

    /*-----------------------靜態(tài)Activity啟動(dòng)方法區(qū)-------------------*/
    /*-----------------------常量聲明區(qū)-------------------------------*/
    /*-----------------------UI控件成員變量聲明區(qū)---------------------*/
    /*-----------------------普通成員變量聲明區(qū)-----------------------*/
    /*-----------------------初始化相關(guān)方法區(qū)-------------------------*/
    /*-----------------------生命周期回調(diào)方法區(qū)(除onCreate()方法外)- */
    /*-----------------------事件響應(yīng)方法區(qū)---------------------------*/
    /*-----------------------重載的邏輯方法區(qū)-------------------------*/
    /*-----------------------普通邏輯方法區(qū)---------------------------*/
    /*-----------------------內(nèi)部接口聲明區(qū)---------------------------*/
    /*-----------------------內(nèi)部類聲明區(qū)-----------------------------*/

如何自定義模板

1.熟悉安卓模板

在Android Studio的安裝目錄下 \plugins\android\lib\templates\activities(同Mac)保存著系統(tǒng)自帶的activity模板和我們自定義的模板

\plugins\android\lib\templates\activities

在編寫自定義模板前吴趴,需要熟悉下模板的結(jié)構(gòu)和組成,這里我們從最簡(jiǎn)單的模板EmptyActivity入手
EmptyActivity目錄

src:代碼文件侮攀,生成對(duì)應(yīng)的文件模板
globals.xml.ftl:Java類庫锣枝,主要用于提供參數(shù)±加ⅲ可存儲(chǔ)全局變量以供其他模板文件統(tǒng)一引用
recipe.xml.ftl:用于組合生成我們實(shí)際需要的代碼文件和布局文件等撇叁。
template.xml:相當(dāng)于Android中的布局文件,用于圖形化提供參數(shù)畦贸,布局等陨闹。
template_blank_activity.png:模板照片

自定義模板通常都是復(fù)制已有,然后再修改修改

globals.xml.ftl

存儲(chǔ)一些全局變量

存儲(chǔ)全局變量薄坏。每一個(gè)變量定義正林,由id 唯一標(biāo)識(shí),type 類型颤殴,value 實(shí)際值組成

recipe.xml.ftl

recipe.xml.ftl

即便不懂freemarker引擎也不影響觅廓,也能依樣畫葫蘆,這里就簡(jiǎn)單講下用到的標(biāo)簽及含義:

  • instantiate 將 ftl->java文件涵但,中間會(huì)通過一個(gè)步驟杈绸,將ftl中的變量都換成對(duì)應(yīng)的值帖蔓,完整的流程是 ftl->freemarker process -> java 。
  • open 用于轉(zhuǎn)換完成時(shí)在項(xiàng)目中對(duì)應(yīng)的包下生成對(duì)應(yīng)文件瞳脓,例如Activity
  • if if指令塑娇,這里if判斷是否生成layout文件
    • <#if >
      <#elseif >
      <#else >
      </#if >

template.xml

template.xml

template.xml

對(duì)應(yīng)用戶輸入的模板界面,
<parameter>獲取用戶輸入?yún)?shù)

  • id 唯一標(biāo)識(shí)劫侧,通過該屬性埋酬,獲取輸入值,也可用于其他文件查找引用
  • name 標(biāo)簽名稱烧栋,類似label展示給用戶看
  • type 輸入值類型
  • constraints 填寫值的約束
  • suggest 建議值写妥,例如填寫Activity Name,給出一個(gè)建議值
  • help 底部提示語言审姓,對(duì)應(yīng)圖形化界面操作
    New EmptyActivity

幾個(gè)文件的整體的關(guān)系類似下圖:

關(guān)系圖

圖片來源:http://www.slideshare.net/murphonic/custom-android-code-templates-15537501


2.定義MVPActivity模板

了解完以上簡(jiǎn)單介紹珍特,基本足夠我們寫自(zhào)定(yàng)義(huà)模(hú)板(lū)

2.1創(chuàng)建MVPActivity文件夾

一般都是復(fù)制現(xiàn)有的(例如EmptyActivity,或者文章末尾的源碼)魔吐,再改改扎筒。


目錄\plugins\android\lib\templates\activities

添加MVP所對(duì)應(yīng)文件


MVPActivity目錄

2.2編寫MVP相關(guān)文件

activity_mvp.xml.ftl

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="${packageName}.${activityClass}">

</RelativeLayout>

IContract.java.ftl

package ${packageName};

import com.xx.mvp.base.BaseModel;
import com.xx.mvp.base.BasePresenter;
import com.xx.mvp.base.BaseView;
import rx.Observable;
<#assign aDateTime = .now>
/**
 * Model: {@link ${modelName}} View:{@link ${activityClass}} Presenter:{@link ${presenterName}}
 * @Author: ${author}
 * @Description: 
 * @Date: Create in ${aDateTime}
 * @Modified By:
 */
public interface ${contractName} {

   interface Model extends BaseModel {
        /**
         * 更新數(shù)據(jù)
         *
         * @return
         */
        Observable<Object> update();

    }

    interface View extends BaseView {

    }

    interface Presenter extends BasePresenter<Model, View> {

        /**
         * 更新數(shù)據(jù)
         */
        void update();
    }
    
}

Model.java.ftl

package ${packageName};

import com.xx.bean.base.BaseResult;
import com.xx.http.rx.TransformUtils;
import com.xx.mvp.base.BaseModelImpl;
import retrofit2.http.POST;
import rx.Observable;
<#assign aDateTime = .now>
/**
 * Present: {@link ${presenterName}}
 * @Author: ${author}
 * @Description: 
 * @Date: Create in  ${aDateTime}
 * @Modified By:
 */
public class ${modelName} extends BaseModelImpl<${modelName}.Service> implements ${contractName}.Model {
    public ${modelName}() {super(${modelName}.Service.class);}

    @Override
    public Observable<Object> update() {
        return getRequestService()
                .update()
                .compose(TransformUtils.defaultSchedulers());
    }

    public interface Service {
        /**
         * 更新數(shù)據(jù)
         *
         * @return
         */
        @POST("pos-web/updateAllData")
        Observable<BaseResult<Object>> update();
    }
}

MVPActivity.java.ftl

package ${packageName};

import ${superClassFqcn};
import android.os.Bundle;
<#if includeCppSupport!false>
import android.widget.TextView;
</#if>
<#assign aDateTime = .now>
/**
<#if generateMVP>
 * Model: {@link ${modelName}} Presenter:{@link ${presenterName}}
</#if>
 * @Author: ${author}
 * @Description: 
 * @Date: Create in ${aDateTime}
 * @Modified By:
 */
<#if generateMVP>
public class ${activityClass} extends BaseActivity<${contractName}.Model, ${contractName}.View, ${contractName}.Presenter> implements ${contractName}.View {
<#else>
public class ${activityClass} extends BaseActivity{
</#if>

    /*-----------------------靜態(tài)Activity啟動(dòng)方法區(qū)-------------------*/

    public static void startActivity(Activity activity) {
        Intent intent = new Intent(activity, ${activityClass}.class);
        activity.startActivity(intent);
    }
    
    /*-----------------------常量聲明區(qū)-------------------------------*/
    /*-----------------------UI控件成員變量聲明區(qū)---------------------*/
    /*-----------------------普通成員變量聲明區(qū)-----------------------*/
    /*-----------------------初始化相關(guān)方法區(qū)-------------------------*/

    @Override
    public int getContentView() {
        return R.layout.${layoutName};
    }

    @Override
    public void initView(Bundle savedInstanceState, View titleLayout) {

    }

    @Override
    public void initData(Intent intent) {
        getPresenter().update();
    }
  

<#if generateMVP>
    @Override
    public ${contractName}.Model createModel() {
        return new ${modelName}();
    }

    @Override
    public ${contractName}.View createView() {
        return this;
    }

    @Override
    public ${contractName}.Presenter createPresenter() {
        return new ${presenterName}();
    }
<#else>
    @Override
    public BasePresenter createPresenter() {
        return null;
    }
</#if>

    /*-----------------------生命周期回調(diào)方法區(qū)(除onCreate()方法外)-*/
    /*-----------------------事件響應(yīng)方法區(qū)---------------------------*/
    /*-----------------------重載的邏輯方法區(qū)-------------------------*/
    /*-----------------------普通邏輯方法區(qū)---------------------------*/
    /*-----------------------內(nèi)部接口聲明區(qū)---------------------------*/
    /*-----------------------內(nèi)部類聲明區(qū)-----------------------------*/
   
}

Presenter.java.ftl

package ${packageName};

import android.os.Bundle;
import com.xx.http.rx.BaseSubscribe;
import com.xx.mvp.base.BasePresenterImpl;
import rx.Subscription;

<#assign aDateTime = .now>
/**
 * Model: {@link ${modelName}} View:{@link ${activityClass}}
 * @Author: ${author}
 * @Description: 
 * @Date: Create in ${aDateTime}
 * @Modified By:
 */
class ${presenterName} extends BasePresenterImpl<${contractName}.Model, ${contractName}.View>
        implements ${contractName}.Presenter {

    @Override
    public void onCreate(Bundle savedInstanceState) {

    }
    
    /**
     * 更新數(shù)據(jù)
     */
    @Override
    public void update() {
        Subscription subscribe = getModel().update()
                .subscribe(new BaseSubscribe<Object>(this) {
                    @Override
                    protected void onSuccess(Object bean) {
                    }
                });
        addSubscribeRequest(subscribe);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }

}

2.3編寫配置文件

template.xml 定義界面

<?xml version="1.0"?>
<template
    format="5"
    revision="5"
    name="MVPActivity"
    minApi="9"
    minBuildApi="14"
    description="Creates a new empty activity">

    <category value="Activity" />
    <formfactor value="Mobile" />

    <parameter
        id="instantAppActivityHost"
        name="Instant App URL Host"
        type="string"
        suggest="${companyDomain}"
        default="instantapp.example.com"
        visibility="isInstantApp!false"
        help="The domain to use in the Instant App route for this activity"/>

    <parameter
        id="instantAppActivityRouteType"
        name="Instant App URL Route Type"
        type="enum"
        default="pathPattern"
        visibility="isInstantApp!false"
        help="The type of route to use in the Instant App route for this activity" >
        <option id="path">Path</option>
        <option id="pathPrefix">Path Prefix</option>
        <option id="pathPattern">Path Pattern</option>
    </parameter>

    <parameter
        id="instantAppActivityRoute"
        name="Instant App URL Route"
        type="string"
        default="/.*"
        visibility="isInstantApp!false"
        help="The route to use in the Instant App route for this activity"/>
<parameter
        id="activityName"
        name="MVP Name"
        type="string"
        constraints="nonempty"
        default="MVP"
        help="The name of the MVP class to create" />
    <parameter
        id="activityClass"
        name="MVPActivity Name"
        type="string"
        constraints="class|unique|nonempty"
        suggest="${activityName}Activity"
        default="MainActivity"
        help="The name of the activity class to create" />

    <parameter
        id="generateLayout"
        name="Generate Layout File"
        type="boolean"
        default="true"
        help="If true, a layout file will be generated" />

    <parameter
        id="layoutName"
        name="Layout Name"
        type="string"
        constraints="layout|unique|nonempty"
        suggest="${activityToLayout(activityName)}"
        default="activity_main"
        visibility="generateLayout"
        help="The name of the layout to create for the activity" />

    <parameter
        id="generateMVP"
        name="Generate MVP File"
        type="boolean"
        default="true"
        help="If true, a mvp file will be generated" />

        <parameter
        id="contractName"
        name="MVP Contract"
        type="string"
        suggest="${activityName}Contract"
        help="The name of the contract to create for the activity" />
        <parameter
        id="modelName"
        name="MVP Model"
        type="string"
        suggest="${activityName}Model"
        help="The name of the model to create for the activity" />
        <parameter
        id="presenterName"
        name="MVP Presenter"
        type="string"
        suggest="${activityName}Presenter"
        help="The name of the presenter to create for the activity" />

    <parameter
        id="isLauncher"
        name="Launcher Activity"
        type="boolean"
        default="false"
        help="If true, this activity will have a CATEGORY_LAUNCHER intent filter, making it visible in the launcher" />

    <parameter
        id="backwardsCompatibility"
        name="Backwards Compatibility (AppCompat)"
        type="boolean"
        default="true"
        help="If false, this activity base class will be Activity instead of AppCompatActivity" />
    
    <parameter
        id="packageName"
        name="Package name"
        type="string"
        constraints="package"
        default="com.mycompany.myapp" />

    <!-- 128x128 thumbnails relative to template.xml -->
    <thumbs>
        <!-- default thumbnail is required -->
        <thumb>template_blank_activity.png</thumb>
    </thumbs>

    <globals file="globals.xml.ftl" />
    <execute file="recipe.xml.ftl" />

</template>

recipe.xml.ftl
注意其中$變量,引用temlplate.xml中各控件的變量id酬姆,方便創(chuàng)建的文件名字已命名好嗜桌。

recipe.xml.ftl

<?xml version="1.0"?>
<#import "root://activities/common/kotlin_macros.ftl" as kt>
<recipe>
    <#include "../common/recipe_manifest.xml.ftl" />
    <@kt.addAllKotlinDependencies />

<#if generateLayout>
    <instantiate from="root/res/layout/activity_mvp.xml.ftl"
                 to="${escapeXmlAttribute(resOut)}/layout/${layoutName}.xml"/>
</#if>

<#if generateMVP>

    <instantiate from="root/src/app_package/IContract.java.ftl"
                   to="${escapeXmlAttribute(srcOut)}/${contractName}.java" />
    <open file="${escapeXmlAttribute(srcOut)}/${contractName}.java" />

     <instantiate from="root/src/app_package/Model.java.ftl"
                   to="${escapeXmlAttribute(srcOut)}/${modelName}.java" />
    <open file="${escapeXmlAttribute(srcOut)}/${modelName}.java" />

     <instantiate from="root/src/app_package/Presenter.java.ftl"
                   to="${escapeXmlAttribute(srcOut)}/${presenterName}.java" />
    <open file="${escapeXmlAttribute(srcOut)}/${presenterName}.java" />
    
</#if>


<#if generateKotlin>
  
    <instantiate from="root/src/app_package/MVPActivity.kt.ftl"
                   to="${escapeXmlAttribute(srcOut)}/${activityClass}.kt" />
    <open file="${escapeXmlAttribute(srcOut)}/${activityClass}.kt" />
<#else>
    <instantiate from="root/src/app_package/MVPActivity.java.ftl"
                   to="${escapeXmlAttribute(srcOut)}/${activityClass}.java" />
    <open file="${escapeXmlAttribute(srcOut)}/${activityClass}.java" />

</#if>

</recipe>

template.xml
想要讓id activityName統(tǒng)一命名Activity、Present辞色、Contract骨宠、Model、layout淫僻,需要通過suggest屬性統(tǒng)一引用它的id

template.xml

<?xml version="1.0"?>
<template
    format="5"
    revision="5"
    name="MVPActivity"
    minApi="9"
    minBuildApi="14"
    description="Creates a new empty activity">

    <category value="Activity" />
    <formfactor value="Mobile" />

    <parameter
        id="instantAppActivityHost"
        name="Instant App URL Host"
        type="string"
        suggest="${companyDomain}"
        default="instantapp.example.com"
        visibility="isInstantApp!false"
        help="The domain to use in the Instant App route for this activity"/>

    <parameter
        id="instantAppActivityRouteType"
        name="Instant App URL Route Type"
        type="enum"
        default="pathPattern"
        visibility="isInstantApp!false"
        help="The type of route to use in the Instant App route for this activity" >
        <option id="path">Path</option>
        <option id="pathPrefix">Path Prefix</option>
        <option id="pathPattern">Path Pattern</option>
    </parameter>

    <parameter
        id="instantAppActivityRoute"
        name="Instant App URL Route"
        type="string"
        default="/.*"
        visibility="isInstantApp!false"
        help="The route to use in the Instant App route for this activity"/>
<parameter
        id="activityName"
        name="MVP Name"
        type="string"
        constraints="nonempty"
        default="MVP"
        help="The name of the MVP class to create" />
    <parameter
        id="activityClass"
        name="MVPActivity Name"
        type="string"
        constraints="class|unique|nonempty"
        suggest="${activityName}Activity"
        default="MainActivity"
        help="The name of the activity class to create" />

    <parameter
        id="generateLayout"
        name="Generate Layout File"
        type="boolean"
        default="true"
        help="If true, a layout file will be generated" />

    <parameter
        id="layoutName"
        name="Layout Name"
        type="string"
        constraints="layout|unique|nonempty"
        suggest="${activityToLayout(activityName)}"
        default="activity_main"
        visibility="generateLayout"
        help="The name of the layout to create for the activity" />

    <parameter
        id="generateMVP"
        name="Generate MVP File"
        type="boolean"
        default="true"
        help="If true, a mvp file will be generated" />

        <parameter
        id="contractName"
        name="MVP Contract"
        type="string"
        suggest="${activityName}Contract"
        help="The name of the contract to create for the activity" />
        <parameter
        id="modelName"
        name="MVP Model"
        type="string"
        suggest="${activityName}Model"
        help="The name of the model to create for the activity" />
        <parameter
        id="presenterName"
        name="MVP Presenter"
        type="string"
        suggest="${activityName}Presenter"
        help="The name of the presenter to create for the activity" />

    <parameter
        id="isLauncher"
        name="Launcher Activity"
        type="boolean"
        default="false"
        help="If true, this activity will have a CATEGORY_LAUNCHER intent filter, making it visible in the launcher" />

    <parameter
        id="backwardsCompatibility"
        name="Backwards Compatibility (AppCompat)"
        type="boolean"
        default="true"
        help="If false, this activity base class will be Activity instead of AppCompatActivity" />
    
    <parameter
        id="packageName"
        name="Package name"
        type="string"
        constraints="package"
        default="com.mycompany.myapp" />

    <!-- 128x128 thumbnails relative to template.xml -->
    <thumbs>
        <!-- default thumbnail is required -->
        <thumb>template_blank_activity.png</thumb>
    </thumbs>

    <globals file="globals.xml.ftl" />
    <execute file="recipe.xml.ftl" />

</template>

2.4小結(jié)诱篷,集(tì)成(huàn)為自己項(xiàng)目MVP

以上自定義MVP模板已經(jīng)全部結(jié)束壶唤。最后需要把MVPActivity挪移到Android Studio的安裝目錄下 \plugins\android\lib\templates\activities(同Mac)雳灵,再重啟Android Studio,大功告成!

1.java.ftl模板中使用變量闸盔。
例如自動(dòng)生成的IContract.java文件中頂部含Header 信息悯辙,Present、Activity等信息(記得修改globals.xml.ftlauthor值迎吵;java import com.xx.等導(dǎo)包)躲撰。如圖

IContract.java

IContract.java.ftl

template.xml

globals.xml.ftl

2.內(nèi)聯(lián)的順序
內(nèi)聯(lián)的順序在代碼中是從上往下執(zhí)行的,因此要想生成文件后焦點(diǎn)窗口定位在新的Activity內(nèi)击费,則要把Activity的內(nèi)聯(lián)代碼放在最下面拢蛋,這樣所有文件生成完畢后才會(huì)優(yōu)先定位到Activity窗口
recipe.xml.ftl

PS:若編碼的時(shí)候出現(xiàn)語法錯(cuò)誤,那么在Android studio中點(diǎn)擊finish生成Activity的時(shí)候會(huì)直接報(bào)錯(cuò)蔫巩,查看點(diǎn)擊log可以看到詳細(xì)的報(bào)錯(cuò)位置谆棱,自己再進(jìn)行修改就可以了快压。

附上模板源碼:MVP模板下載地址

最后編輯于
?著作權(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)離奇詭異,居然都是意外死亡嗦锐,警方通過查閱死者的電腦和手機(jī)嫌松,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來意推,“玉大人豆瘫,你說我怎么就攤上這事【罩担” “怎么了外驱?”我有些...
    開封第一講書人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長腻窒。 經(jī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
  • 文/蒼蘭香墨 我猛地睜開眼结胀,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼两残!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起把跨,我...
    開封第一講書人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤人弓,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后着逐,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體崔赌,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有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
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至旬牲,卻和暖如春仿粹,著一層夾襖步出監(jiān)牢的瞬間搁吓,已是汗流浹背原茅。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留堕仔,地道東北人擂橘。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像摩骨,于是被迫代替她去往敵國和親通贞。 傳聞我的和親對(duì)象是個(gè)殘疾皇子朗若,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355