Android JetPack系列之——Navigation

由于Android的開源性哟沫,在開始的幾年呈現(xiàn)出了百家齊放的盛況匕得,層出不窮的API和以及官方的API各自大放異彩掠河,在豐富了android生態(tài)的同時(shí)也帶來了一個(gè)很嚴(yán)重的問題,即android 的碎片化和規(guī)范化的問題灯节。碎片化主要集中于國(guó)內(nèi)的各大手機(jī)廠商的多種屏幕尺寸循头、多種手機(jī)分辨率、多種機(jī)型的多樣性上炎疆,而規(guī)范化則是集中于開發(fā)生態(tài)上面贷岸,由于Google官方的弱約束,很多時(shí)候大家都隨心所欲以業(yè)務(wù)驅(qū)動(dòng)技術(shù)去進(jìn)行開發(fā)磷雇,導(dǎo)致沒有一個(gè)很好的開發(fā)整體框架偿警。基于此唯笙,Google官方在2018年發(fā)布了一系列輔助開發(fā)Android開發(fā)者的實(shí)用工具螟蒸,合成JetPack。

一崩掘、什么是JetPack?

根據(jù)官方介紹七嫌,JetPack是一個(gè)由多個(gè)庫組成的套件,可幫助開發(fā)者遵循最佳做法苞慢,減少樣板代碼并編寫可在各種Android版本和設(shè)備中一致運(yùn)行的代碼诵原,讓開發(fā)者可將精力集中于真正重要的編碼工作。下面是官方關(guān)于Jetpack的描述圖


Jetpack.jpeg

1. 基礎(chǔ)組件
(1) AppCompat:使得支持較低的 Android 版本挽放。從以前繼承 Activity 到現(xiàn)在繼承AppCompatActivity 就是屬于這一部分
(2) Android KTX:Kotlin 的擴(kuò)展支持庫
(3) Multidex:多 dex 文件支持
(4) Test:測(cè)試支持庫

2. 架構(gòu)組件
(1) Data Binding:MVVM 的一種實(shí)踐
(2) Lifecycles:管理你的 Activity 和 Fragment 生命周期
(3) LiveData:通過觀察者模式感知數(shù)據(jù)變化绍赛,類比 RxJava
(4) Navigation:處理 Fragment 導(dǎo)航相關(guān)邏輯
(5) Paging:分頁數(shù)據(jù)加載方案
(6) Room:官方 ORM 庫
(7) ViewModel:通過數(shù)據(jù)驅(qū)動(dòng) V 視圖發(fā)生改變
(8) WorkManager:管理后臺(tái)任務(wù)

3. 行為組件
(1) DownloadManager:管理下載任務(wù)
(2) Media App:多媒體播放和一些向后兼容的API。主要包含 MediaPlayer 和 ExoPlayer
(3) Notifications:提供向后兼容的通知 API辑畦,支持 Wear 和 Auto
(4) Permissions:權(quán)限管理吗蚌,這個(gè)應(yīng)該都接觸過。用于檢查和請(qǐng)求應(yīng)用權(quán)限
(5) Settings:Preference 相關(guān) API纯出◎歉荆基本每個(gè)應(yīng)用都會(huì)用到
(6) Share Action:提供分享操作敷燎。這塊在國(guó)內(nèi)使用的不多,都是自己封裝或者采用第三方方案
(7) Slices:可以讓應(yīng)用通過外部(其他 APP)顯示 APP 界面(通過設(shè)備自帶的搜索箩言,語音助手等)

4. 界面組件
(1) Animations and Transitions:動(dòng)畫硬贯,界面轉(zhuǎn)場(chǎng)等
(2) Auto:針對(duì)車輛的標(biāo)準(zhǔn)化界面和模式
(3) Emoji:表情符號(hào)相關(guān)
(4) Fragment:基礎(chǔ)概念
(5) Layout:基礎(chǔ)概念
(6) Palette-Colors:調(diào)色板
(7) TV:Android TV 開發(fā)相關(guān)
(8) Wear:可穿戴設(shè)備(目前主要是手表)開發(fā)相關(guān)

二、JetPack到底值不值得我們?nèi)?yīng)用?

說實(shí)話陨收,這個(gè)問題仁者見仁智者見智澄成,因?yàn)闆]有什么東西是絕對(duì)的好或者不好,看你自己的需求而定畏吓,就像MVC、MVP卫漫、MVVM框架一樣菲饼,沒有說哪種模式一定最好,很多時(shí)候是要根據(jù)實(shí)際情況來定列赎。所以宏悦,同等道理,Jetpack到底要不要用包吝,怎么用看開發(fā)需求饼煞,但是對(duì)于我們開發(fā)者來說,掌握它卻是必不可少的诗越,只有完全的掌握它砖瞧,知道了它的優(yōu)點(diǎn)和缺點(diǎn)才能更好的做出理性的判斷在實(shí)際的開發(fā)者到底要不要用它。

