理解Android中不同的Context

作者:兩日的blog

Context是什么郭计,有什么用

在Android開發(fā)中霞揉,Context是一個抽象類有额,它是Android應(yīng)用程序環(huán)境的一部分竹海。它提供了訪問應(yīng)用程序資源和執(zhí)行各種操作的接口慕蔚。可以說,Context是Android應(yīng)用程序與系統(tǒng)環(huán)境進行交互的橋梁斋配。

Context的作用包括:

  1. 訪問應(yīng)用程序資源:通過Context孔飒,可以獲取應(yīng)用程序的資源,如字符串许起、布局文件十偶、圖像等。這些資源可以在應(yīng)用程序的各個組件中使用园细,例如Activity惦积、ServiceBroadcastReceiver等猛频。
  2. 啟動組件:通過Context狮崩,可以啟動其他組件,如啟動Activity鹿寻、啟動Service睦柴、發(fā)送廣播等。它提供了訪問系統(tǒng)服務(wù)的能力毡熏,如啟動其他應(yīng)用程序坦敌、發(fā)送系統(tǒng)廣播等。
  3. 獲取應(yīng)用程序的上下文:通過Context,可以獲取應(yīng)用程序的上下文狱窘,如獲取ApplicationContext杜顺,用于在整個應(yīng)用程序中共享數(shù)據(jù)或執(zhí)行全局操作。
  4. 訪問系統(tǒng)服務(wù):通過Context蘸炸,可以訪問各種系統(tǒng)服務(wù)躬络,如獲取系統(tǒng)級的服務(wù)(如傳感器服務(wù)、位置服務(wù))搭儒、訪問設(shè)備功能(如攝像頭穷当、存儲器)、執(zhí)行網(wǎng)絡(luò)操作等淹禾。
  5. 訪問應(yīng)用程序的文件:通過Context對象馁菜,可以獲取應(yīng)用程序的文件目錄,創(chuàng)建稀拐、讀取火邓、寫入和刪除文件等操作。
  6. 處理資源生命周期:通過Context德撬,可以管理應(yīng)用程序資源的生命周期铲咨,如創(chuàng)建、銷毀對象蜓洪、注冊和注銷監(jiān)聽器等纤勒。它提供了一種機制,確保資源的正確使用和釋放隆檀,避免內(nèi)存泄漏等問題摇天。
public abstract AssetManager getAssets();

/**
 * Returns a Resources instance for the application's package.
 * <p>
 * <strong>Note:</strong> Implementations of this method should return
 * a Resources instance that is consistent with the AssetManager instance
 * returned by {@link #getAssets()}. For example, they should share the
 * same {@link Configuration} object.
 *
 * @return a Resources instance for the application's package
 * @see #getAssets()
 */
public abstract Resources getResources();

/** Return PackageManager instance to find global package information. */
public abstract PackageManager getPackageManager();

/** Return a ContentResolver instance for your application's package. */
public abstract ContentResolver getContentResolver();

/**
 * Return the Looper for the main thread of the current process.  This is
 * the thread used to dispatch calls to application components (activities,
 * services, etc).
 * <p>
 * By definition, this method returns the same result as would be obtained
 * by calling {@link Looper#getMainLooper() Looper.getMainLooper()}.
 * </p>
 *
 * @return The main looper.
 */
public abstract Looper getMainLooper();

/**
 * Return an {@link Executor} that will run enqueued tasks on the main
 * thread associated with this context. This is the thread used to dispatch
 * calls to application components (activities, services, etc).
 */
public Executor getMainExecutor() {
    // This is pretty inefficient, which is why ContextImpl overrides it
    return new HandlerExecutor(new Handler(getMainLooper()));
}

 
public abstract Context getApplicationContext();

public final CharSequence getText(@StringRes int resId) {
    return getResources().getText(resId);
}

/**
 * Returns a localized string from the application's package's
 * default string table.
 *
 * @param resId Resource id for the string
 * @return The string data associated with the resource, stripped of styled
 *         text information.
 */
