Kotlin核心基礎(chǔ)之高階函數(shù)史汗,協(xié)程基本用法

怎么理解kotlin的掛起函數(shù)?

Kotlin協(xié)程進(jìn)階使用
Kotlin協(xié)程在工作中有用過(guò)嗎? (qq.com)

1.kotlin和java編譯后都是java字節(jié)碼早处,相對(duì)于java有啥優(yōu)勢(shì)和劣勢(shì)捷雕?

(1).kotlin優(yōu)勢(shì)

  • 代碼簡(jiǎn)潔椒丧,開發(fā)效率更高
    不用使用findViewById,支減少冗余代碼救巷,支持空安全壶熏,擴(kuò)展函數(shù),屬性浦译,高階函數(shù)和lambda表達(dá)式棒假,內(nèi)聯(lián)函數(shù)。

  • 內(nèi)存消耗更少
    由于空安全特性和內(nèi)聯(lián)函數(shù)優(yōu)化精盅,它能夠生成更高效的字節(jié)碼帽哑,從而減少內(nèi)存的使用。kotlin協(xié)程提供了一中輕量級(jí)的并發(fā)處理方式渤弛,可以進(jìn)一步降低內(nèi)存的占用祝拯。

  • kotlin是未來(lái)Android開發(fā)主流的語(yǔ)言,一些Android的新特性,新組件都會(huì)優(yōu)先支持kotlin版本佳头。

(2).kotlin劣勢(shì)
kotlin編譯速度相對(duì)java較慢鹰贵,因?yàn)樗枰M(jìn)行額外的類型檢查(空安全),和代碼轉(zhuǎn)換(kotlin-java-java字節(jié)碼康嘉,復(fù)雜碉输,耗性能)

備注:Kotlin與Java在運(yùn)行時(shí)性能方面基本相當(dāng),由于kotlin支持inline函數(shù)亭珍,lambda表達(dá)式敷钾,在某些情況下性能還要由于java.

2.Kotlin內(nèi)置的高階函數(shù)run的原理是什么,與let函數(shù)有啥區(qū)別肄梨?

(1).inline :表示這是一個(gè)內(nèi)聯(lián)函數(shù)阻荒,將函數(shù)代碼直接插入調(diào)用處,避免了調(diào)用普通方法時(shí)众羡,棧幀的創(chuàng)建侨赡,銷毀所帶來(lái)的開銷。
(2).<T,R> T.run :T代表要為T擴(kuò)展出一個(gè)名為run的函數(shù)粱侣,R表示lambda表達(dá)式最后一行返回的類型羊壹。
(3).block:T.()->R:
block:表示lambda的名稱
T.():表示輸入?yún)?shù)是T本身,讓lambda表達(dá)式持有了this表示(T)調(diào)用者本身
R:表示lambda最后一行返回的類型.
(T) :表示輸入?yún)?shù)是T本身齐婴,讓lambda表達(dá)式持有了it表示(T)調(diào)用者本身

public inline fun<T,R> T.let(block:(T)->R){
    return block(this)
}

public inline fun<T,R> T.run(block:T.()->R):R{
      return block()
}
//with不是泛型的擴(kuò)展方法油猫,而是全局方法
public inline fun <T, R> with(receiver: T, block: T.() -> R): R {
    return receiver.block()
}

public inline fun <T> T.also(block: (T) -> Unit): T {
    block(this)
    return this
}
public inline fun <T> T.apply(block: T.() -> Unit): T {
    block()
    return this
}



fun main(){
   var  result1="778".run{  
         true
        length
    }
   println(result1)   //3
  var result2="778".let{
         999
         "$it" //778
  }
}

為啥所有的類型都可以使用run或者let,那是因?yàn)楦唠A函數(shù)let和run是對(duì)泛型進(jìn)行擴(kuò)展柠偶,意味著所有類型都等于泛型情妖,所以任何地方都可以使用.run和let的區(qū)別在于lambda表達(dá)式一個(gè)持有this表示調(diào)用者本身,一個(gè)持有it表示調(diào)用者本身嚣州。

public inline <T> T.apply(block:T.()->unit):T
public inline <T> T.also(block:(T)->unit):T
public int <T,R> with(receiver:T,block:T.()->R):R

