RxJava2外傳Ⅰ:官方README翻譯

有些翻譯仍不準(zhǔn)確,會(huì)持續(xù)改進(jìn)。

術(shù)語

上游,下游

RxJava中的數(shù)據(jù)流包括一個(gè)數(shù)據(jù)源、0個(gè)或多個(gè)中間步驟、一個(gè)數(shù)據(jù)消費(fèi)者或組合子步驟(其中的步驟負(fù)責(zé)以某種方式使用數(shù)據(jù)流):

source.operator1().operator2().operator3().subscribe(consumer);

source.flatMap(value -> source.operator1().operator2().operator3());

如果我們想象自己站在operator2上,向左看向source,叫做上游;向右看向subscriber/consumer,叫做下游。當(dāng)像下面這樣每個(gè)元素單獨(dú)寫一行時(shí)看的更加明顯:

source
  .operator1()
  .operator2()
  .operator3()
  .subscribe(consumer)

運(yùn)動(dòng)的對(duì)象

在RxJava的文檔中, emission, emits, item, event, signal, data and message都是近義詞,都表示沿著數(shù)據(jù)流移動(dòng)的對(duì)象。

背壓

當(dāng)數(shù)據(jù)流通過異步步驟運(yùn)行時(shí),每個(gè)步驟可能以不同的速度執(zhí)行不同的事情。為了避免那些由于臨時(shí)緩沖或需要跳過/刪除數(shù)據(jù)而導(dǎo)致內(nèi)存使用量增加的步驟被淹沒,因此應(yīng)用了所謂的背壓,這是一種流控制形式,從而步驟可以表示準(zhǔn)備處理多少項(xiàng)數(shù)據(jù)。使用背壓允許當(dāng)前步驟在通常無法知道上游將發(fā)送多少項(xiàng)數(shù)據(jù)的情況下限制數(shù)據(jù)流的內(nèi)存使用。

在RxJava中,Flowable類被設(shè)計(jì)成支持背壓,Observable類專用于非背壓操作。Single, Maybe and Completable也不支持背壓。

裝配時(shí)間Assembly time

通過應(yīng)用各式各樣的中間操作符來準(zhǔn)備數(shù)據(jù)流,發(fā)生在裝配時(shí)間。

Flowable<Integer> flow = Flowable.range(1, 5)
.map(v -> v * v)
.filter(v -> v % 3 == 0)
;

在當(dāng)前點(diǎn)上,數(shù)據(jù)還沒有流動(dòng),也沒有發(fā)生副作用。

訂閱時(shí)間 Subscription time

這是在內(nèi)部建立處理步驟鏈的流上調(diào)用subscribe()時(shí)的臨時(shí)狀態(tài):

flow.subscribe(System.out::println)

這時(shí)會(huì)觸發(fā)訂閱副作用。有些源在這種狀態(tài)下會(huì)立即阻塞或開始發(fā)送數(shù)據(jù)項(xiàng)。

運(yùn)行時(shí) Runtime

這是數(shù)據(jù)流主動(dòng)發(fā)出數(shù)據(jù)項(xiàng)、錯(cuò)誤或完成信號(hào)時(shí)的狀態(tài):

Observable.create(emitter -> {
     while (!emitter.isDisposed()) {
         long time = System.currentTimeMillis();
         emitter.onNext(time);
         if (time % 2 != 0) {
             emitter.onError(new IllegalStateException("Odd millisecond!"));
             break;
         }
     }
})
.subscribe(System.out::println, Throwable::printStackTrace);

實(shí)際上,這是上面給定示例的主體執(zhí)行的時(shí)候。

簡單的后臺(tái)計(jì)算

RxJava的一個(gè)常見用例是在后臺(tái)線程上運(yùn)行一些計(jì)算、網(wǎng)絡(luò)請(qǐng)求,并在UI線程上顯示結(jié)果(或錯(cuò)誤)

import io.reactivex.schedulers.Schedulers;

Flowable.fromCallable(() -> {
    Thread.sleep(1000); //  imitate expensive computation
    return "Done";
})
  .subscribeOn(Schedulers.io())
  .observeOn(Schedulers.single())
  .subscribe(System.out::println, Throwable::printStackTrace);

Thread.sleep(2000); // <--- wait for the flow to finish