@NonNull
public final String getString(@StringRes int resId) {
    return getResources().getString(resId);
}

/**
 * Returns a localized formatted string from the application's package's
 * default string table, substituting the format arguments as defined in
 * {@link java.util.Formatter} and {@link java.lang.String#format}.
 *
 * @param resId Resource id for the format string
 * @param formatArgs The format arguments that will be used for
 *                   substitution.
 * @return The string data associated with the resource, formatted and
 *         stripped of styled text information.
 */
@NonNull
public final String getString(@StringRes int resId, Object... formatArgs) {
    return getResources().getString(resId, formatArgs);
}

/**
 * Returns a color associated with a particular resource ID and styled for
 * the current theme.
 *
 * @param id The desired resource identifier, as generated by the aapt
 *           tool. This integer encodes the package, type, and resource
 *           entry. The value 0 is an invalid identifier.
 * @return A single color value in the form 0xAARRGGBB.
 * @throws android.content.res.Resources.NotFoundException if the given ID
 *         does not exist.
 */
@ColorInt
public final int getColor(@ColorRes int id) {
    return getResources().getColor(id, getTheme());
}

/**
 * Returns a drawable object associated with a particular resource ID and
 * styled for the current theme.
 *
 * @param id The desired resource identifier, as generated by the aapt
 *           tool. This integer encodes the package, type, and resource
 *           entry. The value 0 is an invalid identifier.
 * @return An object that can be used to draw this resource.
 * @throws android.content.res.Resources.NotFoundException if the given ID
 *         does not exist.
 */
@Nullable
public final Drawable getDrawable(@DrawableRes int id) {
    return getResources().getDrawable(id, getTheme());
}

/**
 * Returns a color state list associated with a particular resource ID and
 * styled for the current theme.
 *
 * @param id The desired resource identifier, as generated by the aapt
 *           tool. This integer encodes the package, type, and resource
 *           entry. The value 0 is an invalid identifier.
 * @return A color state list.
 * @throws android.content.res.Resources.NotFoundException if the given ID
 *         does not exist.
 */
@NonNull
public final ColorStateList getColorStateList(@ColorRes int id) {
    return getResources().getColorStateList(id, getTheme());
}

 /**
 * Set the base theme for this context.  Note that this should be called
 * before any views are instantiated in the Context (for example before
 * calling {@link android.app.Activity#setContentView} or
 * {@link android.view.LayoutInflater#inflate}).
 *
 * @param resid The style resource describing the theme.
 */
public abstract void setTheme(@StyleRes int resid);

/** @hide Needed for some internal implementation...  not public because
 * you can't assume this actually means anything. */
@UnsupportedAppUsage
public int getThemeResId() {
    return 0;
}

/**
 * Return the Theme object associated with this Context.
 */
@ViewDebug.ExportedProperty(deepExport = true)
public abstract Resources.Theme getTheme();

/**
 * Retrieve styled attribute information in this Context's theme.  See
 * {@link android.content.res.Resources.Theme#obtainStyledAttributes(int[])}
 * for more information.
 *
 * @see android.content.res.Resources.Theme#obtainStyledAttributes(int[])
 */
@NonNull
public final TypedArray obtainStyledAttributes(@NonNull @StyleableRes int[] attrs) {
    return getTheme().obtainStyledAttributes(attrs);
}

/**
 * Retrieve styled attribute information in this Context's theme.  See
 * {@link android.content.res.Resources.Theme#obtainStyledAttributes(int, int[])}
 * for more information.
 *
 * @see android.content.res.Resources.Theme#obtainStyledAttributes(int, int[])
 */
@NonNull
public final TypedArray obtainStyledAttributes(@StyleRes int resid,
        @NonNull @StyleableRes int[] attrs) throws Resources.NotFoundException {
    return getTheme().obtainStyledAttributes(resid, attrs);
}

