SystemUI 與 Dagger2 框架

Dagger2 注解基礎(chǔ)

結(jié)構(gòu)

Dagger2 要實(shí)現(xiàn)一個(gè)完整的依賴注入佩谣,必不可少的元素有三種把还,Module,Component茸俭,Container吊履。

Container 就是可以被注入的容器,Container 擁有需要被初始化的元素调鬓。需要被初始化的元素必須標(biāo)上 @Inject艇炎,只有被標(biāo)上 @Inject 的元素才會(huì)被自動(dòng)初始化。被注解的構(gòu)造方法會(huì)自動(dòng)編譯生成一個(gè)Factory工廠類提供該類對(duì)象腾窝。

Module 可以說(shuō)就是依賴的原材料的制造工廠缀踪,所有需要被注入的元素的實(shí)現(xiàn)都是從 Module 生產(chǎn)并且封裝起來(lái),然后交給注入器 Component虹脯。

Component 相當(dāng)于中間的運(yùn)輸員驴娃,將 Module 中產(chǎn)生的依賴對(duì)象自動(dòng)注入到 Container 中。

一些常用的注解

@Inject
  1. 用 @Inject 注解標(biāo)注目標(biāo)類中依賴類的實(shí)例對(duì)象
  2. 用 @Inject 注解標(biāo)注依賴類的構(gòu)造函數(shù)
  3. 若其他類還依賴于另外的類循集,則重復(fù)進(jìn)行上面2個(gè)步驟
@Component
  1. 所有的 Component 都必須以接口形式定義托慨,使用 @Component 注解的接口一般直接命名為 XXXComponent
  2. Dagger2 框架將自動(dòng)生成該 Component 的實(shí)現(xiàn)類,對(duì)應(yīng)的類名是 DaggerXXXComponent
  3. 添加注入方法暇榴,一般使用 inject 做為方法名,方法參數(shù)為對(duì)應(yīng)的 Container蕉世,調(diào)用該方法進(jìn)行注入蔼紧,有參數(shù)的方法返回值類型是void
  4. 注入方法也可以沒(méi)有輸入?yún)?shù)型豁,但是必須有返回值瘩燥,返回的實(shí)例會(huì)先從事先定義的 Module 中查找,如果找不到赡模,則會(huì)使用該類中帶 @Inject 的構(gòu)造方法來(lái)生成向楼,同時(shí)也會(huì)遞歸注入構(gòu)造方法的參數(shù)以及帶 @Inject 的成員變量
@Module
  1. Module 是一個(gè)簡(jiǎn)單的工廠類查吊,添加注解 @Module 注明本類屬于 Module
  2. Module 里面的方法都是創(chuàng)建相應(yīng)類實(shí)例的方法
  3. 在 Module 中添加注解 @Provides 注明該方法是用來(lái)提供依賴對(duì)象的特殊方法

注:一個(gè) Component 可以包含多個(gè) Module ,這樣 Component 獲取依賴時(shí)候會(huì)自動(dòng)從多個(gè) Module 中查找獲取湖蜕,Module 間不能有重復(fù)方法逻卖。添加多個(gè) Module 有兩種方法,一種是在 Component 的注解 @Component(modules={×××.class昭抒,×××.class}) 添加多個(gè) modules评也,另外一種是在可以被使用的 Module 標(biāo)簽中的添加其他 modules: @Module(includes={×××.class炼杖,×××.class})

@Provides
  1. 通過(guò) @Provides 標(biāo)注該 Module 可以向外界提供的類的實(shí)例對(duì)象的方法
  2. Module 中 @Provides 方法可以帶輸入?yún)?shù),其參數(shù)由 Module 集合中的其他 @Provides 方法的返回值提供
  3. 如果2中找不到 @Provides 方法提供對(duì)應(yīng)參數(shù)的對(duì)象盗迟,則其會(huì)自動(dòng)查找參數(shù)類中帶 @Inject 的無(wú)參構(gòu)造生成對(duì)象