三嚷狞、進(jìn)入正題——Jetpack組件之一Navigation

1.什么是Navigation

Navigation是一個(gè)可簡(jiǎn)化的Android導(dǎo)航的庫和插件块促,換句話說,Navigation是用來管理Fragment的切換的床未,并且是通過可視化的方式來進(jìn)行管理的竭翠。

2.Navigation的優(yōu)缺點(diǎn)
優(yōu)點(diǎn)
  • 處理Fragment的切換
  • 默認(rèn)情況下正確處理Fragment的前進(jìn)和后退
  • 為過渡和動(dòng)畫提供標(biāo)準(zhǔn)化的資源
  • 可以綁定Toolbar/BottomNavigationView/ActionBar等
  • 數(shù)據(jù)傳遞時(shí)提供類型安全性(使用SafeArgs)
  • ViewModel支持
缺點(diǎn)
  • fragment切換后底層會(huì)調(diào)用replace方法導(dǎo)致會(huì)被不斷銷毀,無法保存上一次的狀態(tài)
3.Navigation的使用

Navigation的使用相對(duì)來說比較簡(jiǎn)答薇搁,分為以下幾步:
(1)引入依賴
(2)創(chuàng)建多個(gè)要調(diào)配的Fragment
(3)在res下面創(chuàng)建navigation文件夾斋扰,并創(chuàng)建navigation文件
(4)在主Activity里面的XML文件里面引入指定的Fragment
基本上大體步驟就那么幾步,現(xiàn)在我們就一個(gè)一個(gè)來看啃洋。

步驟一:引入依賴

dependencies {
    // Java引入
    implementation "androidx.navigation:navigation-fragment:2.2.2"
    implementation "androidx.navigation:navigation-ui:2.2.2"
    // kotlin引入
    implementation 'androidx.navigation:navigation-fragment-ktx:2.2.2'
    implementation 'androidx.navigation:navigation-ui-ktx:2.2.2'
}

步驟二:創(chuàng)建多個(gè)要調(diào)配的Fragment
這里我創(chuàng)建了3個(gè)Fragment传货,第一個(gè)是歡迎頁面的WelcomeFragment,第二個(gè)是注冊(cè)的RegisterFragment宏娄,第三個(gè)是登錄頁面的LoginFragment损离。分別如下:
歡迎頁面的WelcomeFragment

class WelcomeFragment : Fragment() {

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.fragment_welcome, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        view.findViewById<Button>(R.id.register_jump).setOnClickListener {
            val navOption = navOptions {
                anim {
                    enter = R.anim.common_slide_in_right
                    exit = R.anim.common_slide_out_left
                    popEnter = R.anim.common_slide_in_left
                    popExit = R.anim.common_slide_out_right
                }
            }
            findNavController().navigate(R.id.registerFragment, null, navOption)
        }
        view.findViewById<Button>(R.id.login_jump).setOnClickListener {
            val navOption = navOptions {
                anim {
                    enter = R.anim.common_slide_in_right
                    exit = R.anim.common_slide_out_left
                    popEnter = R.anim.common_slide_in_left
                    popExit = R.anim.common_slide_out_right
                }
            }
            val bundle = LoginFragmentArgs.Builder().setLoginInfo("jack").build().toBundle()
            findNavController().navigate(R.id.loginFragment,bundle,navOption)
        }
    }
}

注冊(cè)的RegisterFragment

class RegisterFragment : Fragment() {

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.fragment_register, container, false)
    }
}

登錄頁面的LoginFragment

class LoginFragment : Fragment() {

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.fragment_login, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        val bundle = arguments
        if (bundle!=null){
            val loginTag = LoginFragmentArgs.fromBundle(bundle).loginInfo
            view.findViewById<TextView>(R.id.login_info).text = loginTag
        }
    }
}

步驟三:在res下面創(chuàng)建navigation文件夾,并創(chuàng)建navigation文件
需要注意的是navigation文件夾必須在res文件夾下面并且名稱為固定寫法绝编,這里我新建了一個(gè)splash_navigation.xml文件僻澎,如下所示:

