Android Navigation的四大要點(diǎn)你都知道嗎粹胯?

image

在JetPack中有一個(gè)組件是Navigation,顧名思義它是一個(gè)頁面導(dǎo)航組件蒋困,相對于其他的第三方導(dǎo)航盾似,不同的是它是專門為Fragment的頁面管理所設(shè)計(jì)的。它對于單個(gè)Activity的App來說非常有用雪标,因?yàn)橐砸粋€(gè)Activity為架構(gòu)的App頁面的呈現(xiàn)都是通過不同的Fragment來展示的零院。所以對于Fragment的管理至關(guān)重要。通常的實(shí)現(xiàn)都要自己維護(hù)Fragment之間的棧關(guān)系村刨,同時(shí)要對Fragment的Transaction操作非常熟悉告抄。為了降低使用與維護(hù)成本,所以就有了今天的主角Navigation嵌牺。

如果你對JetPack的其它組件感興趣打洼,推薦你閱讀我之前的系列文章,本篇文章目前為JetPack系列的最后一篇逆粹。

Android Architecture Components Part1:Room
Android Architecture Components Part2:LiveData
Android Architecture Components Part3:Lifecycle
Android Architecture Components Part4:ViewModel
Paging在RecyclerView中的應(yīng)用募疮,有這一篇就夠了
WorkManager從入門到實(shí)踐,有這一篇就夠了

對于Navigation的使用僻弹,我將其歸納于以下四點(diǎn):

  • Navigation的基本配置
  • Navigation的跳轉(zhuǎn)與數(shù)據(jù)傳遞
  • Navigation的頁面動(dòng)畫
  • Navigation的deepLink

配置

在使用之前需要引入Navigation的依賴阿浓,然后我們需要為Navigation創(chuàng)建一個(gè)配置文件,它將位于res/navigation/nav_graph.xml蹋绽。為了方便理解文章中的代碼芭毙,我寫了一個(gè)Demo,大家可以通過Android精華錄查看卸耘。

在我的Demo中打開nav_graph.xml你將清晰的看到它們頁面間的關(guān)系紐帶

一共有6個(gè)頁面退敦,最左邊的為程序入口頁面,它們間的線條指向?yàn)樗鼈冮g可跳轉(zhuǎn)的方向蚣抗。

我們再來看它們的xm配置??

<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/nav_graph"
    app:startDestination="@id/welcome_fragment">
 
    <fragment
        android:id="@+id/welcome_fragment"
        android:name="com.idisfkj.androidapianalysis.navigation.fragment.WelcomeFragment"
        android:label="welcome_fragment"
        tools:layout="@layout/fragment_welcome">
 
        <action
            android:id="@+id/action_go_to_register_page"
            app:destination="@id/register_fragment" />
 
        <action
            android:id="@+id/action_go_to_order_list_page"
            app:destination="@id/order_list_fragment"/>
 
    </fragment>
 
    <fragment
        android:id="@+id/register_fragment"
        android:name="com.idisfkj.androidapianalysis.navigation.fragment.RegisterFragment"
        android:label="register_fragment"
        tools:layout="@layout/fragment_register">
 
        <action
            android:id="@+id/action_go_to_shop_list_page"
            app:destination="@id/shop_list_fragment" />
 
    </fragment>
     
    ...
</navigation>

頁面標(biāo)簽主要包含navigation侈百、fragment與action

  • navigation: 定義導(dǎo)航棧,可以進(jìn)行嵌套定義翰铡,各個(gè)navigation相互獨(dú)立设哗。它有一個(gè)屬性startDestination用來定義導(dǎo)航棧的根入口fragment
  • fragment: 顧名思義fragment頁面。通過name屬性來定義關(guān)聯(lián)的fragment
  • action: 意圖两蟀,可以理解為Intent,即跳轉(zhuǎn)的行為震缭。通過destination來關(guān)聯(lián)將要跳轉(zhuǎn)的目標(biāo)fragment赂毯。

以上是nav_graph.xml的基本配置。

在配置完之后,我們還需要將其關(guān)聯(lián)到Activity中党涕。因?yàn)樗械腇ragment都離不開Activity烦感。

Navigation為我們提供了兩個(gè)配置參數(shù): defaultNavHost與navGraph,所以在Activity的xml中需要如下配置??

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
    android:background="@android:color/background_light"
    android:orientation="vertical"
    tools:context=".navigation.NavigationMainActivity">
 
    <fragment
        android:id="@+id/nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:defaultNavHost="true"
        app:navGraph="@navigation/nav_graph" />
 
