Android基礎(chǔ)之Context

Android基礎(chǔ)之Context

Context

對于Android開發(fā)者來說Context應(yīng)該是非常熟悉的旁振。我們在使用Toast褐捻,啟動Activity惭嚣,啟動Service勘究,加載資源埋同,操作數(shù)據(jù)庫持隧,獲取App相關(guān)的文件路徑,創(chuàng)建View等操作時(shí),都會涉及到一個(gè)Context引用肛度。那么Context到底是什么,Activity和Application作為Context到底有什么區(qū)別投慈,哪個(gè)更好呢承耿?以及我們在項(xiàng)目建立最初自定義的Application提供全局Context該怎么實(shí)現(xiàn)呢?

什么是Context

寫過一個(gè)小Android demo的應(yīng)該會有一個(gè)疑問為什么一個(gè)Android應(yīng)用不需要一個(gè)main()方法來啟動整個(gè)程序伪煤,如果是通過一個(gè)main()方法來啟動程序加袋,那么我們就可以在里面執(zhí)行例如new一個(gè)Activity等操作。Android的應(yīng)用模型是基于組件的應(yīng)用設(shè)計(jì)模式抱既,組件能夠運(yùn)行需要一個(gè)完整的工程環(huán)境职烧。同時(shí),各個(gè)組件擁有自己獨(dú)立的場景(Context)防泵,并不能采用new的方式創(chuàng)建一個(gè)組件對象蚀之。Context是維持Android程序中各組件能夠正常工作的一個(gè)核心功能類。

總結(jié):一個(gè)應(yīng)用是一個(gè)完整的工程環(huán)境捷泞,在這個(gè)應(yīng)用中我們有許多功能足删,例如打電話,發(fā)短信锁右,發(fā)郵件失受。這些功能都算是這個(gè)環(huán)境中的一個(gè)場景讶泰。比如發(fā)短信場景包含界面的顯示以及數(shù)據(jù)的傳遞等等。所以我們可以把場景(Context)理解為用戶與操作系統(tǒng)交互的一個(gè)過程拂到。

Context類

首先來看Context類的介紹

/**
 * Interface to global information about an application environment.  This is
 * an abstract class whose implementation is provided by
 * the Android system.  It
 * allows access to application-specific resources and classes, as well as
 * up-calls for application-level operations such as launching activities,
 * broadcasting and receiving intents, etc.
 */
public abstract class Context {
    ......
}

他的注釋:Context提供了關(guān)于應(yīng)用環(huán)境全局信息的接口峻厚。它是一個(gè)抽象類,它的執(zhí)行被Android系統(tǒng)所提供谆焊。它允許獲取以應(yīng)用為特征的資源和類型惠桃,是一個(gè)統(tǒng)領(lǐng)一些資源(應(yīng)用程序環(huán)境變量等)的上下文。也就是說Context描述一個(gè)應(yīng)用程序環(huán)境的信息(即上下文)辖试;是一個(gè)抽象類辜王,Android提供了該抽象類的具體實(shí)現(xiàn)類;通過它我們可以獲取應(yīng)用程序的資源和類(包括應(yīng)用級別操作罐孝,如啟動Activity呐馆,發(fā)廣播,接受Intent等)莲兢。

引用自博客Android應(yīng)用Context詳解及源碼解析

那么在平常開發(fā)中我們用到哪些這個(gè)Context抽象類的實(shí)現(xiàn)呢汹来?

盜用大牛郭霖的圖片.png

可以發(fā)現(xiàn)Application,Service改艇,Activity都是者間接繼承自Context收班。在上面的繼承關(guān)系中我們看到ContextImpl和ContextWrapper是直接繼承自Context。ContextWrapper是Context類的一個(gè)封裝類谒兄,而ContextImpl是Context抽象類的實(shí)現(xiàn)類摔桦。ContextWrapper的構(gòu)造函數(shù)中有一個(gè)真正的Context的引用(ContextImpl對象,mBase)承疲。ContextWrapper的子類有一個(gè)ContextThemeWrapper邻耕,是帶主題封裝的類,即通過android:theme屬性指定的(例如Activity帶UI顯示)燕鸽。