這種鏈?zhǔn)秸{(diào)用方法的形式稱為流式API,類似于builder模式。然而,RxJava的響應(yīng)類型是不可變的;每個(gè)方法調(diào)用都返回一個(gè)添加了行為的新的Flowable。我們可以把上面的例子改寫為下面這樣:

Flowable<String> source = Flowable.fromCallable(() -> {
    Thread.sleep(1000); //  imitate expensive computation
    return "Done";
});

Flowable<String> runBackground = source.subscribeOn(Schedulers.io());

Flowable<String> showForeground = runBackground.observeOn(Schedulers.single());

showForeground.subscribe(System.out::println, Throwable::printStackTrace);

Thread.sleep(2000);

通常,您可以通過subscribeOn將計(jì)算或阻塞IO移動(dòng)到其他線程。一旦數(shù)據(jù)準(zhǔn)備好,您就可以通過observeOn確保它們?cè)谇芭_(tái)或GUI線程上得到處理。

調(diào)度者Schedulers

RxJava操作符不直接使用Thread或ExecutorServices,而是使用所謂的調(diào)度器Scheduler,這些調(diào)度器將并發(fā)源抽象到統(tǒng)一API后面。RxJava 2提供了幾個(gè)可通過scheduler類訪問的標(biāo)準(zhǔn)調(diào)度器。

  • Schedulers.computation(): 在后臺(tái)的固定數(shù)量的專用線程上運(yùn)行計(jì)算密集型工作。大多數(shù)異步操作符將此作為其默認(rèn)調(diào)度程序。
  • Schedulers.io(): 在一組動(dòng)態(tài)變化的線程上運(yùn)行類似I/ o或阻塞操作。
  • Schedulers.single(): 以順序和FIFO方式在單個(gè)線程上運(yùn)行工作。
  • Schedulers.trampoline(): 在參與的線程中以順序和FIFO方式運(yùn)行工作,通常用于測(cè)試目的。

這些在所有JVM平臺(tái)上都可用,但是在某些特定的平臺(tái)上,例如android,有它們特有的調(diào)度器:AndroidSchedulers.mainThread(), SwingScheduler.instance() or JavaFXSchedulers.gui().

此外,還可以通過Scheduler .from(Executor)將現(xiàn)有的Executor(及其子類型,如ExecutorService)包裝到調(diào)度器Schedulers中。例如,可以使用它來擁有更大但仍然固定的線程池(不同于分別使用compute()和io())。

上面例子結(jié)尾處的Thread.sleep(2000);是有意為之。在RxJava中,默認(rèn)調(diào)度程序在守護(hù)線程上運(yùn)行,這意味著一旦Java主線程退出,它們就會(huì)全部停止,后臺(tái)計(jì)算可能永遠(yuǎn)不會(huì)發(fā)生。在這個(gè)示例場(chǎng)景中,休眠一段時(shí)間可以讓您看到控制臺(tái)上數(shù)據(jù)流流的輸出。

流中的并發(fā)

RxJava中的流本質(zhì)上是順序的,它們被劃分為可以彼此并發(fā)運(yùn)行的處理階段

Flowable.range(1, 10)
  .observeOn(Schedulers.computation())
  .map(v -> v * v)
  .blockingSubscribe(System.out::println);

這個(gè)示例流將computation調(diào)度器上的數(shù)字從1平方到10,并在主線程(更準(zhǔn)確地說,是blockingSubscribe的調(diào)用線程)上處理結(jié)果。然而lambda表達(dá)式v -> v * v并不是并行運(yùn)行的。它在同一個(gè)計(jì)算線程上依次接收1到10的值。

并行處理

并行處理數(shù)字1到10稍微復(fù)雜一些:

Flowable.range(1, 10)
  .flatMap(v ->
      Flowable.just(v)
        .subscribeOn(Schedulers.computation())
        .map(w -> w * w)
  )
  .blockingSubscribe(System.out::println);

實(shí)際上,RxJava中的并行性意味著運(yùn)行獨(dú)立的流并將它們的結(jié)果合并回單個(gè)流。操作符flatMap首先將1到10的每個(gè)數(shù)字映射到它自己的Flowable中,運(yùn)行它們并合并計(jì)算的平方。

但是,請(qǐng)注意,flatMap不保證任何順序,來自內(nèi)部流的最終結(jié)果可能是交錯(cuò)的。有其他的操作符可供選擇:

  • concatMap 它每次映射并運(yùn)行一個(gè)內(nèi)部流
  • concatMapEager 它“同時(shí)”運(yùn)行所有內(nèi)部流,但是輸出流將按照這些內(nèi)部流創(chuàng)建的順序輸出。