3.kotlin語(yǔ)言泛型的形變是什么鲫售?【PECS原則 extends out || super in】

  • 不變:指的是此泛型既可以是消費(fèi)者共螺,可以是生產(chǎn)者该肴,沒(méi)有任何繼承相關(guān)的概念.
class Student<T> {}   
  • 協(xié)變 : 指的是此泛型只能是生產(chǎn)者 ,泛型類型只能是T或者T的子類藐不,只能get數(shù)據(jù)匀哄,無(wú)法add數(shù)據(jù).
ArrayList<out T>            
  • 逆變:指的是此泛型只能是消費(fèi)者,泛型類型只能是T類型雏蛮,或者T的父類涎嚼,只能add數(shù)據(jù),無(wú)法get【如果get數(shù)據(jù)挑秉,數(shù)據(jù)類型只能是Object】
ArrayList<in T>     

4.協(xié)程的基本使用.

(1).啟動(dòng)協(xié)程的幾種方式.
  • launch{} CoroutineScope接口的擴(kuò)展方法法梯,啟動(dòng)一個(gè)攜程,不阻塞當(dāng)前線程,返回一個(gè)Job對(duì)象協(xié)程.
public fun CoroutineScope.launch(
     context:CoroutineScope=EmptyCoroutineContext,
     start:CoroutineStart = CoroutineStart.DEFAULT,
     block:suspend CoroutineScope.()->Unit
):Job {  //Job是返回值立哑, {} 是launch的方法體實(shí)現(xiàn) 【不要搞混淆了】
 //launch方法體實(shí)現(xiàn)夜惭,返回Job對(duì)象
      val newcontenxt=newCoroutineContext(context)
     val coroutine=if(start.isLazy){
          LazyStandaloneCoroutine(newContext,block);//實(shí)現(xiàn)了job接口
     }else{
        StandaloneCoroutine(newContext,active=true)  //實(shí)現(xiàn)了job接口
    }
     coroutine.start(start,coroutine,block)  //啟動(dòng)job
    return  coroutine;//返回實(shí)現(xiàn)了Job接口的協(xié)程對(duì)象
}

Job.cancel()可以用來(lái)取消協(xié)程铛绰,控制協(xié)程的生命周期.

  • async{} CoroutienScope接口的擴(kuò)展方法诈茧,啟動(dòng)一個(gè)協(xié)程,不阻塞當(dāng)前線程捂掰,返回一個(gè)Deferred<T>類敢会,可以通過(guò)wait獲取T對(duì)象.
public fun <T> CoroutineScope.async(
    context: CoroutineContext = EmptyCoroutineContext,
    start: CoroutineStart = CoroutineStart.DEFAULT,
    block: suspend CoroutineScope.() -> T
): Deferred<T> {
    val newContext = newCoroutineContext(context)
    val coroutine= if (start.isLazy){
        LazyDeferredCoroutine<T>(newContext, block)  //實(shí)現(xiàn)了Deferred接口
    } else{
       DeferredCoroutine<T>(newContext, active = true) //實(shí)現(xiàn)了Deferred接口
    }
    coroutine.start(start, coroutine, block)   //啟動(dòng)協(xié)程
    return coroutine //返回實(shí)現(xiàn)了Deferred接口的協(xié)程對(duì)象
}
  • runBlocking{} 全局方法,創(chuàng)建并啟動(dòng)協(xié)程,返回值是lambda表達(dá)式block的最后一行的返回值.(Unit或者其他具體類型)
public fun <T> runBlocking(context: CoroutineContext = EmptyCoroutineContext, block: suspend CoroutineScope.() -> T): T {
    val currentThread = Thread.currentThread()
    val contextInterceptor = context[ContinuationInterceptor]
    val eventLoop: EventLoop?
    val newContext: CoroutineContext
    if (contextInterceptor == null) {
        eventLoop = ThreadLocalEventLoop.eventLoop
        newContext = GlobalScope.newCoroutineContext(context + eventLoop)
    } else {
        eventLoop = (contextInterceptor as? EventLoop)?.takeIf { it.shouldBeProcessedFromContext() }
            ?: ThreadLocalEventLoop.currentOrNull()
        newContext = GlobalScope.newCoroutineContext(context)
    }
    val coroutine = BlockingCoroutine<T>(newContext, currentThread, eventLoop)
    coroutine.start(CoroutineStart.DEFAULT, coroutine, block)
    return coroutine.joinBlocking()
}
//這一段代碼會(huì)阻塞主線程,直接導(dǎo)致黑屏这嚣。
runBlocking {
     delay(10000)
 }
