Android Navigation組件(二)

Safe Args

Safe Args是官方提供的一個(gè)gradle插件來(lái)生成一些代碼幫助在fragment之間傳值亲善,顧名思義就是要保證值傳遞的安全性,因?yàn)閎undle傳值時(shí)是通過(guò)key-value的形式逗柴,在兩個(gè)頁(yè)面之間傳值很難形式固定的約束蛹头,下個(gè)頁(yè)面接受值的時(shí)候總需要做各種判斷,防止值不存在或沒傳遞。使用Safe Args之后就不會(huì)存在該問(wèn)題了渣蜗。但是Safe Args還是基于bundle傳值屠尊,所以還是建議一次傳遞小量的數(shù)據(jù)。

Safe Args的使用方式

在navigation graph文件中聲明action和argument
例如, 在第一個(gè)fragment中創(chuàng)建action

<action
     android:id="@+id/next_action"
     app:destination="@id/navigation_detail"
/>

在第二個(gè)fragment創(chuàng)建argument

   <argument
            android:name="testString"
            app:argType="string"
            app:nullable="true"
            android:defaultValue="@null"
            />

android:defaultValue為必須聲明耕拷,否則編譯時(shí)會(huì)報(bào)錯(cuò)
跳轉(zhuǎn)頁(yè)面時(shí)使用:

val directions = HomeFragmentDirections.nextAction("testString")
findNavController().navigate(directions)

接受值:

val safeArgs: DetailFragmentArgs by navArgs()
text_home.text = safeArgs.testString

Safe Arg原理

在項(xiàng)目中添加了Safe Arg插件之后讼昆,在navigation graph添加了action和argument之后,下次編譯的時(shí)候就會(huì)生成對(duì)應(yīng)的輔助類骚烧。先看下Directions:

class HomeFragmentDirections private constructor() {
  private data class NextAction(
    val testString: String? = null
  ) : NavDirections {
    override fun getActionId(): Int = R.id.next_action

    override fun getArguments(): Bundle {
      val result = Bundle()
      result.putString("testString", this.testString)
      return result
    }
  }

  companion object {
    fun nextAction(testString: String? = null): NavDirections = NextAction(testString)
  }
}

Directions中定義了一個(gè)對(duì)應(yīng)action名字的類名浸赫,綁定了對(duì)應(yīng)的action Id, 賦值了聲明的Argument, 然后通過(guò)靜態(tài)方法將NavDirections實(shí)例化返回了出去赃绊。結(jié)構(gòu)比較簡(jiǎn)單既峡,一看就懂。

Args

data class DetailFragmentArgs(
  val testString: String? = null
) : NavArgs {
  fun toBundle(): Bundle {
    val result = Bundle()
    result.putString("testString", this.testString)
    return result
  }

  companion object {
    @JvmStatic
    fun fromBundle(bundle: Bundle): DetailFragmentArgs {
      bundle.setClassLoader(DetailFragmentArgs::class.java.classLoader)
      val __testString : String?
      if (bundle.containsKey("testString")) {
        __testString = bundle.getString("testString")
      } else {
        __testString = null
      }
      return DetailFragmentArgs(__testString)
    }
  }
}

Args輔助類就更加簡(jiǎn)單了碧查,提供了fromBundle和toBundle兩個(gè)方法运敢,最終還是通過(guò)Bundle傳遞過(guò)去的。
在fromBundle中調(diào)用了setClassLoader的方法忠售,這個(gè)是什么時(shí)候用的呢传惠?
看下接受值的時(shí)候獲取args的地方:

val safeArgs: DetailFragmentArgs by navArgs()

是通過(guò)navArgs方法獲取到的,看下navArg方法的源碼:

@MainThread
inline fun <reified Args : NavArgs> Fragment.navArgs() = NavArgsLazy(Args::class) {
    arguments ?: throw IllegalStateException("Fragment $this has null arguments")
}