或者,Flowable.parallel()操作符和ParallelFlowable類型可以幫助實(shí)現(xiàn)相同的并行處理模式:

Flowable.range(1, 10)
  .parallel()
  .runOn(Schedulers.computation())
  .map(v -> v * v)
  .sequential()
  .blockingSubscribe(System.out::println);

依賴子流

flatMap是一個(gè)強(qiáng)大的操作符,在很多情況下都有幫助。例如,給定一個(gè)返回Flowable的服務(wù),我們希望使用第一個(gè)服務(wù)發(fā)出的值調(diào)用另一個(gè)服務(wù):

Flowable<Inventory> inventorySource = warehouse.getInventoryAsync();

inventorySource.flatMap(inventoryItem ->
    erp.getDemandAsync(inventoryItem.getId())
    .map(demand 
        -> System.out.println("Item " + inventoryItem.getName() + " has demand " + demand));
  )
  .subscribe();

延續(xù)Continuations

有時(shí),當(dāng)一個(gè)項(xiàng)變得可用時(shí),人們希望依賴它執(zhí)行一些計(jì)算。這有時(shí)稱為延續(xù),根據(jù)將要發(fā)生的情況和涉及的類型,可能需要不同的操作符來實(shí)現(xiàn)。

依賴

最典型的場(chǎng)景是給定一個(gè)值,調(diào)用另一個(gè)服務(wù),等待并使用其結(jié)果繼續(xù):

service.apiCall()
.flatMap(value -> service.anotherApiCall(value))
.flatMap(next -> service.finalCall(next))

通常情況下,后面的序列也需要來自前面映射的值。這可以通過將外部flatMap 移動(dòng)到上一個(gè)flatMap的內(nèi)部來實(shí)現(xiàn),例如:

service.apiCall()
.flatMap(value ->
    service.anotherApiCall(value)
    .flatMap(next -> service.finalCallBoth(value, next))
)

在這里,由于lambda變量捕獲,原始value將在內(nèi)部flatMap中可用。

非依賴

在其他場(chǎng)景中,第一個(gè)源/數(shù)據(jù)流的結(jié)果是不相關(guān)的,我們希望使用獨(dú)立的另一個(gè)源繼續(xù)。flatMap 也可以勝任:

Observable continued = sourceObservable.flatMapSingle(ignored -> someSingleSource)
continued.map(v -> v.toString())
  .subscribe(System.out::println, Throwable::printStackTrace);

然而,在這種情況下,延續(xù)保持Observable ,而不是可能更合適的Single.(這是可以理解的,因?yàn)閺膄latMapSingle的角度來看,sourceObservable是一個(gè)多值源,因此映射也可能導(dǎo)致多個(gè)值)

雖然通常有一種方法更有表現(xiàn)力(也更低的開銷),即使用Completable作為中介,然后使用它的操作符andThen來繼續(xù):

sourceObservable
  .ignoreElements()           // returns Completable
  .andThen(someSingleSource)
  .map(v -> v.toString())

sourceObservable和someSingleSource之間唯一的依賴關(guān)系是前者應(yīng)該正常完成,以便使用后者。

延遲依賴

有時(shí),前一個(gè)序列和新序列之間存在隱式的數(shù)據(jù)依賴關(guān)系,由于某些原因,該依賴關(guān)系沒有通過“常規(guī)通道”流動(dòng)。有人會(huì)傾向于這樣寫延續(xù):

AtomicInteger count = new AtomicInteger();

Observable.range(1, 10)
  .doOnNext(ignored -> count.incrementAndGet())
  .ignoreElements()
  .andThen(Single.just(count.get()))
  .subscribe(System.out::println);

不幸的是,這輸出0,因?yàn)?code>Single.just(count.get())是在數(shù)據(jù)流尚未運(yùn)行的assembly time期間計(jì)算的。我們需要一些東西,來推遲Single來源的計(jì)算,直到主要來源完成的運(yùn)行時(shí):

AtomicInteger count = new AtomicInteger();

Observable.range(1, 10)
  .doOnNext(ignored -> count.incrementAndGet())
  .ignoreElements()
  .andThen(Single.defer(() -> Single.just(count.get())))
  .subscribe(System.out::println);

或者

AtomicInteger count = new AtomicInteger();

Observable.range(1, 10)
  .doOnNext(ignored -> count.incrementAndGet())
  .ignoreElements()
  .andThen(Single.fromCallable(() -> count.get()))
  .subscribe(System.out::println);

類型轉(zhuǎn)換

