Android性能優(yōu)化:App啟動(dòng)優(yōu)化分析

應(yīng)用啟動(dòng)的時(shí)間作為應(yīng)用的門(mén)面,重要性可想而知躺酒。尤其在如今的快時(shí)代,一款秒開(kāi)的App比一款啟動(dòng)需要耗費(fèi)好幾秒的App更容易被用戶喜愛(ài)和長(zhǎng)期使用,整的不好還容易被用戶永久拉入黑名單轩勘。這時(shí)候,應(yīng)用的啟動(dòng)優(yōu)化就必不可少了怯邪。那么接下來(lái)就來(lái)了解下關(guān)于啟動(dòng)優(yōu)化的一些注意事項(xiàng)绊寻。

一、應(yīng)用啟動(dòng)類型

1.1.冷啟動(dòng)

冷啟動(dòng)是指應(yīng)用程序從零開(kāi)始悬秉,系統(tǒng)的進(jìn)程在此啟動(dòng)之前沒(méi)有創(chuàng)建應(yīng)用程序的進(jìn)程澄步,或者由于系統(tǒng)殺死了應(yīng)用后再啟動(dòng)。在冷啟動(dòng)開(kāi)始時(shí)和泌,系統(tǒng)有三個(gè)任務(wù)村缸。這些任務(wù)包括:

  • 加載并啟動(dòng)應(yīng)用程序。
  • 啟動(dòng)后立即顯示一個(gè)空白的啟動(dòng)窗口武氓。
  • 創(chuàng)建應(yīng)用程序app進(jìn)程梯皿。

一旦app進(jìn)程創(chuàng)建完成,系統(tǒng)就開(kāi)始下一階段:

  • 創(chuàng)建app對(duì)象县恕;
  • 啟動(dòng)主線程东羹。
  • 創(chuàng)建主Activity
  • 開(kāi)始對(duì)View進(jìn)行布局。

1.2.熱啟動(dòng)

熱啟動(dòng)不同于冷啟動(dòng)忠烛,熱啟動(dòng)在啟動(dòng)應(yīng)用時(shí)属提,系統(tǒng)中已經(jīng)有了該應(yīng)用的進(jìn)程,啟動(dòng)時(shí)也就少了創(chuàng)建進(jìn)程等一系列耗時(shí)的操作。

1.3.溫啟動(dòng)

溫啟動(dòng)的啟動(dòng)速度處于冷啟動(dòng)和熱啟動(dòng)之間冤议,溫啟動(dòng)會(huì)重新走Activity的onCreate生命周期斟薇。

二、應(yīng)用啟動(dòng)流程

優(yōu)化應(yīng)用的啟動(dòng)速度主要是在于冷啟動(dòng)時(shí)恕酸,應(yīng)用的啟動(dòng)耗時(shí)堪滨。冷啟動(dòng)時(shí)應(yīng)用會(huì)從零開(kāi)啟,這就需要先了解一下當(dāng)我們點(diǎn)擊Launcher上app圖標(biāo)后尸疆,進(jìn)程之間做了什么處理椿猎?

2.1.啟動(dòng)基本流程

img
  1. 點(diǎn)擊App圖標(biāo),Launcher進(jìn)程向SystemServer進(jìn)程發(fā)起startActivity請(qǐng)求寿弱;
  2. SystemServer進(jìn)程收到請(qǐng)求后犯眠,向Zygote進(jìn)程發(fā)送創(chuàng)建App進(jìn)程的請(qǐng)求;
  3. Zygote進(jìn)程fork出新的App進(jìn)程症革,App進(jìn)程就開(kāi)始向SystemServer進(jìn)程發(fā)出attachApplication請(qǐng)求筐咧,在此同時(shí),App進(jìn)程會(huì)執(zhí)行bindApplication噪矛,即創(chuàng)建Application量蕊,調(diào)用Application的onCreate;
  4. SystemServer在收到attachApplication請(qǐng)求后艇挨,再次向App進(jìn)程發(fā)送scheduleLauncherActivity請(qǐng)求残炮;
  5. App進(jìn)程收到請(qǐng)求后,通過(guò)handler向主線程發(fā)送LAUNCHE_ACTIVITY消息缩滨,主線程收到消息后通過(guò)反射機(jī)制創(chuàng)建目標(biāo)Activity势就,并回調(diào)Activity.OnCreate()等方法。到此脉漏,App才正式啟動(dòng)苞冯,開(kāi)始Activity的生命周期。