那么我們一個(gè)應(yīng)用中有多少個(gè)Context呢兄世?

Android應(yīng)用程序只有四大組件,而其中兩大組件都繼承自
Context啊研,另外每個(gè)應(yīng)用程序還有一個(gè)全局的Application對象御滩。所以在我們了解了上面繼承關(guān)系之后我們就可以計(jì)算出來Context總數(shù),如下:

appContextCount = Application + ActivityCount + ServiceCount;

Context的實(shí)例化

Activity,Application,Service實(shí)例都是在ActivityThread中創(chuàng)建的悲伶。我參考了博客Android應(yīng)用Context詳解及源碼解析(因?yàn)樽约哼€沒有深入了解到App的啟動艾恼,只是想了解Context基礎(chǔ)知識)

Activity中ContextImpl實(shí)例化源碼分析

通過startActivity啟動一個(gè)新的Activity時(shí)系統(tǒng)會回調(diào)ActivityThread的handleLaunchActivity()方法,該方法內(nèi)部會調(diào)用performLaunchActivity()方法去創(chuàng)建一個(gè)Activity實(shí)例麸锉,然后回調(diào)Activity的onCreate()等方法钠绍。所以Activity的ContextImpl實(shí)例化是在ActivityThread類的performLaunchActivity方法中,如下:

    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        ......
            //已經(jīng)創(chuàng)建好新的activity實(shí)例
            if (activity != null) {
                //創(chuàng)建一個(gè)Context對象
                Context appContext = createBaseContextForActivity(r, activity);
                ......
                //將上面創(chuàng)建的appContext傳入到activity的attach方法
                activity.attach(appContext, this, getInstrumentation(), r.token,
                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstances, config,
                        r.referrer, r.voiceInteractor);
                ......
            }
        ......
        return activity;
    }
    

通過createBaseContextForActivity(r, activity);創(chuàng)建appContext花沉,然后通過activity.attach設(shè)置值柳爽。

createBaseContextForActivity(r, activity)部分源代碼:

    private Context createBaseContextForActivity(ActivityClientRecord r,
            final Activity activity) {
        //實(shí)質(zhì)就是new一個(gè)ContextImpl對象媳握,調(diào)運(yùn)ContextImpl的有參構(gòu)造初始化一些參數(shù)    
        ContextImpl appContext = ContextImpl.createActivityContext(this, r.packageInfo, r.token);
        //特別特別留意這里!A赘蛾找!
        //ContextImpl中有一個(gè)Context的成員叫mOuterContext,通過這條語句就可將當(dāng)前新Activity對象賦值到創(chuàng)建的ContextImpl的成員mOuterContext(也就是讓ContextImpl內(nèi)部持有Activity)赵誓。
        appContext.setOuterContext(activity);
        //創(chuàng)建返回值并且賦值
        Context baseContext = appContext;
        ......
        //返回ContextImpl對象
        return baseContext;
    }

Activity.attach()部分源代碼:

    final void attach(Context context, ActivityThread aThread,
            Instrumentation instr, IBinder token, int ident,
            Application application, Intent intent, ActivityInfo info,
            CharSequence title, Activity parent, String id,
            NonConfigurationInstances lastNonConfigurationInstances,
            Configuration config, String referrer, IVoiceInteractor voiceInteractor) {
        //特別特別留意這里4蛎!俩功!
        //與上面createBaseContextForActivity方法中setOuterContext語句類似幻枉,不同的在于:
        //通過ContextThemeWrapper類的attachBaseContext方法,將createBaseContextForActivity中實(shí)例化的ContextImpl對象傳入到ContextWrapper類的mBase變量诡蜓,這樣ContextWrapper(Context子類)類的成員mBase就被實(shí)例化為Context的實(shí)現(xiàn)類ContextImpl
        attachBaseContext(context);
        ......
    }