有時(shí),源或服務(wù)返回的類型與應(yīng)該使用它的流不同。 例如,在上面的inventory例子中,getDemandAsync 可能返回一個(gè)Single<DemandRecord>. 如果代碼示例保持不變,則會(huì)導(dǎo)致編譯時(shí)錯(cuò)誤(但是,通常會(huì)出現(xiàn)關(guān)于缺少重載的誤導(dǎo)性錯(cuò)誤消息)。

在這種情況下,通常有兩種方式來修復(fù)轉(zhuǎn)換: 1) 轉(zhuǎn)換為所需類型 2) 查找并使用支持不同類型的特定操作符的重載。

轉(zhuǎn)換為所需類型

每個(gè)響應(yīng)基類都具有可以執(zhí)行此類轉(zhuǎn)換(包括協(xié)議轉(zhuǎn)換)的操作符,以匹配其他類型。 下面的矩陣顯示了可用的轉(zhuǎn)換選項(xiàng):

Flowable Observable Single Maybe Completable
Flowable toObservable first, firstOrError, single, singleOrError, last, lastOrError1 firstElement, singleElement, lastElement ignoreElements
Observable toFlowable2 first, firstOrError, single, singleOrError, last, lastOrError1 firstElement, singleElement, lastElement ignoreElements
Single toFlowable3 toObservable toMaybe ignoreElement
Maybe toFlowable3 toObservable toSingle ignoreElement
Completable toFlowable toObservable toSingle toMaybe

1: 當(dāng)將一個(gè)多值源轉(zhuǎn)換為一個(gè)單值源時(shí),你應(yīng)該決定使用多個(gè)源中的哪一個(gè)值作為結(jié)果。

2: 把一個(gè)Observable變成Flowable 需要一個(gè)額外的決定: 如何處理Observable源中潛在的無約束流? 通過BackpressureStrategy參數(shù)或標(biāo)準(zhǔn)的Flowable操作符(如onBackpressureBuffer、onBackpressureDrop、onbackpressurerelatest,這些操作符還允許進(jìn)一步定制反壓力行為。)可以使用幾種策略(如緩沖、刪除、保持最新狀態(tài))來處理。

3: 當(dāng)只有(最多)一個(gè)源數(shù)據(jù)項(xiàng)時(shí),背壓沒有問題,因?yàn)樗梢砸恢贝鎯?chǔ)到下游準(zhǔn)備使用為止。

使用具有所需類型的重載

許多常用的操作符都有可以處理其他類型的重載。它們通常以目標(biāo)類型的后綴命名:

Operator Overloads
flatMap flatMapSingle, flatMapMaybe, flatMapCompletable, flatMapIterable
concatMap concatMapSingle, concatMapMaybe, concatMapCompletable, concatMapIterable
switchMap switchMapSingle, switchMapMaybe, switchMapCompletable

這些操作符具有后綴而不是簡單地使用具有不同簽名的相同名稱的原因是類型擦除。 Java認(rèn)為像operator(Function<T, Single<R>>)operator(Function<T, Maybe<R>>)這樣的簽名是相同的(與c#不同),并且由于擦除的原因,這兩operator最終會(huì)成為具有相同簽名的重復(fù)方法。

操作符命名約定

命名在編程中是最困難的事情之一,因?yàn)槊蟛婚L、具有表現(xiàn)力、容易捕捉和容易記憶。 不幸的是,目標(biāo)語言(和已經(jīng)存在的約定)在這方面可能不會(huì)提供太多的幫助(不可用的關(guān)鍵字、類型擦除、類型歧義等等)。

不可用關(guān)鍵字

在原始的Rx.NET中,發(fā)出單個(gè)項(xiàng)然后完成的運(yùn)算符稱為 Return(T).由于Java約定是以小寫字母開頭的方法名,因此它應(yīng)該是return(T),但這是Java中的關(guān)鍵字,因此不可用。 因此,RxJava選擇將這個(gè)操作符命名為 just(T). 操作符Switch也存在同樣的限制,必須將其命名為 switchOnNext.另一個(gè)例子是Catch,它被命名為 onErrorResumeNext.

類型消除

許多期望用戶提供返回響應(yīng)類型的函數(shù)的操作符無法重載,因?yàn)楹瘮?shù)Function<T, X>周圍的類型擦除將這些方法簽名轉(zhuǎn)換為重復(fù)。RxJava通過添加類型后綴來命名這些操作符:

Flowable<R> flatMap(Function<? super T, ? extends Publisher<? extends R>> mapper)