從應(yīng)用的啟動(dòng)流程可以發(fā)現(xiàn)侧巨,應(yīng)用的啟動(dòng)其實(shí)是App進(jìn)程與SystemServer進(jìn)程舅锄,Zygote進(jìn)程相互配合的過(guò)程。對(duì)于啟動(dòng)速度的優(yōu)化司忱,應(yīng)用層我們所要關(guān)注并且能夠干預(yù)的也就是Application和Activity的創(chuàng)建皇忿。

2.2.Application

App運(yùn)行時(shí),會(huì)首先自動(dòng)創(chuàng)建Application類并實(shí)例化 Application對(duì)象坦仍,且只有一個(gè)禁添。Application的創(chuàng)建時(shí)間比Activity要早,在上面應(yīng)用的啟動(dòng)流程中也提到桨踪,在啟動(dòng)App時(shí),會(huì)創(chuàng)建Application芹啥,那么就需要先去了解下它的生命周期锻离。

  • attachBaseContext():得到應(yīng)用上下文的Context铺峭,在應(yīng)用創(chuàng)建時(shí)會(huì)首先調(diào)用;
  • onCreate():同樣在應(yīng)用創(chuàng)建時(shí)調(diào)用汽纠,但比attachBaseContext()要晚卫键;
  • onTerminate():應(yīng)用結(jié)束時(shí)調(diào)用;
  • onConfigurationChange():系統(tǒng)配置發(fā)生變化時(shí)調(diào)用虱朵;
  • onLowMemory():系統(tǒng)低內(nèi)存時(shí)調(diào)用莉炉;
  • onTrimMemory():系統(tǒng)要求應(yīng)用釋放內(nèi)存時(shí)調(diào)用。

從Application的生命周期可以看到碴犬,應(yīng)用創(chuàng)建時(shí)會(huì)依次調(diào)用attachBaseContext()和onCreate()絮宁,這兩個(gè)生命周期包含在應(yīng)用的啟動(dòng)流程中,啟動(dòng)速度優(yōu)化可以以此為一個(gè)切入點(diǎn)服协。

2.3.Activity

從點(diǎn)擊圖標(biāo)到用戶看見(jiàn)前臺(tái)數(shù)據(jù)所經(jīng)歷的生命周期绍昂,也就是Activity的onCreate(),onResume()。眾所周知偿荷,Activity會(huì)在onCreate()中加載布局以及進(jìn)行數(shù)據(jù)的初始化窘游。既然包含在應(yīng)用的啟動(dòng)中,那么也可以作為一個(gè)切入點(diǎn)跳纳。

2.4.小結(jié)

從上面的啟動(dòng)流程到Application和Activity的介紹忍饰,應(yīng)用啟動(dòng)優(yōu)化的切入點(diǎn)也就如下圖所示:

流程.png

作為應(yīng)用層所能監(jiān)控并且能處理的,第一點(diǎn)是屬于Application的創(chuàng)建寺庄,第二點(diǎn)就是Activity的創(chuàng)建艾蓝。那么接下來(lái)就需要去監(jiān)測(cè)各個(gè)部分所耗費(fèi)的時(shí)間,再針對(duì)性的進(jìn)行優(yōu)化铣揉。

三饶深、啟動(dòng)耗時(shí)的監(jiān)測(cè)

3.1.logcat生成所有l(wèi)og

在連接上設(shè)備后可以在串口或者adb中利用命令打印出所有的log:

  1. 生成log文件:logcat > /data/xxx.txt
  2. 利用adb將文件pull出來(lái):adb pull /data/xxx.txt

執(zhí)行完上面兩條命令后,就會(huì)生成一個(gè)全log的txt文件逛拱,pull出文件后敌厘,可以在文件中查看所有的信息,包括啟動(dòng)發(fā)生的時(shí)間朽合,類名俱两,線程號(hào)等。