總結(jié):Activity通過ContextWrapper的成員mBase來引用了一個(gè)ContextImpl對象熬甫,這樣,Activity組件以后就可以調(diào)用這個(gè)ContextImpl對象的一系列方法(啟動Service等)蔓罚;同時(shí)ContextImpl類又通過自己的成員mOuterContext引用了與它關(guān)聯(lián)的Activity椿肩,這樣ContextImpl類也可以操作Activity。

由此說明一個(gè)Activity就有一個(gè)Context豺谈,而且生命周期和Activity類相同郑象。在使用Activity作為Context引用時(shí)要考慮到內(nèi)存泄漏。

Service中ContextImpl實(shí)例化源碼分析

通過startService或者bindService方法創(chuàng)建一個(gè)新Service時(shí)就會回調(diào)ActivityThread類的handleCreateService()方法完成相關(guān)數(shù)據(jù)操作核无。具體handleCreateService方法代碼如下:

    private void handleCreateService(CreateServiceData data) {
        ......
        //類似上面Activity的創(chuàng)建扣唱,這里創(chuàng)建service對象實(shí)例
        Service service = null;
        try {
            java.lang.ClassLoader cl = packageInfo.getClassLoader();
            service = (Service) cl.loadClass(data.info.name).newInstance();
        } catch (Exception e) {
            ......
        }

        try {
            ......
            //不做過多解釋,創(chuàng)建一個(gè)Context對象
            ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
            //特別特別留意這里M拍稀!炼彪!
            //ContextImpl中有一個(gè)Context的成員叫mOuterContext吐根,通過這條語句就可將當(dāng)前新Service對象賦值到創(chuàng)建的ContextImpl的成員mOuterContext(也就是讓ContextImpl內(nèi)部持有Service)。
            context.setOuterContext(service);

            Application app = packageInfo.makeApplication(false, mInstrumentation);
            //將上面創(chuàng)建的context傳入到service的attach方法
            service.attach(context, this, data.info.name, data.token, app,
                    ActivityManagerNative.getDefault());
            service.onCreate();
            ......
        } catch (Exception e) {
            ......
        }
    }

Service中的attach方法:

    public final void attach(
            Context context,
            ActivityThread thread, String className, IBinder token,
            Application application, Object activityManager) {
            //特別特別留意這里7怼?介佟!
            //與上面handleCreateService方法中setOuterContext語句類似喜爷,不同的在于:
            //通過ContextWrapper類的attachBaseContext方法冗疮,將handleCreateService中實(shí)例化的ContextImpl對象傳入到ContextWrapper類的mBase變量,這樣ContextWrapper(Context子類)類的成員mBase就被實(shí)例化為Context的實(shí)現(xiàn)類ContextImpl
        attachBaseContext(context);
        ......
    }

說明一個(gè)Service就有一個(gè)Context檩帐,而且生命周期和Service類相同术幔,在使用Service作為Context引用時(shí)要考慮到內(nèi)存泄漏

Application中ContextImpl實(shí)例化源碼分析

一個(gè)APP以后每次重新啟動時(shí)都會首先創(chuàng)建Application對象(每個(gè)APP都有一個(gè)唯一的全局Application對象,與整個(gè)APP的生命周期相同)湃密。創(chuàng)建Application的過程也在ActivityThread類的handleBindApplication()方法完成相關(guān)數(shù)據(jù)操作诅挑。而ContextImpl的創(chuàng)建是在該方法中調(diào)運(yùn)LoadedApk類的makeApplication方法中實(shí)現(xiàn)四敞,LoadedApk類的makeApplication()方法中源代碼如下:

    public Application makeApplication(boolean forceDefaultAppClass,
            Instrumentation instrumentation) {
        //只有新創(chuàng)建的APP才會走if代碼塊之后的剩余邏輯
        if (mApplication != null) {
            return mApplication;
        }
        //即將創(chuàng)建的Application對象
        Application app = null;

        String appClass = mApplicationInfo.className;
        if (forceDefaultAppClass || (appClass == null)) {
            appClass = "android.app.Application";
        }

        try {
            java.lang.ClassLoader cl = getClassLoader();
            if (!mPackageName.equals("android")) {
                initializeJavaContextClassLoader();
            }
            //不做過多解釋,創(chuàng)建一個(gè)Context對象
            ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
            //將Context傳入Instrumentation類的newApplication方法
            app = mActivityThread.mInstrumentation.newApplication(
                    cl, appClass, appContext);
            //特別特別留意這里0瓮住7尬!!
            //ContextImpl中有一個(gè)Context的成員叫mOuterContext没龙,通過這條語句就可將當(dāng)前新Application對象賦值到創(chuàng)建的ContextImpl的成員mOuterContext(也就是讓ContextImpl內(nèi)部持有Application)铺厨。
            appContext.setOuterContext(app);
        } catch (Exception e) {
            ......
        }
        ......
        return app;
    }

