Android拾萃- Activity的生命周期和啟動模式

一、概述

Activity 作為與用戶交互的一個窗口,是使用非常頻繁的一個基本組件。Android系統是通過Activity棧來管理Activity的,而Activity則是通過哦生命周期來進行自己的創建、活動與銷毀等。所以掌握Activity生命周期很有必要。

二、金字塔模型

Activity生命周期

??官方的描述很形象,Activity 生命周期的每個階段就是金字塔上的一階。
??當系統創建新 Activity 實例時,每個回調方法會將 Activity 狀態向頂端移動一階。 金字塔的頂端是 Activity 在前臺運行并且用戶可以與其交互的時間點。
??當用戶開始離開 Activity 時,系統會調用其他方法在金字塔中將 Activity 狀態下移,從而銷毀 Activity。
??在有些情況下,Activity 將只在金字塔中部分下移并等待(比如,當用戶切換到其他應用時),Activity 可從該點開始移回頂端(如果用戶返回到該 Activity),并在用戶停止的位置繼續。

這個模型中包含了Activity的六種狀態:

Created:創建完成
Started:可見(不可交互)
Resumed:可見(活動)
Paused:部分可見(后臺)
Stopped:不可見
Destroyed:銷毀

在這六種狀態當中,只有ResumedPausedStopped這幾種狀態在用戶沒有進一步操作時會保持在該狀態,而其余的,都會在執行完相應的回調函數后快速跳過,很容易理解,resumed 狀態就是在當前界面,后面兩個狀態是進入了另一個界面活動,如果打開一個dialog或者透明主題(dialog主題)的Activity,這個時候,只會進入paused狀態,不會進入stoped狀態。

一般情況下,您不得使用 onPause() 永久性存儲用戶更改(比如輸入表格的個人信息)。 只有在您確定用戶希望自動保存這些更改的情況(比如,草擬電子郵件時)下,才能在 onPause() 中永久性存儲用戶更改。但您應避免在 onPause() 期間執行 CPU 密集型工作,比如向數據庫寫入信息,因為這會拖慢向下一 Activity 過渡的過程(您應改為在 onStop() 間執行高負載關機操作)。另外一點就是,啟動新的Activity,當前的Activity必須onpause進入后臺,才會開始啟動下一個Activity。

三、異常情況下的生命周期

在有些情況下,您的 Activity 會因正常應用行為而銷毀,比如當用戶按 返回按鈕或您的 Activity 通過調用 finish()示意自己的銷毀。 如果 Activity 當前被停止或長期未使用,或者前臺 Activity 需要更多資源以致系統必須關閉后臺進程恢復內存,系統也可能會銷毀 Activity。

當您的 Activity 因用戶按了返回 或 Activity 自行完成而被銷毀時,系統的 Activity 實例概念將永久消失,因為行為指示不再需要 Activity。 但是,如果系統因系統局限性(而非正常應用行為)而銷毀 Activity,盡管 Activity 實際實例已不在,系統會記住其存在,這樣,如果用戶導航回實例,系統會使用描述 Activity 被銷毀時狀態的一組已保存數據創建 Activity 的新實例。 系統用于恢復先前狀態的已保存數據被稱為“實例狀態”,并且是 Bundle 對象中存儲的鍵值對集合。

注意:每次用戶旋轉屏幕時,您的 Activity 將被銷毀并重新創建。 當屏幕方向變化時,系統會銷毀并重新創建前臺 Activity,因為屏幕配置已更改并且您的 Activity 可能需要加載備用資源(比如布局)。

默認情況下,系統會使用 Bundle 實例狀態保存您的 Activity 布局(比如,輸入到 EditText 對象中的文本值)中有關每個 View 對象的信息。 這樣,如果您的 Activity 實例被銷毀并重新創建,布局狀態便恢復為其先前的狀態,且您無需代碼。 但是,您的 Activity 可能具有您要恢復的更多狀態信息,比如跟蹤用戶在 Activity 中進度的成員變量。

:為了 Android 系統恢復 Activity 中視圖的狀態,每個視圖必須具有 android:id 屬性提供的唯一 ID。