Flowable<R> flatMapMaybe(Function<? super T, ? extends MaybeSource<? extends R>> mapper)

類型歧義

盡管某些操作符在類型擦除方面沒有問題,但是是在使用Java 8和lambdas的情況下,它們的簽名可能會(huì)變得含糊不清。例如,concatWith以各種其他反應(yīng)性基類型作為參數(shù)(為了在底層實(shí)現(xiàn)中提供方便和性能優(yōu)勢(shì)),會(huì)出現(xiàn)一些重載:

Flowable<T> concatWith(Publisher<? extends T> other);

Flowable<T> concatWith(SingleSource<? extends T> other);

PublisherSingleSource都以函數(shù)接口的形式出現(xiàn)(帶有一個(gè)抽象方法的類型),并可能鼓勵(lì)用戶嘗試提供lambda表達(dá)式:

someSource.concatWith(s -> Single.just(2))
.subscribe(System.out::println, Throwable::printStackTrace);

不幸的是,這種方法不起作用,示例根本不打印2。 實(shí)際上,從2.1.10版本開始,它甚至不能編譯,因?yàn)橹辽儆?個(gè)concatWith重載存在,編譯器發(fā)現(xiàn)上面的代碼不明確。

在這種情況下,用戶可能希望延遲一些計(jì)算,直到someSource完成,因此正確的明確操作符應(yīng)該是defer:

someSource.concatWith(Single.defer(() -> Single.just(2)))
.subscribe(System.out::println, Throwable::printStackTrace);

有時(shí),添加后綴是為了避免邏輯歧義,這些歧義可能會(huì)編譯,但會(huì)在流中產(chǎn)生錯(cuò)誤的類型:

Flowable<T> merge(Publisher<? extends Publisher<? extends T>> sources);

Flowable<T> mergeArray(Publisher<? extends T>... sources);

當(dāng)函數(shù)接口類型涉及到類型參數(shù)T時(shí),這也會(huì)變得含糊不清。

錯(cuò)誤處理

數(shù)據(jù)流可能失敗,此時(shí)錯(cuò)誤被發(fā)送到使用者。 但是,有時(shí)多個(gè)源可能會(huì)失敗,這時(shí)可以選擇是否等待所有源完成或失敗。為了表示這種機(jī)會(huì),許多操作符的名稱都添加了DelayError單詞的后綴(而其他操作符的重載中則添加了delayErrordelayErrors boolean標(biāo)志):

Flowable<T> concat(Publisher<? extends Publisher<? extends T>> sources);

Flowable<T> concatDelayError(Publisher<? extends Publisher<? extends T>> sources);

當(dāng)然,各種各樣的后綴可能出現(xiàn)在一起:

Flowable<T> concatArrayEagerDelayError(Publisher<? extends T>... sources);

基類vs基類型

由于基類上的靜態(tài)方法和實(shí)例方法的數(shù)量太多,因此可以認(rèn)為基類很重。 RxJava 2的設(shè)計(jì)深受響應(yīng)流規(guī)范的影響,因此,該庫為每種響應(yīng)類型提供了一個(gè)類和一個(gè)接口:

Type Class Interface Consumer
0..N backpressured Flowable Publisher1 Subscriber
0..N unbounded Observable ObservableSource2 Observer
1 element or error Single SingleSource SingleObserver
0..1 element or error Maybe MaybeSource MaybeObserver
0 element or error Completable CompletableSource CompletableObserver

1The org.reactivestreams.Publisher是外部響應(yīng)流庫的一部分。它是通過受響應(yīng)流規(guī)范控制的標(biāo)準(zhǔn)化機(jī)制與其他響應(yīng)庫進(jìn)行交互的主要類型。

2接口的命名約定是將Source追加到半傳統(tǒng)的類名中。 因?yàn)?code>Publisher是由響應(yīng)流庫提供的,所以沒有FlowableSource(而且子類型對(duì)互操作也沒有幫助)。 然而,這些接口并不是響應(yīng)流規(guī)范意義上的標(biāo)準(zhǔn)接口,而且目前僅針對(duì)RxJava。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,362評(píng)論 6 537
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,013評(píng)論 3 423
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,346評(píng)論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,421評(píng)論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,146評(píng)論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,534評(píng)論 1 325
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,585評(píng)論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,767評(píng)論 0 289
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,318評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,074評(píng)論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,258評(píng)論 1 371
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,828評(píng)論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,486評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,916評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,156評(píng)論 1 290
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,993評(píng)論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,234評(píng)論 2 375

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