@Binds
  1. 使用 @Inject 初始化對(duì)象時(shí)如果需要初始化的是接口的實(shí)例坤邪,這時(shí)候就需要用到 @Binds
  2. 方法中必須有且只有一個(gè)參數(shù),必須是接口的實(shí)現(xiàn)類
  3. 實(shí)現(xiàn)類必須提供 @Inject 的構(gòu)造或 Module 中以 @Provides 形式提供
  4. @Binds 相當(dāng)于是在接口或者抽象類中代替 @Provides
@Named
  1. @Named 是基于 String 的限定符
  2. 有兩個(gè)相同的依賴(都繼承某一個(gè)父類或者都實(shí)現(xiàn)某一個(gè)接口)可以提供罚缕,這個(gè)時(shí)候就需要用 @Named 來(lái)區(qū)分艇纺,使用方法為 @Named("AAA"),@Named("BBB")
  3. 擁有相同 @Named 的 @Inject 成員變量與 @Provides 方法才能被對(duì)應(yīng)起來(lái)使用
@Qualifier
  1. @Qualifier 用來(lái)注解接口作為自定義區(qū)分標(biāo)志
  2. 使用此注解的接口 xxx.java 可以當(dāng)做注解標(biāo)簽進(jìn)行使用邮弹,@xxx
@Singleton與@Scope
  1. 顧名思義使用 @Singleton 是用來(lái)標(biāo)注單例對(duì)象的
  2. 在 Component 里的方法添加 @Singleton黔衡,同時(shí)在 Module 對(duì)應(yīng)的 @Provides 方法上也添加 @Singleton,這樣一來(lái)每次注入的都會(huì)是同一個(gè)對(duì)象
  3. @Scope 是注解的注解肠鲫, Scope機(jī)制可以保證在 Scope 標(biāo)記的 Component 作用域內(nèi) 员帮,類會(huì)保持單例,@Singleton 是 @Scope 的一個(gè)默認(rèn)實(shí)現(xiàn)
@Subcomponent
  1. @Subcomponent 用于拓展原有 Component导饲,它與 @Component(dependencies=XXComponent.classs) 類似
  2. @Subcomponent 注解不會(huì)在編譯后生成Dagger前綴的容器類捞高,而是體現(xiàn)在父 Component 的私有內(nèi)部類
  3. Subcomponent 既擁有父 Component 擁有的 Scope,也擁有自己的 Scope
  4. 在父 Component 中顯式添加添加返回 SubComponent 的方法后渣锦,繼承關(guān)系才成立硝岗,SubComponent 能自動(dòng)在父 Component 中查找缺失的依賴

注入方式

Provider與Lazy

Provider和Lazy都是用于包裝Container中需要被注入的類型,Lazy用于延遲加載袋毙,Provide用于強(qiáng)制重新加載。
Provider保證每次重新加載听盖,但是并不意味著每次返回的對(duì)象都是不同的胀溺,只有Module的Provide方法每次都創(chuàng)建新實(shí)例時(shí)仓坞,Provider每次get()的對(duì)象才不相同毛雇。
Lazy != Singleton嫉称,如果有兩個(gè)不同的Lazy對(duì)象,那么他們get()的對(duì)象也是不同的灵疮。