要保存有關 Activity 狀態的其他數據,您必須替代 onSaveInstanceState() 回調方法。當用戶要離開 Activity 并在 Activity 意外銷毀時向其傳遞將保存的 Bundle 對象時,系統會調用此方法。 如果系統必須稍后重新創建 Activity 實例,它會將相同的 Bundle 對象同時傳遞給 onRestoreInstanceState() 和 onCreate() 方法。

如果Activity A 啟動 B 在啟動 C,如果A和B被回收了,這個時候C返回,B會重繪(實例被回收了,但是棧還是在的)

四、由重建引發的窗體泄露

Android的每一個Activity都有個WindowManager窗體管理器,構建在某個Activity之上的對話框、PopupWindow也有相應的WindowManager窗體管理器。因為Dialog、PopupWindown不能脫離Activity而單獨存在著,所以當承載某個Dialog或者某個PopupWindow正在顯示的Activity被finish()后,而Dialog(或PopupWindow)沒有正常退出的話,就會拋Window Leaked錯誤了,因為這個Dialog(或PopupWindow)的WindowManager已經沒有誰可以附屬了,所以它的窗體管理器就泄漏了。

在進入新的Activity時突然轉屏(哥們開發的sdk支持橫豎屏切換),因為在AndroidManifest.xml中沒有配置android:configChanges屬性,此時Activity會重新調用onCreate方法,即會重新調用整個生命周期,而此時的Dialog已經顯示并沒有dismiss,所以造成了窗體泄漏。解決的方法就變得如此簡單,在AndroidManifest.xml中配置android:configChanges屬性,這樣當我們橫豎屏切換的時候會調用Activity的onConfigurationChanged方法,不會重新調用整個生命周期了。

android:configChanges的一些屬性

1、不設置Activity的android:configChanges時,切屏會重新調用整個生命周期,切橫屏時會執行一次,切豎屏時會執行兩次

2、設置Activity的android:configChanges="orientation"時,切屏還是會重新調用整個生命周期,切橫、豎屏時只會執行一次