//即使指定啟動(dòng)的協(xié)程運(yùn)行在IO線程鸥昏,也會(huì)阻塞主線程,導(dǎo)致黑屏
runBlocking(Dispatchers.IO) {
   delay(10000L)
}
//依然會(huì)阻塞主線程導(dǎo)致黑屏
 GlobalScope.launch(Dispatchers.Main){
       runBlocking {
                delay(10000)
        }

 }
//不會(huì)阻塞主線程
 GlobalScope.launch(Dispatchers.IO){
       runBlocking {
                delay(10000)
        }
 }
(2).withContext() suspend修飾姐帚,并不會(huì)啟動(dòng)協(xié)程互广,只能在suspend掛起方法或者協(xié)程中調(diào)用,用于切換線程卧土,并掛起協(xié)程惫皱。(暫停協(xié)程,但是執(zhí)行協(xié)程的線程可以繼續(xù)執(zhí)行其他任務(wù)尤莺,不會(huì)阻塞旅敷,等到協(xié)程恢復(fù),該線程可以繼續(xù)執(zhí)行)
public suspend fun <T> withContext(
    context: CoroutineContext,
    block: suspend CoroutineScope.() -> T
): T
   
 lifecycleScope.launch(Dispatchers.IO) {
            delay(1000)
            withContext(Dispatchers.Main){ //返回值是Unit 也就是void  //切換到主線程 颤霎,此時(shí)協(xié)程的IO線程可以去執(zhí)行其他任務(wù)
                println("Test001:withContext:${Thread.currentThread().name}")
            }
        }
(3).coroutineScope() suspend修飾媳谁,并不會(huì)啟動(dòng)協(xié)程,只能在suspend掛起方法或者協(xié)程中調(diào)用友酱,創(chuàng)建一個(gè)新的協(xié)程作用域【或者說(shuō)可以在已有的協(xié)程內(nèi)部創(chuàng)建一個(gè)新協(xié)程】
public suspend fun <R> coroutineScope(block: suspend CoroutineScope.() -> R): R =
    suspendCoroutineUninterceptedOrReturn { uCont ->
        val coroutine = ScopeCoroutine(uCont.context, uCont)
        coroutine.startUndispatchedOrReturn(coroutine, block)
 }


coroutineScope {  }  //報(bào)錯(cuò) 晴音,不能直接用,只能在協(xié)程里面使用

runBlocking { //非suspend全局方法缔杉,直接啟動(dòng)協(xié)程
   coroutineScope {  }   //正常使用锤躁,因?yàn)閞unBlocking創(chuàng)建了協(xié)程//創(chuàng)建一個(gè)新的協(xié)程作用域
  delay(1000L) 
}

(4).協(xié)程上下文,一般用調(diào)度器Dispatchers來(lái)切換線程或详,它是CoroutineContext接口的實(shí)現(xiàn)類.

  • Dispatchers.Main 協(xié)程代碼執(zhí)行在Android主線程
  • Dispatchers.Unconfined 不限制協(xié)程代碼執(zhí)行在哪個(gè)線程【主線程或者其他空閑線程】
  • Dispatcher.Default JVM共享線程池分配線程執(zhí)行協(xié)程代碼
  • Dispatcher.IO IO線程池分配線程執(zhí)行協(xié)程代碼

5.協(xié)程的掛起和阻塞