</LinearLayout>
  • defaultNavHost: 將設(shè)備的回退操作進(jìn)行攔截膛堤,并將其交給Navigation進(jìn)行管理手趣。
  • navGraph: Navigation的配置文件,即上面我們配置的nav_graph.xml文件

除此之外肥荔,fragment的name屬性必須為NavHostFragment绿渣,因?yàn)樗鼤?huì)作為我們配置的所有fragment的管理者。具體通過內(nèi)部的NavController中的NavigationProvider來獲取Navigator抽象實(shí)例燕耿,具體實(shí)現(xiàn)類是FragmentNavigator中符,所以最終通過它的navigate方法進(jìn)行創(chuàng)建我們配置的Fragment,并且添加到NavHostFragment的FrameLayout根布局中誉帅。

此時(shí)如果我們直接運(yùn)行程序后發(fā)現(xiàn)已經(jīng)可以看到入口頁面WelcomeFragment

但點(diǎn)擊register等操作你會(huì)發(fā)現(xiàn)點(diǎn)擊跳轉(zhuǎn)無效淀散,所以接下來我們需要為其添加跳轉(zhuǎn)

跳轉(zhuǎn)

由于我們之前已經(jīng)在nav_graph.xml中定義了action,所以跳轉(zhuǎn)的接入非常方便蚜锨,每一個(gè)action的關(guān)聯(lián)跳轉(zhuǎn)只需一行代碼??

class WelcomeFragment : Fragment() {
 
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        return inflater.inflate(R.layout.fragment_welcome, container, false).apply {
            register_bt.setOnClickListener(Navigation.createNavigateOnClickListener(R.id.action_go_to_register_page))
            stroll_bt.setOnClickListener(Navigation.createNavigateOnClickListener(R.id.action_go_to_order_list_page))
        }
    }
}

代碼中的id就是配置的action的id档插,內(nèi)部原理是先獲取到對應(yīng)的NavController,通過點(diǎn)擊的view來遍歷找到最外層的parent view亚再,因?yàn)樽钔鈱拥膒arent view會(huì)在配置文件導(dǎo)入時(shí)郭膛,即NavHostFragment中的onViewCreated方法中進(jìn)行關(guān)聯(lián)對應(yīng)的NavController??

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        if (!(view instanceof ViewGroup)) {
            throw new IllegalStateException("created host view " + view + " is not a ViewGroup");
        }
        Navigation.setViewNavController(view, mNavController);
        // When added programmatically, we need to set the NavController on the parent - i.e.,
        // the View that has the ID matching this NavHostFragment.
        if (view.getParent() != null) {
            View rootView = (View) view.getParent();
            if (rootView.getId() == getId()) {
                Navigation.setViewNavController(rootView, mNavController);
            }
        }
    }

然后再調(diào)用navigate進(jìn)行頁面跳轉(zhuǎn)處理,最終通過FragmentTransaction的replace進(jìn)行Fragment替換??

    -------------- NavController ------------------
     
    private void navigate(@NonNull NavDestination node, @Nullable Bundle args,
            @Nullable NavOptions navOptions, @Nullable Navigator.Extras navigatorExtras) {
        boolean popped = false;
        if (navOptions != null) {
            if (navOptions.getPopUpTo() != -1) {
                popped = popBackStackInternal(navOptions.getPopUpTo(),
                        navOptions.isPopUpToInclusive());
            }
        }
        Navigator<NavDestination> navigator = mNavigatorProvider.getNavigator(
                node.getNavigatorName());
        Bundle finalArgs = node.addInDefaultArgs(args);
        # ---- 關(guān)鍵代碼 -------
        NavDestination newDest = navigator.navigate(node, finalArgs,
                navOptions, navigatorExtras);
        ....
    }
     
    -------------- FragmentNavigator ------------------
 
    public NavDestination navigate(@NonNull Destination destination, @Nullable Bundle args,
            @Nullable NavOptions navOptions, @Nullable Navigator.Extras navigatorExtras) {
        if (mFragmentManager.isStateSaved()) {
            Log.i(TAG, "Ignoring navigate() call: FragmentManager has already"
                    + " saved its state");
            return null;
        }
        String className = destination.getClassName();
        if (className.charAt(0) == '.') {
            className = mContext.getPackageName() + className;
        }
        final Fragment frag = instantiateFragment(mContext, mFragmentManager,
                className, args);
        frag.setArguments(args);
        final FragmentTransaction ft = mFragmentManager.beginTransaction();
 
        int enterAnim = navOptions != null ? navOptions.getEnterAnim() : -1;
        int exitAnim = navOptions != null ? navOptions.getExitAnim() : -1;
        int popEnterAnim = navOptions != null ? navOptions.getPopEnterAnim() : -1;
        int popExitAnim = navOptions != null ? navOptions.getPopExitAnim() : -1;
        if (enterAnim != -1 || exitAnim != -1 || popEnterAnim != -1 || popExitAnim != -1) {
            enterAnim = enterAnim != -1 ? enterAnim : 0;
            exitAnim = exitAnim != -1 ? exitAnim : 0;
            popEnterAnim = popEnterAnim != -1 ? popEnterAnim : 0;
            popExitAnim = popExitAnim != -1 ? popExitAnim : 0;
            ft.setCustomAnimations(enterAnim, exitAnim, popEnterAnim, popExitAnim);
        }
 
        # ------ 關(guān)鍵代碼 ------
        ft.replace(mContainerId, frag);
        ft.setPrimaryNavigationFragment(frag);
        ...
    }