3、設置Activity的android:configChanges="orientation|screenSize"一起設置的時候才是moshi有效的(原因看下面的表格)。雖然不會重建Activity,但是會回調Activity里面的一個方法: onConfigurationChanged(Configuration config)
在這里你可以監聽了,Activity的什么改變了,比如方向,比如彈出了鍵盤還是隱藏了moshi鍵盤(清單文件的Activity 添加android:configChanges="keyboard|keyboardHidden“),如果有需要監控其他屬性的需求,請參考底下的表格進行屬性添加

附上開發藝術探索的一張圖(侵刪)android:configChanges屬性解釋:

configchange的項目和含義.png

五、Activity的啟動模式

任務棧

我們知道系統使用棧來管理Activity,而棧根據是否在前臺,可以劃分為前臺棧和后臺棧(實際沒有區別,根據當前的Activity劃分,即前臺只有一個,后臺可能有多個)。

  1. Android任務棧又稱為Task,它是一個棧結構,具有后進先出的特性,用于存放我們的Activity組件。
  2. 我們每次打開一個新的Activity或者退出當前Activity都會在一個稱為任務棧的結構中添加或者減少一個Activity組件,因此一個任務棧包含了一個activity的集合, android系統可以通過Task有序地管理每個activity,并決定哪個Activity與用戶進行交互:只有在任務棧棧頂的activity才可以跟用戶進行交互。
  3. 在我們退出應用程序時,必須把所有的任務棧中所有的activity清除出棧時,任務棧才會被銷毀。當然任務棧也可以移動到后臺, 并且保留了每一個activity的狀態. 可以有序的給用戶列出它們的任務, 同時也不會丟失Activity的狀態信息。
  4. 需要注意的是,一個App中可能不止一個任務棧,某些特殊情況下,單獨一個Actvity可以獨享一個任務棧。還有一點就是一個Task中的Actvity可以來自不同的App,同一個App的Activity也可能不在一個Task中。

那么系統是怎么劃分Activity是在同一個棧里呢?這個時候就要說下TaskAffinity這個屬性了。

TaskAffinity屬性

TaskAffinity(任務相關性),這個參數標識了一個Activity所需要的任務棧的名字,默認情況下,所有的Activity所需的任務棧的名字為應用的包名.
可以為每個Activity都單獨指定TaskAffinity屬性,不同的名字代表不同的任務棧android:taskAffinity="屬性值為字符串"。
TaskAffinity如何生效

  • TaskAffinity + singleTask (其實就是把singletask放到和包名不一樣的棧,singletask單獨使用,不代表不能在包名這個棧,他只表示一旦創建之后,只允許一個棧存在一個實例)
  • TaskAffinity + allowTaskReparenting(允許了其他應用的某個Activity無縫遷移進入我們應用的Activity棧,一旦再次打開其他應用的時候,又會遷移回去,具體見下面的圖)
  • 其他情況是無效的

可以通過 adb shell dumpsys activity activities 命令查看棧的情況
command + K是terminal的清屏快捷鍵
l 在adb命令中顯示的launchMode代表的數值
standard : launchMode = 0
singleTop : launchMode=1
singleTask: launchMode= 2
singleInstance: launchMode=3

allowTaskReparenting = true 的遷移行為,如下圖(來源于網絡,侵刪)

TaskAffinity_allowTaskReparenting.png

不過有點需要說明的是allowTaskReparenting僅限于singleTopstandard模式,這是因為一個activity的affinity屬性由它的taskAffinity屬性定義(代表棧名),而一個task的affinity由它的root activity定義。所以,一個task的root activity總是擁有和它所在task相同的affinity。由于以singleTask和singleInstance啟動的activity只能是一個task的root activity,因此allowTaskReparenting僅限于以standard 和singleTop啟動的activity

四種啟動模式

我們應用中有多個Activity組件,之間經常會進行跳轉,也有可能需要在本應用中打開其它應用的的Activity。當我們返回上一個組件時,我們更希望復用這個Activity。
但Android系統的stander模式每次都會為我們創建一個新的Activity并添加到Task中。另外,我們開啟一次頁面,它的數據和信息狀態都會被保留,這樣會造成數據冗余, 重復數據太多, 最終還可能導致內存溢出的問題(OOM)。

為了解決這些問題,android系統提供了一套Activity的啟動模式來修改系統Activity的默認啟動行為。目前啟動模式有四種,分別是standardsingleTopsingTasksingleInstance,接下來我們將分別介紹這四種模式。

  • Standard 模式
    ??又稱為標準模式,也是系統的默認模式(可以不指定),在這樣模式下,每啟動一個Activity都會重新創建一個Activity的新實例,并且將其加入任務棧中,而且完全不會去考慮這個實例是否已存在。

  • singleTop 模式
    ??又稱棧頂復用模式,顧名思義,在這種模式下,如果有新的Activity已經存在任務棧的棧頂,那么此Activity就不會被重新創建新實例,而是復用已存在任務棧棧頂的Activity。這里重點是位于棧頂,才會被復用,如果新的Activity的實例已存在但沒有位于棧頂,那么新的Activity仍然會被重建。需要注意的是,Activity的onNewIntent方法會被調用,方法原型如下:

@Override
protected void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
}

通過此方法的參數,我們可以獲取當前請求的相關信息,此時Activity的onCreate、onStart方法不會被調用,因為Activity并沒有被重建。
??這種模式通常比較適用于接收到消息后顯示的界面,如qq接收到消息后彈出Activity界面,如果一次來10條消息,總不能一次彈10個Activity,是吧?再比如新聞客戶端收到了100個推送,你每次點一下推送他都會進入某個activiy界面(顯singleTask 模式
?? 又稱為棧內復用模式。這是一種單例模式,與singTop點類似,只不過singTop是檢測棧頂元素是否有需要啟動的Activity,而singTask則是檢測整個棧中是否存在當前需要啟動的Activity,如果存在就直接將該Activity置于棧頂,并將該Activity以上的Activity都從任務棧中移出銷毀,同時也會回調onNewIntent方法。示新聞只用一個activity,只是內容不同而已),這時也比較適合使用singleTop模式。

  • singleTask 模式
    ?? 又稱為棧內復用模式。這是一種單例模式,與singTop點類似,只不過singTop是檢測棧頂元素是否有需要啟動的Activity,而singTask則是檢測整個棧中是singleTask 模式否存在當前需要啟動的Activity,如果存在就直接將該Activity置于棧頂,并將該Activity以上的Activity都從任務棧中移出銷毀,同時也會回調onNewIntent方法。