(1).suspend非阻塞式掛起函數(shù)
image.png
fun testCoroutineInActivity() {
       GlobalScope.launch(Dispatchers.Main) { //1.啟動(dòng)協(xié)程1
           println("Test001:執(zhí)行在協(xié)程中...")
           GlobalScope.launch (Dispatchers.IO){//2.啟動(dòng)協(xié)程2
               println("Test001:異步執(zhí)行result1")
               delay(1000)   
               println("Test001:result1:1234")
           }
           GlobalScope.launch(Dispatchers.IO) {//3.啟動(dòng)協(xié)程3
               println("Test001:異步執(zhí)行result2.")
               delay(1000) 
               println("Test001:result2:123456")
           }
           println("Test001:執(zhí)行完畢...")
       }
}
注意:協(xié)程2和協(xié)程3中的delay函數(shù)只是掛起了協(xié)程2和協(xié)程3系羞,不會(huì)影響協(xié)程1中的主線程的執(zhí)行.

執(zhí)行結(jié)果如下:


image.png
(2).協(xié)程都被掛起了,那么掛起函數(shù)的函數(shù)體由誰(shuí)執(zhí)行呢霸琴?

當(dāng)協(xié)程執(zhí)行到掛起函數(shù)式椒振,協(xié)程的執(zhí)行會(huì)被暫停(即協(xié)程被掛起),但它并不會(huì)阻塞執(zhí)行該掛起函數(shù)的線程梧乘,掛起函數(shù)的函數(shù)體任然由當(dāng)前線程繼續(xù)執(zhí)行澎迎。
為了更清楚的解釋這一點(diǎn),我們可以使用一下步驟:
(1).協(xié)程啟動(dòng):當(dāng)一個(gè)協(xié)程開始運(yùn)行時(shí),它會(huì)在某個(gè)線程(Dispatchers.Main)上執(zhí)行夹供。
(2).遇到掛起函數(shù):當(dāng)協(xié)程遇到掛起函數(shù)時(shí)辑莫,協(xié)程的執(zhí)行會(huì)被暫停。
(3).掛起函數(shù)執(zhí)行:盡管協(xié)程被暫停了罩引,掛起函數(shù)的函數(shù)體任然會(huì)在原始線程上執(zhí)行各吨。(除非該掛起函數(shù)明確指定了其他的執(zhí)行上下文)
(4).掛起函數(shù)完成:一旦掛起函數(shù)完成其工作,它會(huì)通知協(xié)程庫(kù)袁铐,然后協(xié)程會(huì)恢復(fù)執(zhí)行揭蜒。
注意:當(dāng)協(xié)程被掛起時(shí),主線程并沒(méi)有被阻塞剔桨,而是可以執(zhí)行其他的任務(wù)屉更,等到掛起函數(shù)執(zhí)行完畢,協(xié)程恢復(fù)時(shí)洒缀,又可以在主線程中繼續(xù)執(zhí)行瑰谜。
總結(jié)一下:在協(xié)程中使用掛起函數(shù)時(shí),任何可能得"阻塞"操作都會(huì)轉(zhuǎn)移到其他線程上執(zhí)行树绩,這樣啟動(dòng)協(xié)程的原始線程(例如主線程)就不會(huì)被實(shí)際阻塞萨脑,這樣使得協(xié)程特別適合UI線程編程,因?yàn)樗梢源_保UI線程保持響應(yīng)饺饭。

6.kotlin協(xié)程在工作中有用過(guò)嗎渤早?

kotlin協(xié)程是一個(gè)線程框架,提供了一種輕量級(jí)的并發(fā)處理方式瘫俊,通過(guò)非阻塞掛起和恢復(fù)實(shí)現(xiàn)了用同步代碼的方式編寫異步代碼鹊杖,把原本運(yùn)行在不同線程的代碼寫在一個(gè)代碼塊{}里面,看起來(lái)就像是同步代碼扛芽。
協(xié)程的目的是骂蓖,簡(jiǎn)化復(fù)雜的異步代碼邏輯,用同步的代碼編寫方式實(shí)現(xiàn)復(fù)雜異步代碼邏輯川尖。

(1).幾種封裝好的協(xié)程
  • CoroutineScope(Dispatchers.IO)構(gòu)造函數(shù)啟動(dòng)協(xié)程 ,通過(guò)Dispatchers指定運(yùn)行的線程登下。


    image.png
  • GlobalScope啟動(dòng)協(xié)程(默認(rèn)不是主線程)


    image.png
  • MainScope啟動(dòng)協(xié)程(默認(rèn)運(yùn)行在主線程)


    image.png
  • viewModelScope啟動(dòng)協(xié)程(默認(rèn)運(yùn)行在主線程)


    image.png
  • lifecycleScope啟動(dòng)協(xié)程(默認(rèn)運(yùn)行在主線程)


    image.png