示例:

    @Module
    final class CounterModule {
        int next = 100;

        @Provides
        Integer provideInteger() {
            System.out.println("computing...");
            return next++;
        }
    }

    // Provider 注入
    final class ProviderCounter {
        @Inject Provider<Integer> provider;
        void print() {
            System.out.println("printing...");
            System.out.println(provider.get());
            System.out.println(provider.get());
            System.out.println(provider.get());
    }
    /**    
     *    打印結(jié)果:
     *     printing...
     *     computing...
     *     100
     *     computing...
     *     101
     *     computing...
     *     102
     */

    // Lazy 注入
    final class LazyCounter {
        @Inject Lazy<Integer> Lazy;
        void print() {
            System.out.println("printing...");
            System.out.println(Lazy.get());
            System.out.println(Lazy.get());
            System.out.println(Lazy.get());
    }
    /**    
     *    打印結(jié)果:
     *     printing...
     *     computing...
     *     100
     *     100
     *     100
     */

Dagger2 導(dǎo)航

Android Studio 針對(duì) Dagger2 的導(dǎo)航進(jìn)行了支持织阅,方便開發(fā)者快速回溯依賴關(guān)系。


Dagger2 導(dǎo)航
  • 點(diǎn)擊向上的箭頭可以查看該實(shí)例注入的提供方
  • 點(diǎn)擊向下的樹形圖會(huì)轉(zhuǎn)到或展開該實(shí)例被用作依賴項(xiàng)的位置或列表

Dagger2 在 SystemUI 里的應(yīng)用

SystemUI里面大量的模塊都使用了此注入方式震捣,比如StatusBar蒲稳,QS氮趋,Keyguard等。
下面以 Android 11 源碼的SystemUI來(lái)詳細(xì)說(shuō)明江耀。

定義清單列表

SystemUI的application標(biāo)簽定義了一個(gè)appComponentFactory屬性

<application
    android:name=".SystemUIApplication"
    ...
    tools:replace="android:appComponentFactory"
    android:appComponentFactory=".SystemUIAppComponentFactory">

    ...

    <service ...
    />

    <activity ...
    />

    <reveiver ...
    />

    ...

</application>

這個(gè)屬性是用來(lái)控制manifest清單文件里的組件的初始化剩胁,在manifest清單文件里的組件構(gòu)建對(duì)象時(shí)會(huì)調(diào)用下面這些方法。


AppComponentFactory

啟動(dòng)Application

隨著SystemServer發(fā)出啟動(dòng)SystemUIService的請(qǐng)求祥国,SystemUI的Application將首先被實(shí)例化昵观。在實(shí)例化之前,指定的AppComponentFactory實(shí)現(xiàn)類將會(huì)收到回調(diào)舌稀。

  1. 調(diào)用super得到Application實(shí)例之后向其注冊(cè)Context準(zhǔn)備完畢的回調(diào)啊犬,該回調(diào)會(huì)執(zhí)行SystemUIFactory和各組件的初始化:
public class SystemUIAppComponentFactory extends AppComponentFactory {
    @Inject
    public ContextComponentHelper mComponentHelper;
    ...
    @Override
    public Application instantiateApplicationCompat(
            @NonNull ClassLoader cl, @NonNull String className)
            throws InstantiationException, IllegalAccessException, ClassNotFoundException {
        Application app = super.instantiateApplicationCompat(cl, className);
        if (app instanceof ContextInitializer) {
            // 注冊(cè)Context成功取得的回調(diào)
            ((ContextInitializer) app).setContextAvailableCallback(
                    context -> {
                        SystemUIFactory.createFromConfig(context);
                        // 注入SystemUIAppComponentFactory對(duì)象
                        SystemUIFactory.getInstance().getRootComponent().inject(
                                SystemUIAppComponentFactory.this);
                    }
            );
        }

        return app;
    }
    ...
}
  1. 在SystemUIApplication onCreate時(shí)執(zhí)行上述回調(diào), 構(gòu)建SystemUIFactory,并對(duì)它進(jìn)行初始化:
public class SystemUIApplication extends Application implements
        SystemUIAppComponentFactory.ContextInitializer {
    ...
    @Override
    public void setContextAvailableCallback(
            SystemUIAppComponentFactory.ContextAvailableCallback callback) {
        mContextAvailableCallback = callback;
    }

    @Override
    public void onCreate() {
        ...
        // 執(zhí)行回調(diào)
        mContextAvailableCallback.onContextAvailable(this);
        // 獲取 SystemUIRootComponent壁查,很多組件都是通過(guò)它注入的
        mRootComponent = SystemUIFactory.getInstance().getRootComponent();
        // 通過(guò) SystemUIRootComponent 定義的注入方法獲得 ContextComponentHelper 對(duì)象
        mComponentHelper = mRootComponent.getContextComponentHelper();
        ...
    }
}
  1. 創(chuàng)建SystemUIFactory實(shí)例觉至,并初始化SystemUI 的Dagger組件,并向Dependency實(shí)例注入依賴:
public class SystemUIFactory {
    ...
    public static void createFromConfig(Context context) {
        ...
        try {
            Class<?> cls = null;
            cls = context.getClassLoader().loadClass(clsName);
            // 創(chuàng)建SystemUIFactory實(shí)例
            mFactory = (SystemUIFactory) cls.newInstance();
            // 初始化SystemUIFactory
            mFactory.init(context);
        }
    }

    private void init(Context context) {
        // 取得SystemUI的Dagger組件實(shí)例
        mRootComponent = buildSystemUIRootComponent(context);
        // 創(chuàng)建Dependency實(shí)例
        Dependency dependency = new Dependency();
        // 將Dependency綁定到子組件DependencyInjector中睡腿,這里會(huì)通過(guò)Component將各類依賴注入Dependency
        mRootComponent.createDependency().createSystemUI(dependency);
        // 初始化Dependency
        dependency.start();
    }

    // 初始化Dagger組件
    protected SystemUIRootComponent buildSystemUIRootComponent(Context context) {
        return DaggerSystemUIRootComponent.builder() 
                .dependencyProvider(new DependencyProvider())
                .contextHolder(new ContextHolder(context))
                .build();
    }
    ...
}
  1. Dependency里掌管著各式各樣的依賴语御,被依賴的各實(shí)例通過(guò)Map管理。每個(gè)依賴都通過(guò)LazyDependencyCreator將各實(shí)例對(duì)應(yīng)的懶加載回調(diào)緩存進(jìn)去席怪,然后保存在Map mProviders里应闯。其后在各實(shí)例真正使用時(shí)調(diào)用createDependency() 進(jìn)行創(chuàng)建:
public class Dependency {
    // 使用class作為key將對(duì)應(yīng)實(shí)例緩存
    private final ArrayMap<Object, Object> mDependencies = new ArrayMap<>();
    // 同樣的class的key緩存實(shí)例的懶加載回調(diào)
    private final ArrayMap<Object, LazyDependencyCreator> mProviders = new ArrayMap<>();

    protected void start() {
        // 構(gòu)建LazyDependencyCreator放入mProviders,回調(diào)取得對(duì)應(yīng)實(shí)例
        mProviders.put(TIME_TICK_HANDLER, mTimeTickHandler::get);
        mProviders.put(BG_LOOPER, mBgLooper::get);
        mProviders.put(MAIN_LOOPER, mMainLooper::get);
        mProviders.put(MAIN_HANDLER, mMainHandler::get);
        mProviders.put(ActivityStarter.class, mActivityStarter::get);
        mProviders.put(BroadcastDispatcher.class, mBroadcastDispatcher::get);
        ...
    }

    // 根據(jù)class查詢 mDependencies里的緩存
    private synchronized <T> T getDependencyInner(Object key) {
        T obj = (T) mDependencies.get(key);
        if (obj == null) {
            // 尚未緩存的話通過(guò)懶加載回調(diào)獲取注入的實(shí)例并緩存進(jìn) mDependencies
            obj = createDependency(key);
            mDependencies.put(key, obj);
            if (autoRegisterModulesForDump() && obj instanceof Dumpable) {
                mDumpManager.registerDumpable(obj.getClass().getName(), (Dumpable) obj);
            }
        }
        return obj;
    }

    // 根據(jù)class查詢 mProviders里的懶加載回調(diào)
    protected <T> T createDependency(Object cls) {
        Preconditions.checkArgument(cls instanceof DependencyKey<?> || cls instanceof Class<?>);
        LazyDependencyCreator<T> provider = mProviders.get(cls);
        if (provider == null) {
            throw new IllegalArgumentException("Unsupported dependency " + cls
                    + ". " + mProviders.size() + " providers known.");
        }
        // 里面的回調(diào)實(shí)現(xiàn)已經(jīng)通過(guò)start()里的mProviders.put存入了挂捻,實(shí)際調(diào)用的就是各類Lazy.get()
        return provider.createDependency();
    }

    private interface LazyDependencyCreator<T> {
        // 封裝好的回調(diào)
        T createDependency();
    }
}

啟動(dòng)SystemUIService

創(chuàng)建好Application后碉纺,會(huì)啟動(dòng)SystemUIService這個(gè)主Service,然后逐個(gè)啟動(dòng)其他組件刻撒。

public class SystemUIService extends Service {
    ...
    @Override
    public void onCreate() {
        super.onCreate();

        // Start all of SystemUI
        ((SystemUIApplication) getApplication()).startServicesIfNeeded();
        ...
    }
    ...
}

啟動(dòng)各類服務(wù)組件

回到 SystemUIApplication

public class SystemUIApplication {
    ...
    public void startServicesIfNeeded() {
        // 各services定義在 R.array.config_systemUIServiceComponents 里面
        String[] names = SystemUIFactory.getInstance().getSystemUIServiceComponents(getResources());
        startServicesIfNeeded(/* metricsPrefix= */ "StartServices", names);
    }

    private void startServicesIfNeeded(String metricsPrefix, String[] services) {
        ...
        final int N = services.length;
        for (int i = 0; i < N; i++) {
            String clsName = services[i];
            ...
            try {
                // 通過(guò)class name從ContextComponentHelper中獲取對(duì)應(yīng)組件的實(shí)例
                SystemUI obj = mComponentHelper.resolveSystemUI(clsName);
                if (obj == null) {
                    Constructor constructor = Class.forName(clsName).getConstructor(Context.class);
                    obj = (SystemUI) constructor.newInstance(this);
                }
                mServices[i] = obj;
            } catch (ClassNotFoundException
                    | NoSuchMethodException
                    | IllegalAccessException
                    | InstantiationException
                    | InvocationTargetException ex) {
                throw new RuntimeException(ex);
            }

            if (DEBUG) Log.d(TAG, "running: " + mServices[i]);
            // 調(diào)用各組件實(shí)現(xiàn)的start()方法
            mServices[i].start();
            ...
        }
        ...
    }
}

其中 mComponentHelper 在上一節(jié)中有提到骨田,下面講解一下它的注入過(guò)程。
在 SystemUIRootComponent 中定義了 ContextComponentHelper 單例對(duì)象的獲取方法声怔,

@Singleton
@Component(modules = {
        ...
        SystemUIModule.class,
        SystemUIDefaultModule.class})
public interface SystemUIRootComponent {
    ...
    @Singleton
    ContextComponentHelper getContextComponentHelper();
    ...
}

上文dagger2注解基礎(chǔ)里有提到盛撑,無(wú)參有返回值的方法,實(shí)例從定義的Module中查找捧搞,這里在 SystemUIModule 里可以找到,實(shí)際注入的是 ContextComponentResolver 對(duì)象狮荔,它是 ContextComponentHelper 的實(shí)現(xiàn)類:

@Module(includes = {
            ...
        },
        subcomponents = {StatusBarComponent.class,
                NotificationRowComponent.class,
                ExpandableNotificationRowComponent.class})
public abstract class SystemUIModule {
    ...
    @Binds
    public abstract ContextComponentHelper bindComponentHelper(
            ContextComponentResolver componentHelper);
    ...
}

由于該方法標(biāo)了abstract并沒(méi)有進(jìn)行實(shí)現(xiàn)胎撇,所以實(shí)例對(duì)象會(huì)通過(guò) ContextComponentResolver 里面帶 @Inject 標(biāo)簽的構(gòu)造方法來(lái)生成。

@Singleton
public class ContextComponentResolver implements ContextComponentHelper {
    private final Map<Class<?>, Provider<Activity>> mActivityCreators;
    private final Map<Class<?>, Provider<Service>> mServiceCreators;
    private final Map<Class<?>, Provider<SystemUI>> mSystemUICreators;
    private final Map<Class<?>, Provider<RecentsImplementation>> mRecentsCreators;
    private final Map<Class<?>, Provider<BroadcastReceiver>> mBroadcastReceiverCreators;

    @Inject
    ContextComponentResolver(Map<Class<?>, Provider<Activity>> activityCreators,
            Map<Class<?>, Provider<Service>> serviceCreators,
            Map<Class<?>, Provider<SystemUI>> systemUICreators,
            Map<Class<?>, Provider<RecentsImplementation>> recentsCreators,
            Map<Class<?>, Provider<BroadcastReceiver>> broadcastReceiverCreators) {
        mActivityCreators = activityCreators;
        mServiceCreators = serviceCreators;
        mSystemUICreators = systemUICreators;
        mRecentsCreators = recentsCreators;
        mBroadcastReceiverCreators = broadcastReceiverCreators;
    }
    ...

    /**
     * Looks up the SystemUI class name to see if Dagger has an instance of it.
     */
    @Override
    public SystemUI resolveSystemUI(String className) {
        return resolve(className, mSystemUICreators);
    }

    private <T> T resolve(String className, Map<Class<?>, Provider<T>> creators) {
        try {
            Class<?> clazz = Class.forName(className);
            Provider<T> provider = creators.get(clazz);
            return provider == null ? null : provider.get();
        } catch (ClassNotFoundException e) {
            return null;
        }
    }
}

這里的構(gòu)造方法由于帶了 @Inject殖氏,所以它的參數(shù)Map都會(huì)一起注入進(jìn)去晚树,那這些Map又是哪里來(lái)的呢,這里提一下dagger2的 MultiBindings雅采。

首先在 Module 中多次定義一系列返回值類型相同的方法爵憎,這里以 SystemUIBinder 為例慨亲,如果需要的類型是Map,那么就使用 @IntoMap 和 對(duì)應(yīng)key的 @MapKey 的實(shí)現(xiàn) @ClassKey宝鼓,@IntoMap 表示這些方法的返回值對(duì)象都要裝入同一個(gè)Map集合中刑棵,@ClassKey 表示Map的key為class。
然后還必須加上 @Provides 標(biāo)簽愚铡,如果是接口或抽象類則用 @Binds蛉签。這樣聲明下來(lái),dagger2 會(huì)自動(dòng)為其注入 Map<Class<?>, Provider<SystemUI>>沥寥,即把上面的 systemUICreators 給注入進(jìn)去了碍舍。

/**
 * SystemUI objects that are injectable should go here.
 */
@Module(includes = {RecentsModule.class, StatusBarModule.class, BubbleModule.class,
        KeyguardModule.class})
public abstract class SystemUIBinder {
    /** Inject into AuthController. */
    @Binds
    @IntoMap
    @ClassKey(AuthController.class)
    public abstract SystemUI bindAuthController(AuthController service);

    /** Inject into Divider. */
    @Binds
    @IntoMap
    @ClassKey(Divider.class)
    public abstract SystemUI bindDivider(Divider sysui);
    ...

    /** Inject into StatusBar. */
    @Binds
    @IntoMap
    @ClassKey(StatusBar.class)
    public abstract SystemUI bindsStatusBar(StatusBar sysui);
    ...
}

以 bindsStatusBar 為例,參數(shù) StatusBar 的實(shí)例又是由 StatusBarPhoneModule 提供的

/**
 * Dagger Module providing {@link StatusBar}.
 */
@Module(includes = {StatusBarPhoneDependenciesModule.class})
public interface StatusBarPhoneModule {
    /**
     * Provides our instance of StatusBar which is considered optional.
     */
    @Provides
    @Singleton
    static StatusBar provideStatusBar(
            Context context,
            NotificationsController notificationsController,
            LightBarController lightBarController,
            AutoHideController autoHideController,
            KeyguardUpdateMonitor keyguardUpdateMonitor,
            StatusBarIconController statusBarIconController,
            ...) {
        return new StatusBar(
                context,
                notificationsController,
                lightBarController,
                autoHideController,
                keyguardUpdateMonitor,
                statusBarIconController,
                ...);
    }
}

new StatusBar 對(duì)象所用到的參數(shù)邑雅,有些是通過(guò)內(nèi)部自身帶 @Inject 標(biāo)簽的構(gòu)造方法注入片橡,有些則是又再通過(guò)其他 Module 提供,這里就不再往下繼續(xù)跟蹤了淮野。

到此捧书,config_systemUIServiceComponents 里面定義的組件的實(shí)例對(duì)象注入過(guò)程就結(jié)束了。

總結(jié)

由于 SystemUI 模塊內(nèi)大部分結(jié)構(gòu)都已經(jīng)用上了 Dagger2 框架录煤,本文旨在通過(guò)對(duì) Dagger2 框架進(jìn)行一些基礎(chǔ)概念的總結(jié)鳄厌,結(jié)合 SystemUI 部分的源碼來(lái)了解其工作原理,這樣在后續(xù)解讀代碼以及添加需求功能的時(shí)候可以用上妈踊。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末了嚎,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子廊营,更是在濱河造成了極大的恐慌歪泳,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,599評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件露筒,死亡現(xiàn)場(chǎng)離奇詭異呐伞,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)慎式,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,629評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門伶氢,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人瘪吏,你說(shuō)我怎么就攤上這事癣防。” “怎么了掌眠?”我有些...
    開封第一講書人閱讀 158,084評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵蕾盯,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我蓝丙,道長(zhǎng)级遭,這世上最難降的妖魔是什么望拖? 我笑而不...
    開封第一講書人閱讀 56,708評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮挫鸽,結(jié)果婚禮上说敏,老公的妹妹穿的比我還像新娘。我一直安慰自己掠兄,他們只是感情好像云,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,813評(píng)論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著蚂夕,像睡著了一般迅诬。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上婿牍,一...
    開封第一講書人閱讀 50,021評(píng)論 1 291
  • 那天侈贷,我揣著相機(jī)與錄音,去河邊找鬼等脂。 笑死俏蛮,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的上遥。 我是一名探鬼主播搏屑,決...
    沈念sama閱讀 39,120評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼粉楚!你這毒婦竟也來(lái)了辣恋?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,866評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤模软,失蹤者是張志新(化名)和其女友劉穎伟骨,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體燃异,經(jīng)...
    沈念sama閱讀 44,308評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡携狭,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,633評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了回俐。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片逛腿。...
    茶點(diǎn)故事閱讀 38,768評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖仅颇,靈堂內(nèi)的尸體忽然破棺而出单默,到底是詐尸還是另有隱情,我是刑警寧澤灵莲,帶...
    沈念sama閱讀 34,461評(píng)論 4 333
  • 正文 年R本政府宣布,位于F島的核電站殴俱,受9級(jí)特大地震影響政冻,放射性物質(zhì)發(fā)生泄漏枚抵。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,094評(píng)論 3 317
  • 文/蒙蒙 一明场、第九天 我趴在偏房一處隱蔽的房頂上張望汽摹。 院中可真熱鬧,春花似錦苦锨、人聲如沸逼泣。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,850評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)拉庶。三九已至,卻和暖如春秃励,著一層夾襖步出監(jiān)牢的瞬間氏仗,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,082評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工夺鲜, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留皆尔,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,571評(píng)論 2 362
  • 正文 我出身青樓币励,卻偏偏與公主長(zhǎng)得像慷蠕,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子食呻,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,666評(píng)論 2 350

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