singleTask 模式比較適合應用的主界面activity(頻繁使用的主架構),可以用于主架構的activity,(如新聞,側滑,應用主界面等)里面有好多fragment,一般不會被銷毀,它可以跳轉其它的activity 界面再回主架構界面,此時其他Activity就銷毀了。

  • singleInstance 模式
    ??在singleInstance模式下,該Activity在整個android系統內存中有且只有一個實例,而且該實例單獨尊享一個Task。換句話說,A應用需要啟動的MainActivity 是singleInstance模式,當A啟動后,系統會為它創建一個新的任務棧,然后A單獨在這個新的任務棧中,如果此時B應用也要激活MainActivity,由于棧內復用的特性,則不會重新創建,而是兩個應用共享一個Activity的實例。

Activity啟動模式的使用方式

如何給Activity指定啟動模式呢?事實上共有如下兩種方式:
1. 通過AndroidMenifest.xml文件為Activity指定啟動模式,代碼如下:

<activity android:name=".ActivityC" 
          android:launchMode="singleTask" />

2. 通過在Intent中設置標志位(addFlags方法)來為Activity指定啟動模式,示例代碼如下:

Intent intent = new Intent();
intent.setClass(ActivityB.this,ActivityA.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);

那么什么是標志位呢?常用的標志位有哪一些?

啟動標記 Intent Flag

  • Intent.FLAG_ACTIVITY_NEW_TASK
    該標志位表示使用一個新的Task來啟動一個Activity,相當于在清單文件中給Activity指定“singleTask”啟動模式。

  • Intent.FLAG_ACTIVITY_SINGLE_TOP
    ??該標志位表示使用singleTop模式來啟動一個Activity,與在清單文件指定android:launchMode="singleTop"效果相同。

  • Intent.FLAG_ACTIVITY_CLEAR_TOP
    該標志位表示使用singleTask模式來啟動一個Activity,與在清單文件指定android:launchMode="singleTask"效果相同。

  • Intent.FLAG_ACTIVITY_NO_HISTORY
    ??使用該模式來啟動Activity,當該Activity啟動其他Activity后,該Activity就被銷毀了,不會保留在任務棧中。如A-B,B中以這種模式啟動C,C再啟動D,則任務棧只有ABD。

  • Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
    ??使用該標識位啟動的Activity不添加到最近應用列表,也即我們從最近應用里面查看不到我們啟動的這個activity。與屬性android:excludeFromRecents="true"效果相同。

啟動模式中singleTask的特殊情景

特殊情景一

前面我們在分析singleTask模式時,提到過singleTask模式有些比較特殊的場景,現在我們就來了解了解它們。
特殊情景一:現在我們假設有如下兩個Task棧,分別為前臺任務棧和后臺任務棧

前臺任務棧和后臺任務棧

從圖中我們看出前臺任務棧分別為AB兩個Activity,后臺任務棧分別為CD兩個任務棧,而且其啟動模式均為singleTask,此時我們先啟動CD,然后再啟動AB,再有B啟動D,此時后臺任務棧便會被切換到前臺,而且這個時候整個后退列表就變成了ABCD,請注意我們這里強調的是后退列表,而非棧合并。因此當用戶點擊back鍵時,列表中的Activity會依次按DCBA順序出棧,如下圖所示:


back.png
特殊情景二:

如果上面B不是請求啟動D而是請求啟動C,那么又會是什么情況呢?其實這個時候任務棧退出列表變成C->B->A,其實原因很簡單,singleTask模式的ActivityC切換到棧頂時會導致在他之上的棧內的Activity出棧。其他情況都一樣。

特殊場景三:
  • StartActivityForResult的時候,requestCode必須>0,否則收不到result
    看下以下關系圖
android 5.0之前
Android 5.0之后

這是為什么呢?

這是因為ActivityStackSupervisor類中的startActivityUncheckedLocked方法在5.0中進行了修改。在5.0之前,當啟動一個Activity時,系統將首先檢查Activity的launchMode,如果為A頁面設置為SingleInstance或者B頁面設置為singleTask或者singleInstance,則會在LaunchFlags中加入FLAG_ACTIVITY_NEW_TASK標志,而如果含有FLAG_ACTIVITY_NEW_TASK標志的話,onActivityResult將會立即接收到一個cancle的信息,而5.0之后這個方法做了修改,修改之后即便啟動的頁面設置launchMode為singleTask或singleInstance,onActivityResult依舊可以正常工作,也就是說無論設置哪種啟動方式,StartActivityForResult和onActivityResult()這一組合都是有效的。所以如果你目前正好基于5.0做相關開發,不要忘了向下兼容,這里有個坑請注意避讓。