logcat生成的xxx.txt雖然包含了很詳細(xì)的信息曹步,但是還需要我們自己去計(jì)算各個(gè)生命周期間所耗費(fèi)的時(shí)間宪彩。

3.2.adb命令執(zhí)行

除了3.1提到的用logcat打印全log外,adb還有一條命令可以直接生成應(yīng)用啟動(dòng)的時(shí)間讲婚。<u>adb shell am start -W [packageName]/[AppstartActivity]</u>

執(zhí)行完后臺(tái)會(huì)生成ThisTime尿孔、TotalTimeWaitTime這三個(gè)時(shí)間,ThisTime代表一連串啟動(dòng) Activity 的最后一個(gè) Activity 的啟動(dòng)耗時(shí);TotalTime表示應(yīng)用的啟動(dòng)時(shí)間活合,包括創(chuàng)建進(jìn)程雏婶,Application初始化和Activity初始化到界面顯示,一般來(lái)說(shuō)與ThisTime一樣白指;WaitTime則表示AMS啟動(dòng)Activity的總耗時(shí)留晚,一般比TotalTime大。

對(duì)于監(jiān)測(cè)應(yīng)用的啟動(dòng)速度告嘲,我們只需要關(guān)注TotalTime這個(gè)值错维。

如上所述,利用adb命令得到啟動(dòng)時(shí)間橄唬,也只是一個(gè)階段的總時(shí)間赋焕,卻不能如3.1一樣監(jiān)測(cè)到每個(gè)生命周期所耗費(fèi)的時(shí)間,無(wú)法得到具體的耗時(shí)轧坎,無(wú)疑對(duì)啟動(dòng)速度針對(duì)性優(yōu)化沒(méi)有多大的幫助宏邮。

3.3.代碼打點(diǎn)

代碼打點(diǎn)是通過(guò)代碼編寫(xiě)一個(gè)工具類,通過(guò)代碼的形式獲取每個(gè)方法的執(zhí)行的時(shí)間缸血,這個(gè)方法與3.1所達(dá)到的目的是一致的蜜氨,都能得到每個(gè)周期具體的耗時(shí)。唯一不同的是3.1的方式需要不斷敲擊命令捎泻,再在文件中去查找有效信息飒炎,無(wú)疑是耗費(fèi)人力的,而通過(guò)代碼打點(diǎn)的方式可以實(shí)時(shí)監(jiān)測(cè)每個(gè)方法的耗時(shí)笆豁,也可以生成信息上傳到服務(wù)器郎汪。

下面是一個(gè)基本的代碼打點(diǎn)的案例:

public class TimeMonitorManager {
    private static final String TAG = "TimeMonitorManager";

    private HashMap<String, Long> mTimeTagMap = new HashMap<>();
    private long mStartTime = 0;
    private static volatile TimeMonitorManager mMonitorManager;
    
    private TimeMonitorManager() {

    }

    public static TimeMonitorManager getInstance() {
        if (mMonitorManager == null) {
            synchronized (TimeMonitorManager.class) {
                if (mMonitorManager == null) {
                    mMonitorManager = new TimeMonitorManager();
                }
            }
        }
        return mMonitorManager;
    }

    /**
     * 開(kāi)始監(jiān)聽(tīng).
     */
    public void startMonitor() {
        if (mTimeTagMap.size() > 0) {
            mTimeTagMap.clear();
        }

        mStartTime = System.currentTimeMillis();

    }


    /**
     * 結(jié)束監(jiān)聽(tīng).
     * @param tag 所要打印的tag.
     */
    public void endMonitor(String tag) {
        if (mTimeTagMap.get(tag) != null) {
            mTimeTagMap.remove(tag);
        }

        long time = System.currentTimeMillis() - mStartTime;
        mTimeTagMap.put(tag, time);
        showData();
    }

    private void showData() {
        if (mTimeTagMap.size() <= 0) {
            return;
        }

        for (String tag: mTimeTagMap.keySet()
             ) {
            long time = mTimeTagMap.get(tag);
            Log.d(TAG, tag + ": " + time);
        }
    }

}