協(xié)程就是一個(gè)線程框架,是對(duì)線程的封裝空厌,提供了一種輕量并發(fā)的處理方式庐船,通過(guò)非阻塞式掛起和恢復(fù)的方式,用同步代碼的方編寫式實(shí)現(xiàn)復(fù)雜的異步代碼邏輯嘲更,把原本運(yùn)行在不同線程的代碼寫在一個(gè)代碼塊里面,看起來(lái)就像同步代碼揩瞪。

(2).如果一個(gè)頁(yè)面需要同時(shí)并發(fā)請(qǐng)求多個(gè)接口赋朦,當(dāng)所有的接口都請(qǐng)求完成需要做一些合并處理,然后更新UI,如何并發(fā)處理呢宠哄?
  • 方法一:為每個(gè)接口設(shè)置一個(gè)boolean值壹将,每當(dāng)接口請(qǐng)求成功,boolean值設(shè)置為true,當(dāng)最后一個(gè)接口請(qǐng)求成功后毛嫉,在更新UI诽俯,這樣就達(dá)到了并發(fā)的目的 【管理多個(gè)boolean值,不夠優(yōu)雅承粤,太累了】

  • 方法二:RXjava的zip操作符【達(dá)到發(fā)射一次暴区,將結(jié)果合并處理的目的】

   fun testRxjavaZip(){
        println("-------------")
        val observable1: Observable<HttpResult<List<Banner>>> = HttpRetrofit.apiService.getBanners().subscribeOn(Schedulers.io()).observeOn(
            AndroidSchedulers.mainThread())
        val observable2:Observable<HttpResult<ArrayList<HomeData.DatasBean>>> =HttpRetrofit.apiService.getTopArticles().subscribeOn(Schedulers.io()).observeOn(
            AndroidSchedulers.mainThread())
        val observable3: Observable<HttpResult<List<KnowledgeData>>> = HttpRetrofit.apiService.getKnowledgeTree().subscribeOn(Schedulers.io()).observeOn(
            AndroidSchedulers.mainThread())
        var result1: HttpResult<List<Banner>>? =null
        var result2: HttpResult<ArrayList<HomeData.DatasBean>>? =null
        var result3: HttpResult<List<KnowledgeData>>? =null
        Observable.zip(observable1, observable2, observable3,
            object: Function3<
                    HttpResult<List<Banner>>,
                    HttpResult<ArrayList<HomeData.DatasBean>>,
                    HttpResult<List<KnowledgeData>>,
                    Boolean>{
                override fun apply(t1: HttpResult<List<Banner>>, t2: HttpResult<ArrayList<HomeData.DatasBean>>, t3: HttpResult<List<KnowledgeData>>): Boolean {
                    result1=t1
                    result2=t2
                    result3=t3
                    return t1!=null&&t2!=null&&t3!=null
                }
            }).subscribe(object:Observer<Boolean>{
            override fun onSubscribe(d: Disposable) {

            }

            override fun onError(e: Throwable) {

            }

            override fun onComplete() {

            }

            override fun onNext(t: Boolean) {
                if(t){//對(duì)結(jié)果進(jìn)行處理
                    println("成功獲取結(jié)果");
                    println(Gson().toJson(result1))
                    println(Gson().toJson(result2))
                    println(Gson().toJson(result3))
                }
            }
        });

    }
  • kotlin協(xié)程提供了一種輕量級(jí)的并發(fā)處理方式
    fun testCoroutineInActivity() {
      //1.launch啟動(dòng)協(xié)程,返回Job對(duì)象辛臊,通過(guò)job.cancel()取消任務(wù)
     val job:Job=CoroutineScope(Dispatchers.IO).launch() { 
            println("Test001:查看運(yùn)行的線程1:"+Thread.currentThread().name)
            val start= System.currentTimeMillis()
            val result1=async {//運(yùn)行在主線程仙粱,非異步
                println("Test001:查看運(yùn)行的線程2:"+Thread.currentThread().name)
                delay(1000)
                "123"
            }
         //2.async  啟動(dòng)協(xié)程,得到有返回值的Deferred對(duì)象
            val result2:Deferred<String> = async(Dispatchers.IO) { //異步 
                println("Test001:查看運(yùn)行的線程3:"+Thread.currentThread().name)
                delay(2000)
                 "456"

            }
            val result3=result1.await()+result2.await();
            println("Test001:并發(fā)耗時(shí):"+ (System.currentTimeMillis() - start)+"||result3:"+result3)
            withContext(Dispatchers.IO){
                println("Test001:查看運(yùn)行的線程4:"+ Thread.currentThread().name)
                delay(1000)
            }
            println("Test001:查看運(yùn)行的線程5:"+ Thread.currentThread().name)
        }
    }
  • kotlin協(xié)程解決地獄回調(diào)問(wèn)題【先調(diào)用接口1獲取數(shù)據(jù)彻舰,然后拿到接口1的結(jié)果作為參數(shù)調(diào)用接口2】