/**
 * Retrieve styled attribute information in this Context's theme.  See
 * {@link android.content.res.Resources.Theme#obtainStyledAttributes(AttributeSet, int[], int, int)}
 * for more information.
 *
 * @see android.content.res.Resources.Theme#obtainStyledAttributes(AttributeSet, int[], int, int)
 */
@NonNull
public final TypedArray obtainStyledAttributes(
        @Nullable AttributeSet set, @NonNull @StyleableRes int[] attrs) {
    return getTheme().obtainStyledAttributes(set, attrs, 0, 0);
}

/**
 * Retrieve styled attribute information in this Context's theme.  See
 * {@link android.content.res.Resources.Theme#obtainStyledAttributes(AttributeSet, int[], int, int)}
 * for more information.
 *
 * @see android.content.res.Resources.Theme#obtainStyledAttributes(AttributeSet, int[], int, int)
 */
@NonNull
public final TypedArray obtainStyledAttributes(@Nullable AttributeSet set,
        @NonNull @StyleableRes int[] attrs, @AttrRes int defStyleAttr,
        @StyleRes int defStyleRes) {
    return getTheme().obtainStyledAttributes(
        set, attrs, defStyleAttr, defStyleRes);
}

總之,Context在Android開發(fā)中具有重要的作用恐仑,它提供了訪問應(yīng)用程序資源泉坐、啟動組件、訪問系統(tǒng)服務(wù)以及處理資源生命周期的能力裳仆。開發(fā)者可以使用Context來實現(xiàn)各種應(yīng)用程序功能和與系統(tǒng)環(huán)境的交互腕让。

Context有哪些

Context 本身是一個抽象類,主要實現(xiàn)類為 ContextImpl歧斟,另外有子類 ContextWrapperContextThemeWrapper纯丸,另外還有其他由上述三個類引申出來的Context類,Application/Service/Activity静袖,他們的繼承關(guān)系如下:

ContextImpl/ContextWrapper/ContextThemeWrapper的區(qū)別

ContextImpl ContextWrapper ContextThemeWrapper
ContextImplContext的主要實現(xiàn)類觉鼻,它提供了大部分Context的基本功能和行為。它是Android框架中真正的上下文實現(xiàn)類队橙,用于處理應(yīng)用程序的資源訪問坠陈、組件啟動萨惑、文件操作和系統(tǒng)服務(wù)等操作。 ContextWrapper是一個包裝類仇矾,用于對現(xiàn)有的Context對象進行包裝或修改其功能咒钟。它是Context的一個間接子類,可以通過繼承ContextWrapper類來擴展Context的功能若未,例如添加自定義的行為或修改Context的行為。 ContextThemeWrapperContextThemeWrapperContext的另一個包裝類倾鲫,它繼承自ContextWrapper類粗合。與ContextWrapper類似,ContextThemeWrapper也是用于包裝現(xiàn)有的Context對象乌昔,但它還提供了自己的主題資源隙疚。通過ContextThemeWrapper,可以為特定的上下文設(shè)置不同的主題磕道,以實現(xiàn)界面的樣式和外觀的變化供屉。

ContextImpl

上文說到,Context本身是一個抽象類溺蕉,主要的實現(xiàn)類就是ContextImpl伶丐,即Context的那些功能都是在ContexImpl中實現(xiàn)的,即ContextImpl實際承擔(dān)著提供應(yīng)用程序資源訪問疯特、組件啟動和系統(tǒng)服務(wù)等功能的責(zé)任哗魂。

public class ContextImpl extends Context {
    private Resources mResources;
    private Theme mTheme;
   
    void setResources(Resources r) {
        if (r instanceof CompatResources) {
            ((CompatResources) r).setContext(this);
        }
        mResources = r;
    }
    
    @Override
    public Resources getResources() {
        return mResources;
    }
    