源碼就分析到這里了针余,如果需要深入了解饲鄙,建議閱讀NavHostFragmentNavController圆雁、NavigatorProviderFragmentNavigator

傳參

以上是頁面的無參跳轉(zhuǎn)忍级,那么對于有參跳轉(zhuǎn)又該如何呢?

大家想到的應(yīng)該都是bundle伪朽,將傳遞的數(shù)據(jù)填入到bundle中轴咱。沒錯(cuò)Navigator提供的navigate方法可以進(jìn)行傳遞bundle數(shù)據(jù)??

findNavController().navigate(R.id.action_go_to_shop_detail_page, bundleOf("title" to "I am title"))

這種傳統(tǒng)的方法在傳遞數(shù)據(jù)類型上并不能保證其一致性,為了減少人為精力上的錯(cuò)誤烈涮,Navigation提供了一個(gè)Gradle插件朴肺,專門用來保證數(shù)據(jù)的類型安全。

使用它的話需要引入該插件坚洽,方式如下??

buildscript {
    repositories {
        google()
    }
    dependencies {
        def nav_version = "2.1.0"
        classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version"
    }
}

最后再到app下的build.gradle中引入該插件??

apply plugin: "androidx.navigation.safeargs.kotlin"

而它的使用方式也很簡單戈稿,首先參數(shù)需要在nav_graph.xml中進(jìn)行配置。??

    <fragment
        android:id="@+id/shop_list_fragment"
        android:name="com.idisfkj.androidapianalysis.navigation.fragment.ShopListFragment"
        android:label="shop_list_fragment"
        tools:layout="@layout/fragment_shop_list">
 
        <action
            android:id="@+id/action_go_to_shop_detail_page"
            app:destination="@id/shop_detail_fragment">
 
            <argument
                android:name="title"
                app:argType="string" />
 
        </action>
 
    </fragment>
 
    <fragment
        android:id="@+id/shop_detail_fragment"
        android:name="com.idisfkj.androidapianalysis.navigation.fragment.ShopDetailFragment"
        android:label="shop_detail_fragment"
        tools:layout="@layout/fragment_shop_detail">
 
        <action
            android:id="@+id/action_go_to_cart_page"
            app:destination="@id/cart_fragment"
            app:popUpTo="@id/cart_fragment"
            app:popUpToInclusive="true" />
 
        <argument
            android:name="title"
            app:argType="string" />
 
    </fragment>

現(xiàn)在我們從ShopListFragment跳轉(zhuǎn)到ShopDetailFragment讶舰,需要在ShopListFragment的對應(yīng)action中添加argument鞍盗,聲明對應(yīng)的參數(shù)類型與參數(shù)名需了,也可以通過defaultValue定義參數(shù)的默認(rèn)值與nullable標(biāo)明是否可空。對應(yīng)的ShopDetailFragment接收參數(shù)也是一樣般甲。

另外popUpTo與popUpToInclusive屬性是為了實(shí)現(xiàn)跳轉(zhuǎn)到CartFragment時(shí)達(dá)到SingleTop效果肋乍。

下面我們直接看在代碼中如何使用這些配置的參數(shù),首先是在ShopListFragment中??

holder.item.setOnClickListener(Navigation.createNavigateOnClickListener(ShopListFragmentDirections.actionGoToShopDetailPage(shopList[position])))