<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/splash_navigation"
    app:startDestination="@id/welcomeFragment">
    <fragment
        android:id="@+id/welcomeFragment"
        android:name="com.jack.androidjetpack.login.WelcomeFragment"
        android:label="fragment_welcome"
        tools:layout="@layout/fragment_welcome">
        <action
            android:id="@+id/action_welcomeFragment_to_registerFragment"
            app:destination="@id/registerFragment" />
        <action
            android:id="@+id/action_welcomeFragment_to_loginFragment"
            app:destination="@id/loginFragment" />
    </fragment>
    <fragment
        android:id="@+id/registerFragment"
        android:name="com.jack.androidjetpack.login.RegisterFragment"
        android:label="fragment_register"
        tools:layout="@layout/fragment_register" />
    <fragment
        android:id="@+id/loginFragment"
        android:name="com.jack.androidjetpack.login.LoginFragment"
        android:label="fragment_login"
        tools:layout="@layout/fragment_login">
        <argument
            android:name="loginInfo"
            android:defaultValue="defaultValue"
            app:argType="string" />
    </fragment>
</navigation>

這個(gè)XML文件是Navigation里面一個(gè)比較重要的文件貌踏,下面我們慢慢來分析一下里面包含了哪些東西:

名稱 含義
<navigation>/</navigation> 文件必須以<navigation>開頭,以</navigation>結(jié)尾窟勃,標(biāo)識(shí)這是一個(gè)Navigation文件
app:startDestination 默認(rèn)的起始的fragment所對(duì)應(yīng)的id祖乳,此處意味著WelcomeFragment作為起始的Fragment
<fragment> Navigation所操作的都是Fragment
<fragment android:id 對(duì)應(yīng)的Fragment的id
<fragment android:name 對(duì)應(yīng)的Fragment,注意這里的值必須是完整的Fragment的路徑
<fragment android:layout 對(duì)應(yīng)的Fragment的布局文件
<fragment <action Fragment對(duì)應(yīng)的跳轉(zhuǎn)行為
<fragment <argument Fragment傳參
<argument Fragment傳參
<argument android:name Fragment傳參的key
<argument android:defaultValue Fragment傳參的參數(shù)默認(rèn)值
<argument app:argType Fragment傳參的參數(shù)對(duì)應(yīng)的類型

步驟四:在主Activity里面的XML文件里面引入指定的Fragment
主Activity很簡(jiǎn)單秉氧,沒有寫一行代碼

/**
 * 歡迎頁面
 */
class WelcomeActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_welcome)
    }
}

對(duì)應(yīng)的activity_welcome文件

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".login.WelcomeActivity">

    <fragment
        android:id="@+id/welcome_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:defaultNavHost="true"
        app:navGraph="@navigation/splash_navigation" />


</androidx.constraintlayout.widget.ConstraintLayout>

不知道大家發(fā)現(xiàn)沒有眷昆,在WelcomeActivity對(duì)應(yīng)的XML文件里面我們并沒有引用我們自己創(chuàng)建的Fragment,而是引用了一個(gè)NavHostFragment汁咏,那么NavHostFragment到底是什么呢亚斋?這里就要介紹幾個(gè)概念了:
(1) NavHostFragment:NavHostFragment是我們引入的Navigation組件提供的一個(gè)Fragment,其實(shí)現(xiàn)了NavHost接口攘滩,可以將它理解為系統(tǒng)默認(rèn)的一個(gè)Fragment模板帅刊,或者是當(dāng)前Fragment的容器。
(2)app:navGraph:NavHostFragment 與導(dǎo)航圖相關(guān)聯(lián)工作由它完成漂问,在navigation中完成到目的視圖導(dǎo)航
(3)app:defaultNavHost:是否被系統(tǒng)返回鍵攔截

需要強(qiáng)調(diào)的是赖瞒,在fragment中android:name="androidx.navigation.fragment.NavHostFragment"是固定寫法。

基礎(chǔ)工作已經(jīng)結(jié)束了蚤假,接下來我們解決兩個(gè)問題:

  • (1)Fragment的切換
  • (2)Fragment的傳參

先說明的就是栏饮,fragment的切換其實(shí)就是通過replace的方法來實(shí)現(xiàn)的,相信這個(gè)做法很多人都不陌生磷仰,只不過以前是我們自己手動(dòng)實(shí)現(xiàn)(包括回退棧)袍嬉,但是現(xiàn)在借助Navigation我們不必去手動(dòng)實(shí)現(xiàn),Navigation在底部幫我們實(shí)現(xiàn)了灶平,我們只需要按照Navigation的模板去實(shí)現(xiàn)就好了冬竟。

Fragment的切換

  findNavController().navigate(R.id.registerFragment, null, navOption)

Fragment的切換很簡(jiǎn)單,一行代碼就可以搞定民逼,不過我這是kotlin的寫法泵殴,Java的寫法稍微復(fù)雜一點(diǎn)。