    @Override
    public void setTheme(int resId) {
        synchronized (mSync) {
            if (mThemeResource != resId) {
                mThemeResource = resId;
                initializeTheme();
            }
        }
    }
    
    public Resources.Theme getTheme() {
        synchronized (mSync) {
            if (mTheme != null) {
                return mTheme;
            }
    
            mThemeResource = Resources.selectDefaultTheme(mThemeResource,
                    getOuterContext().getApplicationInfo().targetSdkVersion);
            initializeTheme();
    
            return mTheme;
        }
    }
    
    private void initializeTheme() {
        if (mTheme == null) {
            mTheme = mResources.newTheme();
        }
        mTheme.applyStyle(mThemeResource, true);
    }
    
    // 其他方法的實現(xiàn)省略...
}

ContextImpl,我們重點關(guān)注一下ResourceTheme的相關(guān)實現(xiàn)漓雅,ContextImpl中提供了getResources/setResources方法录别,用于獲取Resources以及設(shè)置Resources,以提供資源的訪問邻吞。

getTheme/setTheme用于獲取Theme以及設(shè)置Theme组题,以提供對主題的訪問.

重點看一下getTheme()方法,該方法抱冷,會首先獲取mThemeResource崔列,這里直接選擇的系統(tǒng)默認主題,系統(tǒng)會根據(jù)不同的sdk版本選擇不同的默認主題徘层。

@UnsupportedAppUsage
public static int selectDefaultTheme(int curTheme, int targetSdkVersion) {
    return selectSystemTheme(curTheme, targetSdkVersion,
            com.android.internal.R.style.Theme,
            com.android.internal.R.style.Theme_Holo,
            com.android.internal.R.style.Theme_DeviceDefault,
            com.android.internal.R.style.Theme_DeviceDefault_Light_DarkActionBar);
}

/** @hide */
public static int selectSystemTheme(int curTheme, int targetSdkVersion, int orig, int holo,
        int dark, int deviceDefault) {
    if (curTheme != ID_NULL) {
        return curTheme;
    }
    if (targetSdkVersion < Build.VERSION_CODES.HONEYCOMB) {
        return orig;
    }
    if (targetSdkVersion < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
        return holo;
    }
    if (targetSdkVersion < Build.VERSION_CODES.N) {
        return dark;
    }
    return deviceDefault;
}

通過ContextImpl的實例峻呕,應(yīng)用程序可以獲取到Resources對象和Theme對象,從而實現(xiàn)對資源和主題的訪問和處理趣效。需要注意的是瘦癌,這是一個簡化的,實際的ContextImpl源碼非常復(fù)雜跷敬,還涉及到處理上下文的生命周期讯私、系統(tǒng)服務(wù)的獲取等方面的邏輯。

ContextWrapper

ContextWrapper是一個包裝類,內(nèi)部包含一個mBase成員變量斤寇,所有的實現(xiàn)都是調(diào)用mBase的方法桶癣。

public class ContextWrapper extends Context {
    @UnsupportedAppUsage
    Context mBase;

    public ContextWrapper(Context base) {
        mBase = base;
    }
    
    @Override
    public void setTheme(int resid) {
        mBase.setTheme(resid);
    }
    
    /** @hide */
    @Override
    @UnsupportedAppUsage
    public int getThemeResId() {
        return mBase.getThemeResId();
    }
    
    @Override
    public Resources.Theme getTheme() {
        return mBase.getTheme();
    }
    
    @Override
    public ClassLoader getClassLoader() {
        return mBase.getClassLoader();
    }
    
    @Override
    public String getPackageName() {
        return mBase.getPackageName();
    }
    
 }

ContextThemeWrapper

ContextThemeWrapper繼承自ContextWrapper,從名字中可以看出娘锁,該類主要是跟主題相關(guān)的包裝類:

public class ContextThemeWrapper extends ContextWrapper {
    ...
    
    @Override
    public Resources getResources() {
        return getResourcesInternal();
    }
    