一個(gè)Fragment的內(nèi)聯(lián)擴(kuò)展方法档痪,最終獲取到了NavArgsLazy類中的value, NavArgsLazy是Kotlin的lazy的一個(gè)子類,里面的泛型是NavArgs涉枫。DetailFragmentArgs的父類就是NavArgs. NavArgsLazy類的實(shí)現(xiàn):

internal val methodSignature = arrayOf(Bundle::class.java)
internal val methodMap = ArrayMap<KClass<out NavArgs>, Method>()

class NavArgsLazy<Args : NavArgs>(
    private val navArgsClass: KClass<Args>,
    private val argumentProducer: () -> Bundle
) : Lazy<Args> {
    private var cached: Args? = null

    override val value: Args
        get() {
            var args = cached
            if (args == null) {
                val arguments = argumentProducer()
                val method: Method = methodMap[navArgsClass]
                    ?: navArgsClass.java.getMethod("fromBundle", *methodSignature).also { method ->
                        // Save a reference to the method
                        methodMap[navArgsClass] = method
                    }

                @Suppress("UNCHECKED_CAST")
                args = method.invoke(null, arguments) as Args
                cached = args
            }
            return args
        }

    override fun isInitialized() = cached != null
}

可以看到是在Lazy懶加載的基礎(chǔ)上添加了一層緩存,使用cached緩存了一次腐螟,如果緩存有則直接返回愿汰。
如果沒有緩存則從arguments中生成。先從argumentProducer獲取fragment的arguments對(duì)象乐纸,然后通過(guò)反射fromBundle方法衬廷,生成對(duì)應(yīng)的實(shí)例。又緩存了一次NavArgs的Method汽绢,為了提高性能吗跋。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市宁昭,隨后出現(xiàn)的幾起案子跌宛,更是在濱河造成了極大的恐慌,老刑警劉巖积仗,帶你破解...
    沈念sama閱讀 216,591評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件疆拘,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡寂曹,警方通過(guò)查閱死者的電腦和手機(jī)哎迄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門回右,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人漱挚,你說(shuō)我怎么就攤上這事翔烁。” “怎么了旨涝?”我有些...
    開封第一講書人閱讀 162,823評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵蹬屹,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我白华,道長(zhǎng)哩治,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,204評(píng)論 1 292
  • 正文 為了忘掉前任衬鱼,我火速辦了婚禮,結(jié)果婚禮上憔杨,老公的妹妹穿的比我還像新娘鸟赫。我一直安慰自己,他們只是感情好消别,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,228評(píng)論 6 388
  • 文/花漫 我一把揭開白布抛蚤。 她就那樣靜靜地躺著,像睡著了一般寻狂。 火紅的嫁衣襯著肌膚如雪岁经。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,190評(píng)論 1 299
  • 那天蛇券,我揣著相機(jī)與錄音缀壤,去河邊找鬼。 笑死纠亚,一個(gè)胖子當(dāng)著我的面吹牛塘慕,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蒂胞,決...
    沈念sama閱讀 40,078評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼图呢,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了骗随?” 一聲冷哼從身側(cè)響起蛤织,我...
    開封第一講書人閱讀 38,923評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎鸿染,沒想到半個(gè)月后指蚜,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,334評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡牡昆,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,550評(píng)論 2 333
  • 正文 我和宋清朗相戀三年姚炕,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了摊欠。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,727評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡柱宦,死狀恐怖些椒,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情掸刊,我是刑警寧澤免糕,帶...
    沈念sama閱讀 35,428評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站忧侧,受9級(jí)特大地震影響石窑,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蚓炬,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,022評(píng)論 3 326
  • 文/蒙蒙 一松逊、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧肯夏,春花似錦经宏、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至徊都,卻和暖如春沪斟,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背暇矫。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工主之, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人李根。 一個(gè)月前我還...
    沈念sama閱讀 47,734評(píng)論 2 368
  • 正文 我出身青樓杀餐,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親朱巨。 傳聞我的和親對(duì)象是個(gè)殘疾皇子史翘,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,619評(píng)論 2 354