在需要打點(diǎn)開(kāi)始的地方調(diào)用startMonitor(),在結(jié)束的地方調(diào)用endMonitor(String tag),例如Activity在加載布局,也就是setContentView(R.layout.activity_main)時(shí)是耗時(shí)的,根據(jù)打點(diǎn)規(guī)則,在setContentView(R.layout.activity_main);前后調(diào)用TimeMonitorManager的方法,以達(dá)到監(jiān)測(cè)setContentView所耗費(fèi)的時(shí)間.如下:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        TimeMonitorManager.getInstance().startMonitor();
        setContentView(R.layout.activity_main);
        TimeMonitorManager.getInstance().endMonitor(TAG + " onCreate setContentView");
    }

運(yùn)行后Logcat中打印的效果如下:

TimeMonitorManager: MainActivity onCreate setContentView: 60

可以發(fā)現(xiàn),Activity在setContentView()時(shí)所耗費(fèi)的時(shí)間大約為60ms.

利用TimeMonitorManager打點(diǎn)的好處在于可以清楚的監(jiān)測(cè)到每一處的耗時(shí),更加精準(zhǔn);

從第二節(jié)應(yīng)用啟動(dòng)流程就了解到,應(yīng)用啟動(dòng)耗時(shí)能夠監(jiān)測(cè)的切入點(diǎn)為Application的創(chuàng)建和Activity的創(chuàng)建闯狱,我們就可以通過(guò)代碼打點(diǎn)的方式在以下這些地方進(jìn)行打點(diǎn):

  • Application的onCreate()
  • Activity的onCreate()煞赢,onStart(),onResume()
  • 初始化對(duì)象的方法,注冊(cè)等方法
  • 一些耗時(shí)的操作

四哄孤、優(yōu)化方向

從上面三節(jié)可以了解到照筑,影響應(yīng)用啟動(dòng)時(shí)間的要素一般可分為Application里一些數(shù)據(jù)的準(zhǔn)備,Activity的布局以及在初始化的耗時(shí)操作瘦陈。下面也將從這幾個(gè)方面分別描述下優(yōu)化策略凝危。

4.1.布局優(yōu)化

4.1.1.按需選擇布局方式

我們都知道onCreate()里的setContentView()是用來(lái)加載布局,應(yīng)用啟動(dòng)時(shí)會(huì)去解析xml中的結(jié)構(gòu)晨逝,當(dāng)一個(gè)xml里結(jié)構(gòu)嵌套過(guò)多蛾默,系統(tǒng)需要去解析的時(shí)間就大大增加了。

當(dāng)布局比較復(fù)雜捉貌,可以使用ConstraintLayout布局支鸡,ConstraintLayout是Android Studio 2.2新增的一個(gè)功能冬念,它的一大特點(diǎn)就是為了解決布局嵌套。具體使用方法可參考:

https://blog.csdn.net/sinyu890807/article/details/53122387

另外牧挣,當(dāng)版本較低且布局復(fù)雜刘急,RelativeLayout布局優(yōu)化的效果是要優(yōu)于LinearLayout。但是當(dāng)布局簡(jiǎn)單時(shí)浸踩,LinearLayout卻優(yōu)于RelativeLayout,所以大家可依照具體情況進(jìn)行選擇统求。

4.1.2.< include >检碗、< merge >

< include >與< merge >是布局優(yōu)化的兩個(gè)利器。< include >標(biāo)簽是可以允許在一個(gè)布局當(dāng)中引入另外一個(gè)布局码邻,當(dāng)多個(gè)布局中有用到相同的部分折剃,就可以采用< include >標(biāo)簽將相同的部分提取出來(lái),利用< include >將公告部分替代像屋。

而< merge >標(biāo)簽的作用是作為< include >標(biāo)簽的一種輔助擴(kuò)展來(lái)使用的怕犁,它的主要作用是為了防止在引用布局文件時(shí)產(chǎn)生多余的布局嵌套。

4.1.3.ViewStub