    private Resources getResourcesInternal() {
        if (mResources == null) {
            if (mOverrideConfiguration == null) {
                mResources = super.getResources();
            } else {
                final Context resContext = createConfigurationContext(mOverrideConfiguration);
                mResources = resContext.getResources();
            }
        }
        return mResources;
    }
    
    @Override
    public void setTheme(int resid) {
        if (mThemeResource != resid) {
            mThemeResource = resid;
            initializeTheme();
        }
    }
    
    @Override
    public Resources.Theme getTheme() {
        if (mTheme != null) {
            return mTheme;
        }
    
        mThemeResource = Resources.selectDefaultTheme(mThemeResource,
                getApplicationInfo().targetSdkVersion);
        initializeTheme();
    
        return mTheme;
    }
    
    @UnsupportedAppUsage
    private void initializeTheme() {
        final boolean first = mTheme == null;
        if (first) {
            mTheme = getResources().newTheme();
            final Resources.Theme theme = getBaseContext().getTheme();
            if (theme != null) {
                mTheme.setTo(theme);
            }
        }
        onApplyThemeResource(mTheme, mThemeResource, first);
    }
    
    ...

}

ContextImpl相比較牙寞,ContextThemeWrapper中獲取資源以及主題的代碼有所不同,多了一個Configuration莫秆,其他行為大致一致间雀。

另外在AppCompat中,默認的主題為Theme_AppCompat_Light镊屎,

package androidx.appcompat.view;

public class ContextThemeWrapper extends ContextWrapper {
    ... 
    @Override
    public Resources.Theme getTheme() {
        if (mTheme != null) {
            return mTheme;
        }
    
        if (mThemeResource == 0) {
            mThemeResource = R.style.Theme_AppCompat_Light;
        }
        initializeTheme();
    
        return mTheme;
    }
}

App中不同Context對象的Theme

我們在開發(fā)中惹挟,經(jīng)常會用到各種Context,常用的有activity/application/applicationContext/baseContext缝驳,為了測試不同Context中Theme對象连锯,我們編寫如下代碼:

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        printLog("baseContext is ${baseContext.themeResId} baseContext is $baseContext")
        printLog("application is ${application.themeResId} application is $application")
        printLog("applicationContext is ${applicationContext.themeResId} applicationContext is $applicationContext")
        printLog("activity is ${this.themeResId}")

    }

    private fun printLog(msg: String) {
        println("MainActivity themeResId in $msg")
    }
}

我們分別獲取每個Context對應(yīng)的themeResId,即每個ContextTheme對應(yīng)的resId

對代碼運行結(jié)果我們有如下結(jié)論:

  1. getApplicationgetApplicationContext得到的是同一個Application實例對象用狱;
  2. Application對象中的themeResId 為0 运怖,Application其實也有主題的應(yīng)用,畢竟主題樣式都是針對UI元素的齿拂;
  3. Activity****中的主題和****getBaseContext****中的主題是不一樣的驳规,具體對應(yīng)什么主題下文將進行探究
  4. getBaseContext中得到的是ContextThemeWrapper,這點讓我有點意外署海,之前的理解都是Activity啟動時吗购,會新建一個ContextImpl對象,在attachBaseContext中賦予Activity中的mBase砸狞,于是仔細研究一下發(fā)現(xiàn)捻勉,其實是AppCompatActivity做了替換:
//androidx.appcompat.app.AppCompatActivity
// AppCompatActivity重寫了Activity中的attachBaseContext方法
@Override
protected void attachBaseContext(Context newBase) {
    super.attachBaseContext(getDelegate().attachBaseContext2(newBase));
}

我們看一下代理類AppCompatDelegateImplattachBaseContext2的實現(xiàn):

//androidx.appcompat.app.AppCompatDelegateImpl