Instrumentation.newApplication方法部分源碼:

    public Application newApplication(ClassLoader cl, String className, Context context)
            throws InstantiationException, IllegalAccessException, 
            ClassNotFoundException {
        return newApplication(cl.loadClass(className), context);
    }

newApplication方法部分源碼:

    static public Application newApplication(Class<?> clazz, Context context)
            throws InstantiationException, IllegalAccessException, 
            ClassNotFoundException {
        ......
        //繼續(xù)傳遞context
        app.attach(context);
        return app;
    }

Application類的attach方法部分源碼:

final void attach(Context context) {
        //特別特別留意這里!S蚕恕努释!
        //與上面makeApplication方法中setOuterContext語句類似,不同的在于:
        //通過ContextWrapper類的attachBaseContext方法咬摇,將makeApplication中實(shí)例化的ContextImpl對象傳入到ContextWrapper類的mBase變量伐蒂,這樣ContextWrapper(Context子類)類的成員mBase就被實(shí)例化為Application的實(shí)現(xiàn)類ContextImpl
        attachBaseContext(context);
        ......
    }

說明一個(gè)Application就有一個(gè)Context,而且生命周期和Application類相同(然而一個(gè)App只有一個(gè)Application肛鹏,而且與應(yīng)用生命周期相同)逸邦。

通過Context引用獲取資源

看到這里我有個(gè)疑問不同的Context引用,獲取到的資源是同一份嗎在扰?

class ContextImpl extends Context {
    ......
    private final ResourcesManager mResourcesManager;
    private final Resources mResources;
    ......
    @Override
    public Resources getResources() {
        return mResources;
    }
    ......
}

有了上面分析我們可以很確定平時(shí)寫的App中context.getResources方法獲得的Resources對象就是上面ContextImpl的成員變量mResources缕减。那我們追蹤可以發(fā)現(xiàn)mResources的賦值操作如下:

    private ContextImpl(ContextImpl container, ActivityThread mainThread,
            LoadedApk packageInfo, IBinder activityToken, UserHandle user, boolean restricted,
            Display display, Configuration overrideConfiguration) {
        ......
        //單例模式獲取ResourcesManager對象
        mResourcesManager = ResourcesManager.getInstance();
        ......
        //packageInfo對于一個(gè)APP來說只有一個(gè),所以resources 是同一份
        Resources resources = packageInfo.getResources(mainThread);
        if (resources != null) {
            if (activityToken != null
                    || displayId != Display.DEFAULT_DISPLAY
                    || overrideConfiguration != null
                    || (compatInfo != null && compatInfo.applicationScale
                            != resources.getCompatibilityInfo().applicationScale)) {
                //mResourcesManager是單例芒珠,所以resources是同一份
                resources = mResourcesManager.getTopLevelResources(packageInfo.getResDir(),
                        packageInfo.getSplitResDirs(), packageInfo.getOverlayDirs(),
                        packageInfo.getApplicationInfo().sharedLibraryFiles, displayId,
                        overrideConfiguration, compatInfo, activityToken);
            }
        }
        //把resources賦值給mResources
        mResources = resources;
        ......
    }

由此可以看出在設(shè)備其他因素不變的情況下我們通過不同的Context實(shí)例得到的Resources是同一套資源桥狡。