TaskAffinity與allowTaskReparenting和singleTask結合時可能發生的應用場景

TaskAffinity與singleTask應用場景

假如現在有這么一個需求,我們的客戶端app正處于后臺運行,此時我們因為某些需要,讓微信調用自己客戶端app的某個頁面,用戶完成相關操作后,我們不做任何處理,按下回退或者當前Activity.finish(),頁面都會停留在自己的客戶端(此時我們的app回退棧不為空),這顯然不符合邏輯的,用戶體驗也是相當出問題的。我們要求是,回退必須回到微信客戶端,而且要保證不殺死自己的app.這時候我們的處理方案就是,設置當前被調起Activity的屬性為:

LaunchMode=""SingleTask" taskAffinity="com.tencent.mm"

其中com.tencent.mm是借助于工具找到的微信包名,就是把自己的Activity放到微信默認的Task棧里面,這樣回退時就會遵循“Task只要有Activity一定從本Task剩余Activity回退”的原則,不會回到自己的客戶端;而且也不會影響自己客戶端本來的Activity和Task邏輯。

TaskAffinity與allowTaskReparenting應用場景

一個e-mail應用消息包含一個網頁鏈接,點擊這個鏈接將觸發一個activity來顯示這個頁面,雖然這個activity是瀏覽器應用定義的,但是activity由于e-mail應用程序加載的,所以在這個時候該activity也屬于e-mail這個task。如果e-mail應用切換到后臺,瀏覽器在下次打開時由于allowTaskReparenting值為true,此時瀏覽器就會顯示該activity而不顯示瀏覽器主界面,同時actvity也將從e-mail的任務棧遷移到瀏覽器的任務棧,下次打開e-mail時并不會再顯示該activity

清空任務棧

Android系統除了給我提供了TaskAffinity來指定任務棧名稱外,還給我提供了清空任務棧的方法,在一般情況下我們只需要在<activity>標簽中指明相應的屬性值即可。
  如果用戶離開一個task很久,系統就會清理這個task中的所有activities,除了根activity。當用戶返回到這個task,只有根activity會被恢復。
  有一些activity的屬性,你可以用來改變這一行為:

android:clearTaskOnLaunch

這個屬性用來標記是否從task清除除根Activity之外的所有的Activity,“true”表示清除,“false”表示不清除,默認為“false”。這里有點我們必須要注意的,這個屬性只對任務棧內的root Activity起作用,任務棧內其他的Activity都會被忽略。如果android:clearTaskOnLaunch屬性為“true”,每次我們重新android:clearTaskOnLaunch進入這個應用時,我們只會看到根Activity,任務棧中的其他Activity都會被清除出棧。
??比如一個應用的Activity A,B,C,其中A 的clearTaskOnLaunch設置為true,C為默認值,我們依次啟動A,B,C,點擊HOME,再在桌面點擊圖標。啟動的是A,而B,C將都被移除當前任務棧。也就是說,當Activity的屬性clearTaskOnLaunch為true時將被優先啟動,其余的Activity(B、C)都被移除任務棧并銷毀,除非前面A已經finish銷毀,后面的已注冊clearTaskOnLaunch為true的activity(B)才會生效。
??特別地,如果我們的應用中引用到了其他應用的Activity,這些Activity設置了android:allowTaskReparenting屬性為“true”,則它們會被重新宿主到有共同affinity的task中。

android:finishOnTaskLaunch

finishOnTaskLaunch屬性與clearTaskOnLaunch 有些類似,它們的區別是finishOnTaskLaunch是作用在自己身上(把自己移除任務棧,不影響別的Activity),而clearTaskOnLaunch則是作用在別人身上(把別的Activity移除任務棧),如果我們把Activity的android:finishOnTaskLaunch屬性值設置為true時,離開這個Activity所依賴的任務棧后,當我們重新返回時,該Activity將會被finish掉,而且其他Activity不會受到影響。

android:alwaysRetainTaskState