NavigationController  navigationController  = Navigation.findNavController(it)
navigationController.navigate(R.id.registerFragment, null, navOption)

但是不管是Java寫法還是kotlin寫法底層都是一樣的拼苍,這里需要用到一個(gè)很重要的東西NavigationController笑诅,顧名思義NavigationController是用來控制Navigation的操作的,最終我們切換Fragment就是依靠它來實(shí)現(xiàn)的疮鲫。NavigationController提供了一個(gè)方法navigate吆你,navigate的重載方法有很多,這里簡(jiǎn)單介紹幾個(gè):

// 通過傳遞我們要跳轉(zhuǎn)的Fragment來實(shí)現(xiàn)切換
// resId:目標(biāo)Fragment的id
public void navigate(@IdRes int resId) {
        navigate(resId, null);
}

// 通過傳遞我們要跳轉(zhuǎn)的Fragment來實(shí)現(xiàn)切換
// resId:目標(biāo)Fragment的id
// Bundle args:傳遞給目標(biāo)Fragment的參數(shù)
public void navigate(@IdRes int resId, @Nullable Bundle args) {
        navigate(resId, args, null);
}

// 通過傳遞我們要跳轉(zhuǎn)的Fragment來實(shí)現(xiàn)切換
// resId:目標(biāo)Fragment的id
// Bundle args:傳遞給目標(biāo)Fragment的參數(shù)
// NavOptions navOptions:Fragment切換時(shí)候的過渡動(dòng)畫
public void navigate(@IdRes int resId, @Nullable Bundle args,
            @Nullable NavOptions navOptions) {
        navigate(resId, args, navOptions, null);
}

這個(gè)比較簡(jiǎn)單俊犯,一看就懂了妇多,關(guān)于怎么傳參放到下面去講,我們?cè)谶@里先看看怎么實(shí)現(xiàn)動(dòng)畫

  val navOption = navOptions {
                anim {
                    enter = R.anim.common_slide_in_right
                    exit = R.anim.common_slide_out_left
                    popEnter = R.anim.common_slide_in_left
                    popExit = R.anim.common_slide_out_right
                }
            }

實(shí)現(xiàn)動(dòng)畫也很簡(jiǎn)單燕侠,創(chuàng)建一個(gè)NavOptions在里面設(shè)置好我們想要的動(dòng)畫效果
common_slide_in_right

<set xmlns:android="http://schemas.android.com/apk/res/android">

    <translate
        android:duration="200"
        android:fromXDelta="100%"
        android:fromYDelta="0%"
        android:toXDelta="0%"
        android:toYDelta="0%" />
</set>

common_slide_out_left

<set xmlns:android="http://schemas.android.com/apk/res/android">

    <translate
        android:duration="200"
        android:fromXDelta="0%"
        android:fromYDelta="0%"
        android:toXDelta="-100%"
        android:toYDelta="0%" />
</set>

common_slide_in_left

<set xmlns:android="http://schemas.android.com/apk/res/android">

    <translate
        android:duration="200"
        android:fromXDelta="-100%"
        android:fromYDelta="0%"
        android:toXDelta="0%"
        android:toYDelta="0%" />
</set>

common_slide_out_right

<set xmlns:android="http://schemas.android.com/apk/res/android">

    <translate
        android:duration="200"
        android:fromXDelta="0%"
        android:fromYDelta="0%"
        android:toXDelta="100%"
        android:toYDelta="0%" />
</set>

Fragment的傳參
Fragment的傳參方式也有兩種:

  • 方式一:常規(guī)傳參
// 傳遞參數(shù)
val bundle = Bundle()
bundle.putString("loginInfo","steven")
findNavController().navigate(R.id.loginFragment,bundle,navOption)

// 獲取參數(shù)
 val bundle = arguments
if (bundle!=null){
   val loginTag = bundle.getString("loginInfo")
   view.findViewById<TextView>(R.id.login_info).text = loginTag
}
  • 方式二:使用系統(tǒng)推薦的插件Safe Args
    Safe Args使用步驟:
    (1)添加依賴
    在項(xiàng)目的builder.gradle下面添加
    dependencies {
        ...
        classpath "androidx.navigation:navigation-safe-args-gradle-plugin:2.3.0"
    }

(2)在主module的builder.gradle下面添加

plugins {
    ...
    id 'androidx.navigation.safeargs'
}

(3)在navigation文件夾下面我們創(chuàng)建的文件下面要跳轉(zhuǎn)的目標(biāo)Fragment下面設(shè)置argument。