以上源碼分析完全是引用自別人的博客,自己對上面的分析也只是停留在一個(gè)字面意思上皱卓,只是通過上面的分析理解了不同Context的實(shí)例相對于整個(gè)App的生命周期裹芝,可以在實(shí)際開發(fā)中作為判斷到底使用哪個(gè)Context引用的依據(jù)。以及解決了心中對于不同Context引用獲取資源的疑問

getApplication和getApplicationContext的區(qū)別

getApplication()方法

Activity和Service提供了getApplication娜汁,而且返回類型都是Application嫂易。

public final Application getApplication() {
        return mApplication;
    }

這個(gè)mApplication都是在各自類的attach方法參數(shù)出入的,也就是說這個(gè)mApplication都是在ActivityThread中各自實(shí)例化時(shí)獲取的makeApplication方法返回值掐禁。而且不同的Activity和Service返回的Application均為同一個(gè)全局對象怜械。

getApplicationContext()方法

通過ContextImpl對象調(diào)用getApplicationContext()方法

class ContextImpl extends Context {
    ......
    @Override
    public Context getApplicationContext() {
        return (mPackageInfo != null) ?
                mPackageInfo.getApplication() : mMainThread.getApplication();
    }
    ......
}

可以看到getApplicationContext方法是Context的方法,而且返回值是Context類型傅事,返回對象和上面通過Service或者Activity的getApplication返回的是一個(gè)對象缕允。

區(qū)別

雖然這兩個(gè)方法最終的得到的值都是同一個(gè)對象的引用,但是它們的類型不同(一個(gè)是Application蹭越,一個(gè)是Context)且作用域有很大的區(qū)別障本。getApplication()方法的語義性非常強(qiáng),一看就知道是用來獲取Application實(shí)例的般又,但是這個(gè)方法只有在Activity和Service中才能調(diào)用的到彼绷。那么也許在絕大多數(shù)情況下我們都是在Activity或者Service中使用Application的巍佑,但是如果在一些其它的場景,比如BroadcastReceiver中也想獲得Application的實(shí)例寄悯,這時(shí)就可以借助getApplicationContext()方法萤衰。

還有一個(gè)得到Context的方法,getBaseContext()猜旬。getBaseContext()方法得到的是一個(gè)ContextImpl對象脆栋。也就是調(diào)用ContextWrapper的getBaseContext()方法返回存儲ContextImpl對象的mBase。

Activity和Application作為Context引用

Context引起的內(nèi)存泄漏

在實(shí)際開發(fā)中我們需要用到工具類洒擦,一般都會采用單例模式:

public class Singleton {
    private static Singleton instance;
    private Context mContext;
    private Singleton(Context context) {
        this.mContext = context;
    }
    public static synchronized Singleton getInstance(Context context) {
        if (instance == null) {
            instance = new Singleton(context);
        }
        return instance;
    }
   
}

你在某個(gè)Activity調(diào)用了getInstance()方法椿争,直接傳了個(gè)this;這樣問題就來了,我們的這個(gè)類中的sInstance是一個(gè)static且強(qiáng)引用的熟嫩,在其內(nèi)部引用了一個(gè)Activity作為Context秦踪,也就是說,我們的這個(gè)Activity只要我們的項(xiàng)目活著掸茅,就沒有辦法進(jìn)行內(nèi)存回收椅邓。而我們的Activity的生命周期肯定沒這么長,所以造成了內(nèi)存泄漏昧狮。

Java強(qiáng)引用會導(dǎo)致GC內(nèi)存無法回收

解決辦法:

public class Singleton {
    private static Singleton instance;
    private Context mContext;
    private Singleton(Context context) {
        this.mContext = context;
    }
    public static synchronized Singleton getInstance(Context context) {
        if (instance == null) {
            instance = new Singleton(context.getApplicationContext());
        }
        return instance;
    }
   
}

由于Application對象的生命周期如上面分析的那樣景馁,和整個(gè)項(xiàng)目一樣長。也就是它的生命周期和我們的單例對象一致逗鸣。