ViewStub是一個(gè)比較輕量級(jí)的控件己莺,沒(méi)有大小奏甫,不需要繪制,同時(shí)也不參與布局凌受,所以消耗的資源是非常小的阵子。ViewStub的使用就在于當(dāng)我們存在時(shí)而需要顯示時(shí)而不顯示的view的時(shí)候,就可以使用它胜蛉。例如我們進(jìn)行網(wǎng)絡(luò)請(qǐng)求時(shí)的loading bar挠进,請(qǐng)求時(shí),會(huì)顯示誊册,當(dāng)請(qǐng)求結(jié)束领突,loading bar就會(huì)消失,這個(gè)時(shí)候就可以使用ViewStub案怯,減少資源的消耗的同時(shí)也減少了布局解析的時(shí)間君旦。

另外,針對(duì)布局的優(yōu)化殴泰,AS提供了Profile和Hierarchy View兩個(gè)工具分別檢查View的繪制和分析布局于宙。

具體使用可參考

https://blog.csdn.net/guolin_blog/article/details/43376527

4.2.邏輯加載優(yōu)化

邏輯耗時(shí)一般分為Application中和Activity中的邏輯加載。在Application或者Activity中進(jìn)行初始化的時(shí)候悍汛,有些的邏輯初始化是必要的捞魁,而有些初始化非必要,可以適當(dāng)?shù)难訒r(shí)去加載离咐。例如在最近的項(xiàng)目中谱俭,應(yīng)用啟動(dòng)時(shí)需要提前去連接服務(wù)并且去注冊(cè)回調(diào)接口奉件,為了提前連接上服務(wù),將連接的操作就放置在了Application里進(jìn)行初始化昆著。這就是屬于必要的邏輯操作县貌。對(duì)于不同優(yōu)先級(jí)的邏輯,我們可以大致分為以下幾點(diǎn):

4.2.1.異步加載(必要且耗時(shí))

有些邏輯處理的優(yōu)先級(jí)比較高凑懂,并且初始化耗時(shí)煤痕,可以采用異步加載的方式,利用RxJava接谨,HandlerThread摆碉,IntentService等在后臺(tái)進(jìn)行加載,這樣就不會(huì)阻塞主線程脓豪,UI展現(xiàn)到用戶眼前的時(shí)間也會(huì)縮短巷帝。

4.2.2.延時(shí)加載(非必要且耗時(shí))

當(dāng)邏輯操作的優(yōu)先級(jí)不是很高時(shí),可以采取延時(shí)加載的方式扫夜,也就是應(yīng)用啟動(dòng)過(guò)程中暫時(shí)不去初始化這些邏輯楞泼,將之前在Application或者Activity onCreate()中的操作移除,在主線程空閑的時(shí)候再進(jìn)行加載操作笤闯。

另外堕阔,MessageQueue內(nèi)部有一個(gè)接口IdleHandler,可以很好的處理延時(shí)問(wèn)題望侈。IdleHandler在looper里面的message都處理完了的時(shí)候就會(huì)回調(diào)這個(gè)接口印蔬,返回false,就會(huì)移除它脱衙,返回true就會(huì)在下次message處理完了的時(shí)候繼續(xù)回調(diào)侥猬。

舉個(gè)例子,一般情況下捐韩,應(yīng)用啟動(dòng)時(shí)會(huì)去繪制布局退唠,會(huì)去調(diào)用measure, layout, draw等方法,在執(zhí)行這些操作后荤胁,用戶才會(huì)去看見(jiàn)UI瞧预,而之前優(yōu)先級(jí)不高的初始化,就可以延時(shí)在這些操作后加載仅政,那么主要的問(wèn)題就是我們?nèi)绾稳ヅ袛鄊easure, layout, draw等操作已經(jīng)完成了垢油?延時(shí)加載的時(shí)機(jī)在哪?IdleHandler就幫我們解決了這個(gè)問(wèn)題圆丹,上面也都知道IdleHandler是在隊(duì)列為空的時(shí)候會(huì)去回調(diào)它滩愁,measure, layout, draw都可以作為一個(gè)個(gè)message,IdleHandler就會(huì)在他們執(zhí)行完成后響應(yīng)辫封。這個(gè)時(shí)候就可以進(jìn)行之前需要延時(shí)的初始化操作硝枉。