還是創(chuàng)建一個(gè)createNavigateOnClickListener敷存,只不過現(xiàn)在傳遞的不再是跳轉(zhuǎn)的action id墓造,而是通過插件自動(dòng)生成的ShopListFragmentDirections.actionGoToShopDetailPage方法。一旦我們?nèi)缟吓渲昧薬rgument锚烦,插件就會(huì)自動(dòng)生成一個(gè)以[類名]+Directions的類觅闽,而自動(dòng)生成的類本質(zhì)是做了跳轉(zhuǎn)與參數(shù)的封裝,源碼如下??

class ShopListFragmentDirections private constructor() {
    private data class ActionGoToShopDetailPage(val title: String) : NavDirections {
        override fun getActionId(): Int = R.id.action_go_to_shop_detail_page
 
        override fun getArguments(): Bundle {
            val result = Bundle()
            result.putString("title", this.title)
            return result
        }
    }
 
    companion object {
        fun actionGoToShopDetailPage(title: String): NavDirections = ActionGoToShopDetailPage(title)
    }
}

本質(zhì)是將action id與argument封裝成一個(gè)NavDirections挽牢,內(nèi)部通過解析它來獲取action id與argument谱煤,從而執(zhí)行跳轉(zhuǎn)。

而對于接受方ShopDetailFragment禽拔,插件頁面自動(dòng)幫我們生成一個(gè)ShopDetailFragmentArgs刘离,以[類名]+Args的類。所以我們需要做的也非常簡單??

class ShopDetailFragment : Fragment() {
 
    private val args by navArgs<ShopDetailFragmentArgs>()
 
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        return inflater.inflate(R.layout.fragment_shop_detail, container, false).apply {
            title.text = args.title
            add_cart.setOnClickListener(Navigation.createNavigateOnClickListener(ShopDetailFragmentDirections.actionGoToCartPage()))
        }
    }

}

通過navArgs來獲取ShopDetailFragmentArgs對象睹栖,它其中包含了傳遞過來的頁面數(shù)據(jù)硫惕。

動(dòng)畫

在action中不僅可以配置跳轉(zhuǎn)的destination,還可以定義對應(yīng)頁面的轉(zhuǎn)場動(dòng)畫野来,使用非常簡單??

<?xml version="1.0" encoding="utf-8"?>
<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/nav_graph"
    app:startDestination="@id/welcome_fragment">
 
    <fragment
        android:id="@+id/welcome_fragment"
        android:name="com.idisfkj.androidapianalysis.navigation.fragment.WelcomeFragment"
        android:label="welcome_fragment"
        tools:layout="@layout/fragment_welcome">
 
        <action
            android:id="@+id/action_go_to_register_page"
            app:destination="@id/register_fragment"
            app:enterAnim="@anim/slide_in_right"
            app:exitAnim="@anim/slide_in_left"
            app:popEnterAnim="@anim/slide_out_left"
            app:popExitAnim="@anim/slide_out_right" />
 
        <action
            android:id="@+id/action_go_to_order_list_page"
            app:destination="@id/order_list_fragment"
            app:enterAnim="@anim/slide_in_right"
            app:exitAnim="@anim/slide_in_left"
            app:popEnterAnim="@anim/slide_out_left"
            app:popExitAnim="@anim/slide_out_right" />
 
    </fragment>
    ...
</navigation>

對應(yīng)四個(gè)動(dòng)畫配置參數(shù)

  • enterAnim: 配置進(jìn)場時(shí)目標(biāo)頁面動(dòng)畫
  • exitAnim: 配置進(jìn)場時(shí)原頁面動(dòng)畫
  • popEnterAnim: 配置回退pop時(shí)目標(biāo)頁面動(dòng)畫
  • popExitAnim: 配置回退pop時(shí)原頁面動(dòng)畫

通過上面的配置你可以看到如下效果??

deepLink

我們回想一下對于多個(gè)Activity我需要實(shí)現(xiàn)deepLink效果恼除,應(yīng)該都是在AndroidManifest.xml中進(jìn)行配置scheme、host等曼氛。而對于單個(gè)Activity也需要實(shí)現(xiàn)類似的效果豁辉,Navigation也提供了對應(yīng)的實(shí)現(xiàn),而且操作更簡單舀患。