不同的Context適用場景

正如上面所說的Context引用不當(dāng)會造成內(nèi)存泄漏合住,那么我們是否可以都引用Application作為Context引用呢?答案是否定的撒璧,不同Context(指的是Activity透葛,Application,Service)的應(yīng)用場景是不同的沪悲,并非所有Activity為Context的場景获洲,Application Context都能搞定。

Application Activity Service
show dialog N Y N
start Activity N Y N
Layout Inflation N Y N
start service Y Y Y
send a BroadCast Y Y Y
register a BroadCast Receiver Y Y Y
load Resource Y Y Y

上述表格中可以看到殿如,在啟動一個(gè)Activity和Dialog時(shí),不推薦使用Application和Service最爬。Android系統(tǒng)出于安全原因的考慮涉馁,是不允許Activity或Dialog憑空出現(xiàn)的,一個(gè)Activity的啟動必須要建立在另一個(gè)Activity的基礎(chǔ)之上爱致,也就是以此形成的返回棧烤送。而Dialog則必須在一個(gè)Activity上面彈出(除非是System Alert類型的Dialog),因此在這種場景下糠悯,我們只能使用Activity類型的Context帮坚,否則將會出錯(cuò)妻往。調(diào)用除了Activity的,其他Context實(shí)例的LayoutInflation试和,會使用系統(tǒng)默認(rèn)的主題樣式讯泣,如果你自定義了某些樣式可能不會被使用。

總結(jié):和UI相關(guān)的方法基本都不建議或者不可使用Application阅悍,并且好渠,前三個(gè)操作基本不可能在Application中出現(xiàn)。實(shí)際上节视,只要把握住一點(diǎn)拳锚,凡是跟UI相關(guān)的,都應(yīng)該使用Activity做為Context來處理寻行;其他的一些操作霍掺,Service,Activity,Application等實(shí)例都可以,當(dāng)然了拌蜘,注意Context引用的持有杆烁,防止內(nèi)存泄漏。

參考

Context都沒弄明白拦坠,還怎么做Android開發(fā)连躏?

Android應(yīng)用Context詳解及源碼解析

Android Context完全解析,你所不知道的Context的各種細(xì)節(jié)

Android Context 上下文 你必須知道的一切

目標(biāo)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末链蕊,一起剝皮案震驚了整個(gè)濱河市事甜,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌滔韵,老刑警劉巖逻谦,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異陪蜻,居然都是意外死亡邦马,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來滋将,“玉大人邻悬,你說我怎么就攤上這事∷婷觯” “怎么了父丰?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長橱脸。 經(jīng)常有香客問我础米,道長,這世上最難降的妖魔是什么添诉? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任屁桑,我火速辦了婚禮,結(jié)果婚禮上栏赴,老公的妹妹穿的比我還像新娘蘑斧。我一直安慰自己,他們只是感情好须眷,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布竖瘾。 她就那樣靜靜地躺著,像睡著了一般花颗。 火紅的嫁衣襯著肌膚如雪捕传。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天扩劝,我揣著相機(jī)與錄音庸论,去河邊找鬼。 笑死棒呛,一個(gè)胖子當(dāng)著我的面吹牛聂示,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播簇秒,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼鱼喉,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了趋观?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤皱坛,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡抹沪,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年刻肄,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了融欧。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,841評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡噪馏,死狀恐怖麦到,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情欠肾,我是刑警寧澤,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布粹淋,位于F島的核電站瑟慈,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏借杰。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一蔗衡、第九天 我趴在偏房一處隱蔽的房頂上張望缘琅。 院中可真熱鬧,春花似錦翩隧、人聲如沸呻纹。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽哥力。三九已至墩弯,卻和暖如春寞射,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背桥温。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工侵浸, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人掏觉。 一個(gè)月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓履腋,卻偏偏與公主長得像,于是被迫代替她去往敵國和親遵湖。 傳聞我的和親對象是個(gè)殘疾皇子延旧,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評論 2 354

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