@NonNull
@Override
@CallSuper
public Context attachBaseContext2(@NonNull final Context baseContext) {
    mBaseContextAttached = true;

    final int modeToApply = mapNightMode(baseContext, calculateNightMode());

    // If the base context is a ContextThemeWrapper (thus not an Application context)
    // and nobody's touched its Resources yet, we can shortcut and directly apply our
    // override configuration.
    if (sCanApplyOverrideConfiguration
            && baseContext instanceof android.view.ContextThemeWrapper) {
        final Configuration config = createOverrideConfigurationForDayNight(
                baseContext, modeToApply, null);

        ContextThemeWrapperCompatApi17Impl.applyOverrideConfiguration(
                (android.view.ContextThemeWrapper) baseContext, config);
        return baseContext;
        
    }

    // Again, but using the AppCompat version of ContextThemeWrapper.
    if (baseContext instanceof ContextThemeWrapper) {
        final Configuration config = createOverrideConfigurationForDayNight(
                baseContext, modeToApply, null);
        
        ((ContextThemeWrapper) baseContext).applyOverrideConfiguration(config);
        return baseContext;
        
    }

    // We can't apply the configuration directly to the existing base context, so we need to
    // wrap it. We can't create a new configuration context since the app may rely on method
    // overrides or a specific theme -- neither of which are preserved when creating a
    // configuration context. Instead, we'll make a best-effort at wrapping the context and
    // rebasing the original theme.
    if (!sCanReturnDifferentContext) {
        return super.attachBaseContext2(baseContext);
    }

    Configuration configOverlay = null;

    final Configuration config = createOverrideConfigurationForDayNight(
            baseContext, modeToApply, configOverlay);
  
      //重點1:新建ContextThemeWrapper對象將傳入的baseContext賦值給ContextWrapper中的mBase,
      // 并且ContextThemeWrapper中的主題為Theme_AppCompat_Empty
    // Next, we'll wrap the base context to ensure any method overrides or themes are left
    // intact. Since ThemeOverlay.AppCompat theme is empty, we'll get the base context's theme.
    final ContextThemeWrapper wrappedContext = new ContextThemeWrapper(baseContext,
            R.style.Theme_AppCompat_Empty);
    wrappedContext.applyOverrideConfiguration(config);

    // Check whether the base context has an explicit theme or is able to obtain one
    // from its outer context. If it throws an NPE because we're at an invalid point in app
    // initialization, we don't need to worry about rebasing under the new configuration.
    boolean needsThemeRebase;
    try {
        needsThemeRebase = baseContext.getTheme() != null;
    } catch (NullPointerException e) {
        needsThemeRebase = false;
    }

    if (needsThemeRebase) {
        // Attempt to rebase the old theme within the new configuration. This will only
        // work on SDK 23 and up, but it's unlikely that we're keeping the base theme
        // anyway so maybe nobody will notice. Note that calling getTheme() will clone
        // the base context's theme into the wrapped context's theme.
        ResourcesCompat.ThemeCompat.rebase(wrappedContext.getTheme());
    }

    
    return super.attachBaseContext2(wrappedContext);
}

//androidx.appcompat.app.AppCompatDelegate
@NonNull
@CallSuper
public Context attachBaseContext2(@NonNull Context context) {
// 重點2刀森,將上一步包裝了baseContext的ContextThemeWrapper對象進一步賦值給Activity的mBase
    attachBaseContext(context);
    return context;
}

最終AppCompatActivity中的mBase是包裝了ContextImplContextThemeWrapper對象踱启,并且其主題為Theme_AppCompat_Empty

關(guān)于第三點,getBaseActivityActivity中的主題到底是哪一個研底,我們可以根據(jù)resId和resources索引表resource.arsc(直接將apk文件拖到AndroidStudio中就可以看到該文件)找到:

21317554102131755474對應(yīng)16進制為0x7f1001920x7f1001d2

可以看到埠偿,getBaseActivityActivity中的主題分別對應(yīng)Theme_AppCompat_Empty 與我們在AndroidManifest.xml中設(shè)置的應(yīng)用主題Theme.ThemeTest