另外廉丽,當(dāng)代碼中同時(shí)有UI繪制和邏輯加載,可以在IdleHandler回調(diào)中再去處理邏輯加載妻味,UI繪制與邏輯分開(kāi)操作正压,可以減少數(shù)據(jù)空白時(shí)間長(zhǎng)的問(wèn)題。

4.2.3.分步加載

當(dāng)初始化對(duì)象有很多時(shí)责球,且必要焦履,可以采取分步加載的方式,將邏輯的優(yōu)先級(jí)區(qū)分開(kāi)來(lái)雏逾,優(yōu)先級(jí)高的先加載裁良。

五、總結(jié)

啟動(dòng)優(yōu)化需要針對(duì)不同的業(yè)務(wù)做出不同的優(yōu)化方式校套,例如可以采用Multidex預(yù)加載優(yōu)化,但是虛擬機(jī)在5.0以上默認(rèn)就使用ART牧抵,對(duì)于項(xiàng)目是5.0以上版本就不需要去優(yōu)化此方面笛匙。

總的來(lái)說(shuō),優(yōu)化方向可以分為布局優(yōu)化犀变,減少解析xml和繪制的時(shí)間妹孙;邏輯優(yōu)化,將必要且耗時(shí)的操作異步加載获枝,將非必要的采用延時(shí)加載蠢正,另外,將操作優(yōu)先級(jí)高的可以優(yōu)先加載省店。

最后嚣崭,啟動(dòng)速度優(yōu)化是一個(gè)大工程,后續(xù)還需要針對(duì)具體場(chǎng)景繼續(xù)深度挖掘懦傍。

參考:《Android應(yīng)用性能優(yōu)化最佳實(shí)踐》

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末雹舀,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子粗俱,更是在濱河造成了極大的恐慌说榆,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,997評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件寸认,死亡現(xiàn)場(chǎng)離奇詭異签财,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)偏塞,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,603評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)唱蒸,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人烛愧,你說(shuō)我怎么就攤上這事油宜〉嗉睿” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,359評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵慎冤,是天一觀的道長(zhǎng)疼燥。 經(jīng)常有香客問(wèn)我,道長(zhǎng)蚁堤,這世上最難降的妖魔是什么醉者? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,309評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮披诗,結(jié)果婚禮上撬即,老公的妹妹穿的比我還像新娘。我一直安慰自己呈队,他們只是感情好剥槐,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,346評(píng)論 6 390
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著宪摧,像睡著了一般粒竖。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上几于,一...
    開(kāi)封第一講書(shū)人閱讀 51,258評(píng)論 1 300
  • 那天蕊苗,我揣著相機(jī)與錄音,去河邊找鬼沿彭。 笑死朽砰,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的喉刘。 我是一名探鬼主播瞧柔,決...
    沈念sama閱讀 40,122評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼睦裳!你這毒婦竟也來(lái)了非剃?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,970評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤推沸,失蹤者是張志新(化名)和其女友劉穎备绽,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體鬓催,經(jīng)...
    沈念sama閱讀 45,403評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡肺素,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,596評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了宇驾。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片倍靡。...
    茶點(diǎn)故事閱讀 39,769評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖课舍,靈堂內(nèi)的尸體忽然破棺而出塌西,到底是詐尸還是另有隱情他挎,我是刑警寧澤,帶...
    沈念sama閱讀 35,464評(píng)論 5 344
  • 正文 年R本政府宣布捡需,位于F島的核電站办桨,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏站辉。R本人自食惡果不足惜呢撞,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,075評(píng)論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望饰剥。 院中可真熱鬧殊霞,春花似錦、人聲如沸汰蓉。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,705評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)顾孽。三九已至瘸右,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間岩齿,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,848評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工苞俘, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留盹沈,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,831評(píng)論 2 370
  • 正文 我出身青樓吃谣,卻偏偏與公主長(zhǎng)得像乞封,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子岗憋,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,678評(píng)論 2 354

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