<fragment
        android:id="@+id/loginFragment"
        android:name="com.jack.androidjetpack.login.LoginFragment"
        android:label="fragment_login"
        tools:layout="@layout/fragment_login">
        <argument
            // 傳遞的參數(shù)key 
            android:name="loginInfo"
           // 默認(rèn)值
            android:defaultValue="defaultValue"
           // 參數(shù)對(duì)應(yīng)的類型
            app:argType="string" />
</fragment>

(4)Build-> Make Project
完成后會(huì)發(fā)現(xiàn)在我們的app->build->generated->source->navigation-args->debug->com.jack.androidjetpack.login文件夾下面有一個(gè)LoginFragmentArgs文件,而這個(gè)文件正是用來傳遞參數(shù)使用的唤锉。
(5)創(chuàng)建我們的bundle并進(jìn)行傳遞

    val bundle = LoginFragmentArgs.Builder().setLoginInfo("jack").build().toBundle()

(6)獲取我們傳遞的值

  val bundle = arguments
        if (bundle != null) {
            val loginTag = LoginFragmentArgs.fromBundle(bundle).loginInfo
            view.findViewById<TextView>(R.id.login_info).text = loginTag
        }

這樣通過插件傳值就結(jié)束了骗露。

可以看到遭居,可能會(huì)有人會(huì)疑惑,用Bundle不是更簡(jiǎn)單些嗎,Safe Args 傳遞方式不僅編碼復(fù)雜,還要安裝它的插件刹淌,不會(huì)太麻煩嗎?既然是Google推薦讥耗,那當(dāng)然是有道理的這里不再啰嗦有勾,直接貼上官方說明

Safe Args.png

感覺其實(shí)官方就說了一句話:使用Safe Args可以確保數(shù)據(jù)安全。但是說實(shí)話我還沒有太明白和我們以往直接通過bundle有什么區(qū)別古程。知道的同學(xué)可以在下面留言大家探討探討蔼卡。

到這里,關(guān)于Navigation的基礎(chǔ)知識(shí)就結(jié)束了籍琳,下一篇我們看看Navigation在實(shí)際項(xiàng)目中的應(yīng)用到底有哪些。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末贷祈,一起剝皮案震驚了整個(gè)濱河市趋急,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌势誊,老刑警劉巖呜达,帶你破解...
    沈念sama閱讀 216,692評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異粟耻,居然都是意外死亡查近,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,482評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門挤忙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來霜威,“玉大人,你說我怎么就攤上這事册烈「昶茫” “怎么了?”我有些...
    開封第一講書人閱讀 162,995評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵赏僧,是天一觀的道長(zhǎng)大猛。 經(jīng)常有香客問我,道長(zhǎng)淀零,這世上最難降的妖魔是什么挽绩? 我笑而不...
    開封第一講書人閱讀 58,223評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮驾中,結(jié)果婚禮上唉堪,老公的妹妹穿的比我還像新娘模聋。我一直安慰自己,他們只是感情好巨坊,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,245評(píng)論 6 388
  • 文/花漫 我一把揭開白布撬槽。 她就那樣靜靜地躺著,像睡著了一般趾撵。 火紅的嫁衣襯著肌膚如雪侄柔。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,208評(píng)論 1 299
  • 那天占调,我揣著相機(jī)與錄音暂题,去河邊找鬼。 笑死究珊,一個(gè)胖子當(dāng)著我的面吹牛薪者,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播剿涮,決...
    沈念sama閱讀 40,091評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼言津,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了取试?” 一聲冷哼從身側(cè)響起悬槽,我...
    開封第一講書人閱讀 38,929評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎瞬浓,沒想到半個(gè)月后初婆,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,346評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡猿棉,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,570評(píng)論 2 333
  • 正文 我和宋清朗相戀三年磅叛,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片萨赁。...
    茶點(diǎn)故事閱讀 39,739評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡弊琴,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出杖爽,到底是詐尸還是另有隱情访雪,我是刑警寧澤,帶...
    沈念sama閱讀 35,437評(píng)論 5 344
  • 正文 年R本政府宣布掂林,位于F島的核電站臣缀,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏泻帮。R本人自食惡果不足惜精置,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,037評(píng)論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望锣杂。 院中可真熱鬧脂倦,春花似錦番宁、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,677評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至火欧,卻和暖如春棋电,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背苇侵。 一陣腳步聲響...
    開封第一講書人閱讀 32,833評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工赶盔, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人榆浓。 一個(gè)月前我還...
    沈念sama閱讀 47,760評(píng)論 2 369
  • 正文 我出身青樓于未,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親陡鹃。 傳聞我的和親對(duì)象是個(gè)殘疾皇子烘浦,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,647評(píng)論 2 354

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