// 注意:在真實(shí)開發(fā)過(guò)程中伐割,MainScope作用域用的非常常用
MainScope().launch(){     // 注意:此協(xié)程塊默認(rèn)是在UI線程中啟動(dòng)協(xié)程
    // 下面的代碼看起來(lái)會(huì)以同步的方式一行行執(zhí)行(異步代碼同步獲取結(jié)果)
    val token = apiService.getToken()   // 網(wǎng)絡(luò)請(qǐng)求:IO線程,獲取用戶token
    val user = apiService.getUser(token)// 網(wǎng)絡(luò)請(qǐng)求:IO線程刃唤,獲取用戶信息
    nameTv.text = user.name             // 更新 UI:主線程隔心,展示用戶名
    val articleList = apiService.getArticleList(user.id)// 網(wǎng)絡(luò)請(qǐng)求:IO線程,根據(jù)用戶id獲取用戶的文章集合哦
    articleTv.text = "用戶${user.name}的文章頁(yè)數(shù)是:${articleList.size}頁(yè)"   // 更新 UI:主線程
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末尚胞,一起剝皮案震驚了整個(gè)濱河市济炎,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌辐真,老刑警劉巖须尚,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異侍咱,居然都是意外死亡耐床,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門楔脯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)撩轰,“玉大人,你說(shuō)我怎么就攤上這事昧廷】吧” “怎么了?”我有些...
    開封第一講書人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵木柬,是天一觀的道長(zhǎng)皆串。 經(jīng)常有香客問(wèn)我,道長(zhǎng)眉枕,這世上最難降的妖魔是什么恶复? 我笑而不...
    開封第一講書人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任怜森,我火速辦了婚禮,結(jié)果婚禮上谤牡,老公的妹妹穿的比我還像新娘副硅。我一直安慰自己,他們只是感情好翅萤,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開白布恐疲。 她就那樣靜靜地躺著,像睡著了一般套么。 火紅的嫁衣襯著肌膚如雪培己。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,125評(píng)論 1 297
  • 那天违诗,我揣著相機(jī)與錄音漱凝,去河邊找鬼。 笑死诸迟,一個(gè)胖子當(dāng)著我的面吹牛茸炒,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播阵苇,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼壁公,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了绅项?” 一聲冷哼從身側(cè)響起紊册,我...
    開封第一講書人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎快耿,沒(méi)想到半個(gè)月后囊陡,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡掀亥,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年撞反,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片搪花。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡遏片,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出撮竿,到底是詐尸還是另有隱情吮便,我是刑警寧澤,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布幢踏,位于F島的核電站髓需,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏惑折。R本人自食惡果不足惜授账,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一枯跑、第九天 我趴在偏房一處隱蔽的房頂上張望惨驶。 院中可真熱鬧白热,春花似錦、人聲如沸粗卜。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)续扔。三九已至攻臀,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間纱昧,已是汗流浹背刨啸。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留识脆,地道東北人设联。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像灼捂,于是被迫代替她去往敵國(guó)和親离例。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353

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