總結(jié)

Context是Android應(yīng)用程序與系統(tǒng)環(huán)境進行交互的橋梁,主要實現(xiàn)類是ContextImpl, 可以訪問應(yīng)用程序資源/啟動組件/訪問系統(tǒng)服務(wù)/訪問應(yīng)用程序的文件等榜晦,而Context可以分為三種:ContextImpl/ContextWrapper/ContextThemeWrapper冠蒋,不同ContextImpl 是Context的主要實現(xiàn)類,ContextWrapper是簡單的包裝類乾胶,所有的實現(xiàn)都由其內(nèi)部的mBase成員完成抖剿,ContextThemeWrapper繼承自ContextWrapper 朽寞,它的主要繼承者是Activity,和其他兩個Context不同的是斩郎,他內(nèi)部對應(yīng)用資源和主題有不同的行為脑融,在應(yīng)用中使用跟主題相關(guān)的Context時,最好使用activity缩宜,而不要使用getBaseContext或者applictaion.

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末是尖,一起剝皮案震驚了整個濱河市爷贫,隨后出現(xiàn)的幾起案子米碰,更是在濱河造成了極大的恐慌受啥,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,270評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件炼幔,死亡現(xiàn)場離奇詭異,居然都是意外死亡史简,警方通過查閱死者的電腦和手機乃秀,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來圆兵,“玉大人跺讯,你說我怎么就攤上這事⊙撑” “怎么了刀脏?”我有些...
    開封第一講書人閱讀 165,630評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長超凳。 經(jīng)常有香客問我愈污,道長,這世上最難降的妖魔是什么轮傍? 我笑而不...
    開封第一講書人閱讀 58,906評論 1 295
  • 正文 為了忘掉前任暂雹,我火速辦了婚禮,結(jié)果婚禮上创夜,老公的妹妹穿的比我還像新娘杭跪。我一直安慰自己,他們只是感情好驰吓,可當我...
    茶點故事閱讀 67,928評論 6 392
  • 文/花漫 我一把揭開白布涧尿。 她就那樣靜靜地躺著,像睡著了一般檬贰。 火紅的嫁衣襯著肌膚如雪姑廉。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,718評論 1 305
  • 那天偎蘸,我揣著相機與錄音庄蹋,去河邊找鬼瞬内。 笑死,一個胖子當著我的面吹牛限书,可吹牛的內(nèi)容都是我干的虫蝶。 我是一名探鬼主播,決...
    沈念sama閱讀 40,442評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼倦西,長吁一口氣:“原來是場噩夢啊……” “哼能真!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起扰柠,我...
    開封第一講書人閱讀 39,345評論 0 276
  • 序言:老撾萬榮一對情侶失蹤粉铐,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后卤档,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蝙泼,經(jīng)...
    沈念sama閱讀 45,802評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,984評論 3 337
  • 正文 我和宋清朗相戀三年劝枣,在試婚紗的時候發(fā)現(xiàn)自己被綠了汤踏。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,117評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡舔腾,死狀恐怖溪胶,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情稳诚,我是刑警寧澤哗脖,帶...
    沈念sama閱讀 35,810評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站扳还,受9級特大地震影響才避,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜氨距,卻給世界環(huán)境...
    茶點故事閱讀 41,462評論 3 331
  • 文/蒙蒙 一工扎、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧衔蹲,春花似錦肢娘、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,011評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至沙廉,卻和暖如春拘荡,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背撬陵。 一陣腳步聲響...
    開封第一講書人閱讀 33,139評論 1 272
  • 我被黑心中介騙來泰國打工珊皿, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留网缝,地道東北人。 一個月前我還...
    沈念sama閱讀 48,377評論 3 373
  • 正文 我出身青樓蟋定,卻偏偏與公主長得像粉臊,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子驶兜,可洞房花燭夜當晚...
    茶點故事閱讀 45,060評論 2 355

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