alwaysRetainTaskState實際上是給了當前Activity所在的任務棧一個“免死金牌”,如果當前Activity的android:alwaysRetainTaskState設置為true時,那么該Activity所在的任務棧將不會受到任何清理命令的影響,一直保持當前任務棧的狀態。

應用場景:

  1. singleTop適合接收通知啟動的內容顯示頁面。例如,某個新聞客戶端的新聞內容頁面,如果收到10個新聞推送,每次都打開一個新聞內容頁面是很煩人的。聊天的對話窗口,
  1. singleTask適合作為程序入口點。例如瀏覽器的主界面。不管從多少個應用啟動瀏覽器,只會啟動主界面一次,其余情況都會走onNewIntent,并且會清空主界面上面的其他頁面。之前打開過的頁面,打開之前的頁面就ok,不再新建。
    singleTask:a界面購物,b界面確認訂單,c界面付款,如果付款成功會跳到a,如果不付款則返回b,這時候重啟a就會用到singleTask.

  2. singleInstance適合需要與程序分離開的頁面。例如鬧鈴提醒,將鬧鈴提醒與鬧鈴設置分離。singleInstance不要用于中間頁面,如果用于中間頁面,跳轉會有問題,比如:A -> B (singleInstance) -> C,完全退出后,在此啟動,首先打開的是B。

  3. standard 標準的啟動模式,也是默認的啟動模式。

隱式啟動Activity,intentFilter匹配規則

這一部分參考的 http://www.lxweimin.com/p/151640add690
啟動activity分為兩種,顯式啟動和隱式啟動。顯式:明確指出被調用activity的包名類名,隱式調用不需要明確信息。顯式和隱式原則上是不共存的,如果共存以顯示為主。隱式啟動匹配信息在AndroidManifest的activity中的<intent-filter>,三種過濾信息:action,category,data。三個信息可同時存在多個。intent-filter也可同時存在多個,匹配其中一組intent-filter的三種信息各一種即可。

匹配規則
action

區分大小寫,action系統有自定義一些,action匹配字符串必須一樣。若intentFilter定義了action屬性,隱式啟動至少匹配其中一個。

category

Intent未指定category時,系統會默認給Intent增加category屬性:<category android:name="android.intent.category.DEFAULT" ,所以如果你隱式啟動activity且不想指定category在AndroidManifest總定義隱式啟動時,需加上<category android:name="android.intent.category.DEFAULT"。
Intent指定category,指定一個必須正確匹配一個,多個必須正確匹配多個。

data

intentFilter配置data,Intent隱式啟動必須匹配至少一個,和action類似
先介紹一種結構 URI:

<scheme>://<host>:<port>/[<path>|<pathPrefix>|<pathPattern>]

例如
content://com.example.test:100/folder/subfolder/test
http://www.baidu.com:80/search/info

data的所有匹配屬性如下:

<data   
     android:mimeType="string"  
     android:scheme="string"  
     android:host="string"  
     android:port="string"  
     android:path="string"  
     android:pathPrefix="string"  
     android:pathPattern="string"/> 

主要分為兩種,一種是mimeType,一種是URI中的其中任何之一屬性。

屬性簡介:

mimeType:媒體類型,image/jpeg,image/png,image/* 、video/等等
Scheme:URI模式,http、file、content等,URI無此參數URI無效
Host:URI主機名,www.baidu.com等,URI無此參數URI無效
Port:URI中端口號
Path/PathPrefix/PathPattern:路徑信息,path和pathPattern表示完整的路徑信息,pahPatten可包含通配符"",PathPrefix路徑的前綴信息。
設置方法三種:

mIntent.setType(mType)
mIntent.setData(mUri)
mIntent.setDataAndType(mUri,mType)

若先setType再setData,mimeType會被清空
若先setData再setType,data會被清空
原因看源碼,setType和seData類似

public Intent setData(Uri data) {
        mData = data;
        mType = null;
        return this;
    }

如下兩種屬性同時使用,標明這是一個入口activity,并且會出現在系統應用列表中

<action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER"
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,663評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,125評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,506評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,614評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,402評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,934評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,021評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,168評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,690評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,596評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,784評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,288評論 5 357
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,027評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,404評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,662評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,398評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,743評論 2 370

推薦閱讀更多精彩內容