Navigation提供的是deepLink標(biāo)簽徽级,可以直接在nav_graph.xml進(jìn)行配置,例如??

    <fragment
        android:id="@+id/register_fragment"
        android:name="com.idisfkj.androidapianalysis.navigation.fragment.RegisterFragment"
        android:label="register_fragment"
        tools:layout="@layout/fragment_register">
 
        <action
            android:id="@+id/action_go_to_shop_list_page"
            app:destination="@id/shop_list_fragment"
            app:enterAnim="@anim/slide_in_right"
            app:exitAnim="@anim/slide_in_left"
            app:popEnterAnim="@anim/slide_out_left"
            app:popExitAnim="@anim/slide_out_right" />
 
        <deepLink app:uri="api://register/" />
 
    </fragment>

上面通過deepLink我配置了一個(gè)跳轉(zhuǎn)到注冊頁RegisterFragment聊浅,寫法非常簡單餐抢,直接配置uri即可;同時(shí)還可以通過占位符配置傳遞參數(shù)低匙,例如??

<deepLink app:uri="api://register/{id}" />

這時(shí)我們就可以在注冊頁面通過argument獲取key為id的數(shù)據(jù)旷痕。

當(dāng)然要實(shí)現(xiàn)上面的效果,我們還需要一個(gè)前提顽冶,需要在AndroidManifest.xml中將我們的deepLink進(jìn)行配置欺抗,在Activity中使用nav-graph標(biāo)簽??

    <application
        ...
        android:theme="@style/AppTheme">
        <activity android:name=".navigation.NavigationMainActivity" >
            <intent-filter>
                <action android:name="android.intent.action.VIEW"/>
                <action android:name="android.intent.action.MAIN" />
 
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            <nav-graph android:value="@navigation/nav_graph"/>
        </activity>
        ...
    </application>

現(xiàn)在只需將文章中的demo安裝到手機(jī)上,再點(diǎn)擊下面的link

jump to register api

之后就會(huì)啟動(dòng)App强重,并定位到注冊界面绞呈。是不是非常簡單呢团滥?

最后我們再來看下效果??

有關(guān)Navigation暫時(shí)就到這里,通過這篇文章报强,希望你能夠熟悉運(yùn)用Navigation,并且發(fā)現(xiàn)單Activity的魅力拱燃。

如果這篇文章對你有所幫助秉溉,你可以順手點(diǎn)贊、關(guān)注一波碗誉,這是對我最大的鼓勵(lì)召嘶!

項(xiàng)目地址

Android精華錄

該庫的目的是結(jié)合詳細(xì)的Demo來全面解析Android相關(guān)的知識點(diǎn), 幫助讀者能夠更快的掌握與理解所闡述的要點(diǎn)

Android精華錄

Android補(bǔ)給站
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市哮缺,隨后出現(xiàn)的幾起案子弄跌,更是在濱河造成了極大的恐慌,老刑警劉巖尝苇,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件铛只,死亡現(xiàn)場離奇詭異,居然都是意外死亡糠溜,警方通過查閱死者的電腦和手機(jī)淳玩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來非竿,“玉大人蜕着,你說我怎么就攤上這事『熘” “怎么了承匣?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長锤悄。 經(jīng)常有香客問我韧骗,道長,這世上最難降的妖魔是什么铁蹈? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任宽闲,我火速辦了婚禮,結(jié)果婚禮上握牧,老公的妹妹穿的比我還像新娘容诬。我一直安慰自己,他們只是感情好沿腰,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布览徒。 她就那樣靜靜地躺著,像睡著了一般颂龙。 火紅的嫁衣襯著肌膚如雪习蓬。 梳的紋絲不亂的頭發(fā)上纽什,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天,我揣著相機(jī)與錄音躲叼,去河邊找鬼芦缰。 笑死,一個(gè)胖子當(dāng)著我的面吹牛枫慷,可吹牛的內(nèi)容都是我干的让蕾。 我是一名探鬼主播,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼或听,長吁一口氣:“原來是場噩夢啊……” “哼探孝!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起誉裆,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤顿颅,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后足丢,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體粱腻,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年霎桅,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了栖疑。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,039評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡滔驶,死狀恐怖遇革,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情揭糕,我是刑警寧澤萝快,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站著角,受9級特大地震影響揪漩,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜吏口,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一奄容、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧产徊,春花似錦昂勒、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春塘娶,著一層夾襖步出監(jiān)牢的瞬間归斤,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工刁岸, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留脏里,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓虹曙,卻偏偏與公主長得像膝宁,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子根吁,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評論 2 345

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