[{"data":1,"prerenderedAt":2065},["ShallowReactive",2],{"navigation_docs":3,"-android-compose-navigation":173,"-android-compose-navigation-surround":2060},[4,22,29,36,107,138,145,161],{"title":5,"icon":6,"path":7,"stem":8,"children":9},"博客","i-lucide-pen-line","\u002Fblog","0.blog",[10,12,17],{"title":5,"path":7,"stem":11,"icon":6},"0.blog\u002Findex",{"title":13,"path":14,"stem":15,"icon":16},"创建基于 UIKit 的原生 iOS 项目","\u002Fblog\u002Fcreate-uikit-ios-project","0.blog\u002F01.create-uikit-ios-project","i-lucide-app-window",{"title":18,"path":19,"stem":20,"icon":21},"Lockify：把账号和密码留在自己的手机里","\u002Fblog\u002Flockify","0.blog\u002F02.lockify","i-lucide-lock",{"title":23,"path":24,"stem":25,"children":26,"icon":28},"年度总结","\u002Fannual-review","1.annual-review\u002Findex",[27],{"title":23,"path":24,"stem":25,"icon":28},"i-lucide-git-commit",{"title":30,"path":31,"stem":32,"children":33,"icon":35},"故事","\u002Fstories","2.stories\u002Findex",[34],{"title":30,"path":31,"stem":32,"icon":35},"i-lucide-feather",{"title":37,"icon":38,"path":39,"stem":40,"children":41},"Android","i-simple-icons-android","\u002Fandroid","3.android",[42,44,49],{"title":37,"path":39,"stem":43,"icon":38},"3.android\u002Findex",{"title":45,"path":46,"stem":47,"icon":48},"初探Navigation","\u002Fandroid\u002Fcompose-navigation","3.android\u002F01.compose-navigation","i-lucide-route",{"title":50,"icon":51,"path":52,"stem":53,"children":54},"安卓代码加固","i-lucide-shield","\u002Fandroid\u002Fhidden-hardening","3.android\u002F02.hidden-hardening\u002Findex",[55,58,62,67,72,77,82,87,92,97,102],{"title":56,"path":52,"stem":53,"icon":57},"安卓代码加固：总览","i-lucide-map",{"title":59,"path":60,"stem":61,"icon":21},"安卓代码加固（1）：加密DEX","\u002Fandroid\u002Fhidden-hardening\u002Fencrypt-dex","3.android\u002F02.hidden-hardening\u002F01.encrypt-dex",{"title":63,"path":64,"stem":65,"icon":66},"安卓代码加固（2）：Native解密","\u002Fandroid\u002Fhidden-hardening\u002Fnative-decrypt","3.android\u002F02.hidden-hardening\u002F02.native-decrypt","i-lucide-cpu",{"title":68,"path":69,"stem":70,"icon":71},"安卓代码加固（3）：内存加载","\u002Fandroid\u002Fhidden-hardening\u002Fmemory-load","3.android\u002F02.hidden-hardening\u002F03.memory-load","i-lucide-memory-stick",{"title":73,"path":74,"stem":75,"icon":76},"安卓代码加固（4）：指令分发","\u002Fandroid\u002Fhidden-hardening\u002Fopcode-dispatch","3.android\u002F02.hidden-hardening\u002F04.opcode-dispatch","i-lucide-hash",{"title":78,"path":79,"stem":80,"icon":81},"安卓代码加固（5）：XOR混淆","\u002Fandroid\u002Fhidden-hardening\u002Fxor-obfuscate","3.android\u002F02.hidden-hardening\u002F05.xor-obfuscate","i-lucide-shuffle",{"title":83,"path":84,"stem":85,"icon":86},"安卓代码加固（6）：密钥外置","\u002Fandroid\u002Fhidden-hardening\u002Fkey-external","3.android\u002F02.hidden-hardening\u002F06.key-external","i-lucide-key",{"title":88,"path":89,"stem":90,"icon":91},"安卓代码加固（7）：依赖隔离","\u002Fandroid\u002Fhidden-hardening\u002Fdep-isolate","3.android\u002F02.hidden-hardening\u002F07.dep-isolate","i-lucide-layers",{"title":93,"path":94,"stem":95,"icon":96},"安卓代码加固（8）：构建校验","\u002Fandroid\u002Fhidden-hardening\u002Fbuild-verify","3.android\u002F02.hidden-hardening\u002F08.build-verify","i-lucide-shield-check",{"title":98,"path":99,"stem":100,"icon":101},"安卓代码加固（9）：防录屏","\u002Fandroid\u002Fhidden-hardening\u002Fflag-secure","3.android\u002F02.hidden-hardening\u002F09.flag-secure","i-lucide-eye-off",{"title":103,"path":104,"stem":105,"icon":106},"安卓代码加固（10）：ABI门禁","\u002Fandroid\u002Fhidden-hardening\u002Fabi-gate","3.android\u002F02.hidden-hardening\u002F10.abi-gate","i-lucide-git-compare",{"title":108,"icon":109,"path":110,"stem":111,"children":112},"iOS","i-simple-icons-apple","\u002Fios","4.ios",[113,115,120,125,129,133],{"title":108,"path":110,"stem":114,"icon":109},"4.ios\u002Findex",{"title":116,"path":117,"stem":118,"icon":119},"iOS面试题1","\u002Fios\u002Fios-interview1","4.ios\u002F01.ios-interview1","i-lucide-sparkles",{"title":121,"path":122,"stem":123,"icon":124},"设置启动图","\u002Fios\u002Fset-launch-screen","4.ios\u002F02.set-launch-screen","i-lucide-image",{"title":126,"path":127,"stem":128,"icon":48},"路由管理","\u002Fios\u002Frouting","4.ios\u002F03.routing",{"title":130,"path":131,"stem":132,"icon":91},"状态管理","\u002Fios\u002Fstate-management","4.ios\u002F04.state-management",{"title":134,"path":135,"stem":136,"icon":137},"事件传递","\u002Fios\u002Fevent-delivery","4.ios\u002F05.event-delivery","i-lucide-pointer",{"title":139,"path":140,"stem":141,"children":142,"icon":144},"Flutter","\u002Fflutter","5.flutter\u002Findex",[143],{"title":139,"path":140,"stem":141,"icon":144},"i-simple-icons-flutter",{"title":146,"icon":147,"path":148,"stem":149,"children":150,"page":160},"面试","i-lucide-graduation-cap","\u002Finterview","6.interview",[151,156],{"title":152,"path":153,"stem":154,"icon":155},"Flutter面试题1","\u002Finterview\u002Fflutter-interview1","6.interview\u002F01.flutter-interview1","i-lucide-boxes",{"title":157,"path":158,"stem":159,"icon":66},"Flutter面试题2","\u002Finterview\u002Fflutter-interview2","6.interview\u002F02.flutter-interview2",false,{"title":162,"icon":163,"path":164,"stem":165,"children":166},"算法学习","i-lucide-binary","\u002Falgorithm","7.algorithm",[167,169],{"title":162,"path":164,"stem":168,"icon":163},"7.algorithm\u002Findex",{"title":170,"path":171,"stem":172},"算法基础1：复杂度分析","\u002Falgorithm\u002Ftime-space-complexity","7.algorithm\u002F01.time-space-complexity",{"id":174,"title":45,"body":175,"description":2041,"extension":2042,"links":2043,"meta":2050,"navigation":2055,"path":46,"seo":2056,"stem":47,"__hash__":2059},"docs\u002F3.android\u002F01.compose-navigation.md",{"type":176,"value":177,"toc":2025},"minimark",[178,187,208,212,229,477,480,538,555,558,577,694,701,788,796,800,818,1105,1111,1114,1133,1235,1242,1295,1298,1303,1317,1369,1373,1380,1479,1490,1493,1496,1507,1560,1563,1580,1626,1639,1642,1660,1763,1964,1982,1985,2021],[179,180,181,182,186],"p",{},"用 Jetpack Navigation Compose（2.8+）的类型安全 API 在页面之间跳转：用 ",[183,184,185],"code",{},"@Serializable"," 路由替代字符串 path，在编译期发现拼写和参数类型错误。",[188,189,190,191,195,196,203,204,207],"note",{},"本文覆盖 ",[192,193,194],"strong",{},"Navigation 2"," 的 Compose 类型安全写法，这是当前多数项目的生产路径。Google 另有面向 Compose 的 ",[197,198,202],"a",{"href":199,"rel":200},"https:\u002F\u002Fdeveloper.android.com\u002Fguide\u002Fnavigation\u002Fnavigation-3",[201],"nofollow","Navigation 3","，新项目可以对照官方文档评估，不必和本文的 ",[183,205,206],{},"NavHost"," API 混用。",[209,210,211],"h2",{"id":211},"添加依赖",[179,213,214,215,218,219,222,223,228],{},"类型安全路由依赖两件事：",[183,216,217],{},"navigation-compose"," 2.8.0 及以上，以及 ",[192,220,221],{},"Kotlin Serialization"," 插件与 JSON 运行时。先在 Version Catalog 里固定版本，再在 app 模块启用插件并声明依赖。版本号以 ",[197,224,227],{"href":225,"rel":226},"https:\u002F\u002Fdeveloper.android.com\u002Fjetpack\u002Fandroidx\u002Freleases\u002Fnavigation",[201],"AndroidX Navigation 发布说明"," 为准。",[230,231,237],"pre",{"className":232,"code":233,"filename":234,"language":235,"meta":236,"style":236},"language-toml shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","[versions]\nnavigationCompose = \"2.9.0\"\nkotlinxSerializationJson = \"1.8.1\"\n\n[libraries]\nandroidx-navigation-compose = { group = \"androidx.navigation\", name = \"navigation-compose\", version.ref = \"navigationCompose\" }\nkotlinx-serialization-json = { group = \"org.jetbrains.kotlinx\", name = \"kotlinx-serialization-json\", version.ref = \"kotlinxSerializationJson\" }\n\n[plugins]\nkotlin-serialization = { id = \"org.jetbrains.kotlin.plugin.serialization\", version.ref = \"kotlin\" }\n","gradle\u002Flibs.versions.toml","toml","",[183,238,239,255,275,290,297,307,368,421,426,436],{"__ignoreMap":236},[240,241,244,248,252],"span",{"class":242,"line":243},"line",1,[240,245,247],{"class":246},"sMK4o","[",[240,249,251],{"class":250},"sBMFI","versions",[240,253,254],{"class":246},"]\n",[240,256,258,262,265,268,272],{"class":242,"line":257},2,[240,259,261],{"class":260},"sTEyZ","navigationCompose ",[240,263,264],{"class":246},"=",[240,266,267],{"class":246}," \"",[240,269,271],{"class":270},"sfazB","2.9.0",[240,273,274],{"class":246},"\"\n",[240,276,278,281,283,285,288],{"class":242,"line":277},3,[240,279,280],{"class":260},"kotlinxSerializationJson ",[240,282,264],{"class":246},[240,284,267],{"class":246},[240,286,287],{"class":270},"1.8.1",[240,289,274],{"class":246},[240,291,293],{"class":242,"line":292},4,[240,294,296],{"emptyLinePlaceholder":295},true,"\n",[240,298,300,302,305],{"class":242,"line":299},5,[240,301,247],{"class":246},[240,303,304],{"class":250},"libraries",[240,306,254],{"class":246},[240,308,310,313,315,318,321,323,325,328,331,334,337,339,341,343,345,347,350,353,356,358,360,363,365],{"class":242,"line":309},6,[240,311,312],{"class":260},"androidx-navigation-compose ",[240,314,264],{"class":246},[240,316,317],{"class":246}," {",[240,319,320],{"class":260}," group ",[240,322,264],{"class":246},[240,324,267],{"class":246},[240,326,327],{"class":270},"androidx.navigation",[240,329,330],{"class":246},"\"",[240,332,333],{"class":246},",",[240,335,336],{"class":260}," name ",[240,338,264],{"class":246},[240,340,267],{"class":246},[240,342,217],{"class":270},[240,344,330],{"class":246},[240,346,333],{"class":246},[240,348,349],{"class":260}," version",[240,351,352],{"class":246},".",[240,354,355],{"class":260},"ref ",[240,357,264],{"class":246},[240,359,267],{"class":246},[240,361,362],{"class":270},"navigationCompose",[240,364,330],{"class":246},[240,366,367],{"class":246}," }\n",[240,369,371,374,376,378,380,382,384,387,389,391,393,395,397,400,402,404,406,408,410,412,414,417,419],{"class":242,"line":370},7,[240,372,373],{"class":260},"kotlinx-serialization-json ",[240,375,264],{"class":246},[240,377,317],{"class":246},[240,379,320],{"class":260},[240,381,264],{"class":246},[240,383,267],{"class":246},[240,385,386],{"class":270},"org.jetbrains.kotlinx",[240,388,330],{"class":246},[240,390,333],{"class":246},[240,392,336],{"class":260},[240,394,264],{"class":246},[240,396,267],{"class":246},[240,398,399],{"class":270},"kotlinx-serialization-json",[240,401,330],{"class":246},[240,403,333],{"class":246},[240,405,349],{"class":260},[240,407,352],{"class":246},[240,409,355],{"class":260},[240,411,264],{"class":246},[240,413,267],{"class":246},[240,415,416],{"class":270},"kotlinxSerializationJson",[240,418,330],{"class":246},[240,420,367],{"class":246},[240,422,424],{"class":242,"line":423},8,[240,425,296],{"emptyLinePlaceholder":295},[240,427,429,431,434],{"class":242,"line":428},9,[240,430,247],{"class":246},[240,432,433],{"class":250},"plugins",[240,435,254],{"class":246},[240,437,439,442,444,446,449,451,453,456,458,460,462,464,466,468,470,473,475],{"class":242,"line":438},10,[240,440,441],{"class":260},"kotlin-serialization ",[240,443,264],{"class":246},[240,445,317],{"class":246},[240,447,448],{"class":260}," id ",[240,450,264],{"class":246},[240,452,267],{"class":246},[240,454,455],{"class":270},"org.jetbrains.kotlin.plugin.serialization",[240,457,330],{"class":246},[240,459,333],{"class":246},[240,461,349],{"class":260},[240,463,352],{"class":246},[240,465,355],{"class":260},[240,467,264],{"class":246},[240,469,267],{"class":246},[240,471,472],{"class":270},"kotlin",[240,474,330],{"class":246},[240,476,367],{"class":246},[179,478,479],{},"在 app 模块应用插件并引入库：",[230,481,485],{"className":482,"code":483,"filename":484,"language":472,"meta":236,"style":236},"language-kotlin shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","plugins {\n    alias(libs.plugins.kotlin.serialization)\n}\n\ndependencies {\n    implementation(libs.androidx.navigation.compose)\n    implementation(libs.kotlinx.serialization.json)\n}\n","app\u002Fbuild.gradle.kts",[183,486,487,495,503,508,512,519,527,534],{"__ignoreMap":236},[240,488,489,492],{"class":242,"line":243},[240,490,433],{"class":491},"s2Zo4",[240,493,494],{"class":260}," {\n",[240,496,497,500],{"class":242,"line":257},[240,498,499],{"class":491},"    alias",[240,501,502],{"class":260},"(libs.plugins.kotlin.serialization)\n",[240,504,505],{"class":242,"line":277},[240,506,507],{"class":260},"}\n",[240,509,510],{"class":242,"line":292},[240,511,296],{"emptyLinePlaceholder":295},[240,513,514,517],{"class":242,"line":299},[240,515,516],{"class":491},"dependencies",[240,518,494],{"class":260},[240,520,521,524],{"class":242,"line":309},[240,522,523],{"class":491},"    implementation",[240,525,526],{"class":260},"(libs.androidx.navigation.compose)\n",[240,528,529,531],{"class":242,"line":370},[240,530,523],{"class":491},[240,532,533],{"class":260},"(libs.kotlinx.serialization.json)\n",[240,535,536],{"class":242,"line":423},[240,537,507],{"class":260},[539,540,541,544,545,548,549,551,552,554],"tip",{},[183,542,543],{},"kotlin-serialization"," 必须加在",[192,546,547],{},"定义路由的模块","上。只加 ",[183,550,399],{}," 而不启用插件，",[183,553,185],{}," 不会生成序列化器，编译会失败。",[209,556,557],{"id":557},"定义类型安全的路由",[179,559,560,561,564,565,568,569,572,573,576],{},"把每个目的地写成可序列化的 Kotlin 类型，而不是 ",[183,562,563],{},"\"home\"","、",[183,566,567],{},"\"profile\u002F{id}\""," 这类字符串。无参页面用 ",[183,570,571],{},"object","，需要参数的页面用 ",[183,574,575],{},"data class","。参数只放轻量、可序列化的值（原始类型、枚举、短字符串），不要把整个领域模型塞进路由。",[230,578,581],{"className":482,"code":579,"filename":580,"language":472,"meta":236,"style":236},"import kotlinx.serialization.Serializable\n\n@Serializable\nobject Home\n\n@Serializable\nobject Login\n\n@Serializable\ndata class Profile(val userId: String)\n\n@Serializable\ndata class Search(val query: String = \"\")\n","navigation\u002FAppRoute.kt",[183,582,583,591,595,600,607,611,615,622,626,630,657,662,667],{"__ignoreMap":236},[240,584,585,588],{"class":242,"line":243},[240,586,587],{"class":246},"import",[240,589,590],{"class":250}," kotlinx.serialization.Serializable\n",[240,592,593],{"class":242,"line":257},[240,594,296],{"emptyLinePlaceholder":295},[240,596,597],{"class":242,"line":277},[240,598,599],{"class":250},"@Serializable\n",[240,601,602,604],{"class":242,"line":292},[240,603,571],{"class":246},[240,605,606],{"class":250}," Home\n",[240,608,609],{"class":242,"line":299},[240,610,296],{"emptyLinePlaceholder":295},[240,612,613],{"class":242,"line":309},[240,614,599],{"class":250},[240,616,617,619],{"class":242,"line":370},[240,618,571],{"class":246},[240,620,621],{"class":250}," Login\n",[240,623,624],{"class":242,"line":423},[240,625,296],{"emptyLinePlaceholder":295},[240,627,628],{"class":242,"line":428},[240,629,599],{"class":250},[240,631,632,636,639,642,645,648,651,654],{"class":242,"line":438},[240,633,635],{"class":634},"spNyl","data",[240,637,638],{"class":246}," class",[240,640,641],{"class":250}," Profile",[240,643,644],{"class":260},"(",[240,646,647],{"class":246},"val",[240,649,650],{"class":260}," userId: ",[240,652,653],{"class":250},"String",[240,655,656],{"class":260},")\n",[240,658,660],{"class":242,"line":659},11,[240,661,296],{"emptyLinePlaceholder":295},[240,663,665],{"class":242,"line":664},12,[240,666,599],{"class":250},[240,668,670,672,674,677,679,681,684,686,689,692],{"class":242,"line":669},13,[240,671,635],{"class":634},[240,673,638],{"class":246},[240,675,676],{"class":250}," Search",[240,678,644],{"class":260},[240,680,647],{"class":246},[240,682,683],{"class":260}," query: ",[240,685,653],{"class":250},[240,687,688],{"class":246}," =",[240,690,691],{"class":270}," \"\"",[240,693,656],{"class":260},[179,695,696,697,700],{},"规模变大时，用 ",[183,698,699],{},"sealed interface"," 把路由收拢到一处，避免散落的顶层类型：",[230,702,704],{"className":482,"code":703,"filename":580,"language":472,"meta":236,"style":236},"import kotlinx.serialization.Serializable\n\n@Serializable\nsealed interface AppRoute {\n    @Serializable\n    data object Home : AppRoute\n\n    @Serializable\n    data class Profile(val userId: String) : AppRoute\n}\n",[183,705,706,712,716,720,733,738,755,759,763,784],{"__ignoreMap":236},[240,707,708,710],{"class":242,"line":243},[240,709,587],{"class":246},[240,711,590],{"class":250},[240,713,714],{"class":242,"line":257},[240,715,296],{"emptyLinePlaceholder":295},[240,717,718],{"class":242,"line":277},[240,719,599],{"class":250},[240,721,722,725,728,731],{"class":242,"line":292},[240,723,724],{"class":634},"sealed",[240,726,727],{"class":246}," interface",[240,729,730],{"class":250}," AppRoute",[240,732,494],{"class":260},[240,734,735],{"class":242,"line":299},[240,736,737],{"class":250},"    @Serializable\n",[240,739,740,743,746,749,752],{"class":242,"line":309},[240,741,742],{"class":634},"    data",[240,744,745],{"class":246}," object",[240,747,748],{"class":250}," Home",[240,750,751],{"class":260}," : ",[240,753,754],{"class":250},"AppRoute\n",[240,756,757],{"class":242,"line":370},[240,758,296],{"emptyLinePlaceholder":295},[240,760,761],{"class":242,"line":423},[240,762,737],{"class":250},[240,764,765,767,769,771,773,775,777,779,782],{"class":242,"line":428},[240,766,742],{"class":634},[240,768,638],{"class":246},[240,770,641],{"class":250},[240,772,644],{"class":260},[240,774,647],{"class":246},[240,776,650],{"class":260},[240,778,653],{"class":250},[240,780,781],{"class":260},") : ",[240,783,754],{"class":250},[240,785,786],{"class":242,"line":438},[240,787,507],{"class":260},[789,790,791,792,795],"warning",{},"导航参数会写入系统 ",[183,793,794],{},"SavedState","。不要传递大型列表、Bitmap 或整个网络响应对象；页面之间只传 ID，在目的地用 Repository 或 ViewModel 再取数据。",[209,797,799],{"id":798},"搭建-navhost-与起始页","搭建 NavHost 与起始页",[179,801,802,803,806,807,809,810,813,814,817],{},"在根 Composable 里创建 ",[183,804,805],{},"NavController","，用 ",[183,808,206],{}," 声明图，并把 ",[183,811,812],{},"startDestination"," 设成起始路由类型。",[183,815,816],{},"composable\u003CT>"," 的类型参数就是目的地，不再传 route 字符串。",[230,819,822],{"className":482,"code":820,"filename":821,"language":472,"meta":236,"style":236},"import androidx.compose.runtime.Composable\nimport androidx.navigation.compose.NavHost\nimport androidx.navigation.compose.composable\nimport androidx.navigation.compose.rememberNavController\nimport androidx.navigation.toRoute\n\n@Composable\nfun AppNavHost() {\n    val navController = rememberNavController()\n\n    NavHost(\n        navController = navController,\n        startDestination = Home,\n    ) {\n        composable\u003CHome> {\n            HomeScreen(\n                onOpenProfile = { userId ->\n                    navController.navigate(Profile(userId = userId))\n                },\n            )\n        }\n        composable\u003CProfile> { backStackEntry ->\n            val profile = backStackEntry.toRoute\u003CProfile>()\n            ProfileScreen(\n                userId = profile.userId,\n                onBack = { navController.popBackStack() },\n            )\n        }\n    }\n}\n","navigation\u002FAppNavHost.kt",[183,823,824,831,838,845,852,859,863,868,879,895,899,907,917,927,933,948,956,970,992,998,1004,1010,1024,1048,1056,1067,1084,1089,1094,1100],{"__ignoreMap":236},[240,825,826,828],{"class":242,"line":243},[240,827,587],{"class":246},[240,829,830],{"class":250}," androidx.compose.runtime.Composable\n",[240,832,833,835],{"class":242,"line":257},[240,834,587],{"class":246},[240,836,837],{"class":250}," androidx.navigation.compose.NavHost\n",[240,839,840,842],{"class":242,"line":277},[240,841,587],{"class":246},[240,843,844],{"class":250}," androidx.navigation.compose.composable\n",[240,846,847,849],{"class":242,"line":292},[240,848,587],{"class":246},[240,850,851],{"class":250}," androidx.navigation.compose.rememberNavController\n",[240,853,854,856],{"class":242,"line":299},[240,855,587],{"class":246},[240,857,858],{"class":250}," androidx.navigation.toRoute\n",[240,860,861],{"class":242,"line":309},[240,862,296],{"emptyLinePlaceholder":295},[240,864,865],{"class":242,"line":370},[240,866,867],{"class":250},"@Composable\n",[240,869,870,873,876],{"class":242,"line":423},[240,871,872],{"class":246},"fun",[240,874,875],{"class":491}," AppNavHost",[240,877,878],{"class":260},"() {\n",[240,880,881,884,887,889,892],{"class":242,"line":428},[240,882,883],{"class":246},"    val",[240,885,886],{"class":260}," navController ",[240,888,264],{"class":246},[240,890,891],{"class":491}," rememberNavController",[240,893,894],{"class":260},"()\n",[240,896,897],{"class":242,"line":438},[240,898,296],{"emptyLinePlaceholder":295},[240,900,901,904],{"class":242,"line":659},[240,902,903],{"class":491},"    NavHost",[240,905,906],{"class":260},"(\n",[240,908,909,912,914],{"class":242,"line":664},[240,910,911],{"class":260},"        navController ",[240,913,264],{"class":246},[240,915,916],{"class":260}," navController,\n",[240,918,919,922,924],{"class":242,"line":669},[240,920,921],{"class":260},"        startDestination ",[240,923,264],{"class":246},[240,925,926],{"class":260}," Home,\n",[240,928,930],{"class":242,"line":929},14,[240,931,932],{"class":260},"    ) {\n",[240,934,936,939,942,945],{"class":242,"line":935},15,[240,937,938],{"class":491},"        composable",[240,940,941],{"class":260},"\u003C",[240,943,944],{"class":250},"Home",[240,946,947],{"class":260},"> {\n",[240,949,951,954],{"class":242,"line":950},16,[240,952,953],{"class":491},"            HomeScreen",[240,955,906],{"class":260},[240,957,959,962,964,967],{"class":242,"line":958},17,[240,960,961],{"class":260},"                onOpenProfile ",[240,963,264],{"class":246},[240,965,966],{"class":260}," { userId ",[240,968,969],{"class":634},"->\n",[240,971,973,976,979,981,984,987,989],{"class":242,"line":972},18,[240,974,975],{"class":260},"                    navController.",[240,977,978],{"class":491},"navigate",[240,980,644],{"class":260},[240,982,983],{"class":491},"Profile",[240,985,986],{"class":260},"(userId ",[240,988,264],{"class":246},[240,990,991],{"class":260}," userId))\n",[240,993,995],{"class":242,"line":994},19,[240,996,997],{"class":260},"                },\n",[240,999,1001],{"class":242,"line":1000},20,[240,1002,1003],{"class":260},"            )\n",[240,1005,1007],{"class":242,"line":1006},21,[240,1008,1009],{"class":260},"        }\n",[240,1011,1013,1015,1017,1019,1022],{"class":242,"line":1012},22,[240,1014,938],{"class":491},[240,1016,941],{"class":260},[240,1018,983],{"class":250},[240,1020,1021],{"class":260},"> { backStackEntry ",[240,1023,969],{"class":634},[240,1025,1027,1030,1033,1035,1038,1041,1043,1045],{"class":242,"line":1026},23,[240,1028,1029],{"class":246},"            val",[240,1031,1032],{"class":260}," profile ",[240,1034,264],{"class":246},[240,1036,1037],{"class":260}," backStackEntry.",[240,1039,1040],{"class":491},"toRoute",[240,1042,941],{"class":260},[240,1044,983],{"class":250},[240,1046,1047],{"class":260},">()\n",[240,1049,1051,1054],{"class":242,"line":1050},24,[240,1052,1053],{"class":491},"            ProfileScreen",[240,1055,906],{"class":260},[240,1057,1059,1062,1064],{"class":242,"line":1058},25,[240,1060,1061],{"class":260},"                userId ",[240,1063,264],{"class":246},[240,1065,1066],{"class":260}," profile.userId,\n",[240,1068,1070,1073,1075,1078,1081],{"class":242,"line":1069},26,[240,1071,1072],{"class":260},"                onBack ",[240,1074,264],{"class":246},[240,1076,1077],{"class":260}," { navController.",[240,1079,1080],{"class":491},"popBackStack",[240,1082,1083],{"class":260},"() },\n",[240,1085,1087],{"class":242,"line":1086},27,[240,1088,1003],{"class":260},[240,1090,1092],{"class":242,"line":1091},28,[240,1093,1009],{"class":260},[240,1095,1097],{"class":242,"line":1096},29,[240,1098,1099],{"class":260},"    }\n",[240,1101,1103],{"class":242,"line":1102},30,[240,1104,507],{"class":260},[188,1106,1107,1110],{},[183,1108,1109],{},"rememberNavController()"," 必须放在会跨配置变更保留的组合位置（通常是 Activity 的根内容）。不要在每个子页面各造一个 controller，否则返回栈会分裂。",[209,1112,1113],{"id":1113},"在页面之间导航",[179,1115,1116,1117,1119,1120,1122,1123,1125,1126,1128,1129,1132],{},"调用 ",[183,1118,978],{}," 时传入路由实例。有参目的地直接构造 ",[183,1121,575],{},"；无参目的地传 ",[183,1124,571],{},"。需要同时清栈或避免重复入栈时，在 ",[183,1127,978],{}," 的 lambda 里配置 ",[183,1130,1131],{},"NavOptions","。",[230,1134,1137],{"className":482,"code":1135,"filename":1136,"language":472,"meta":236,"style":236},"fun onOpenProfile(userId: String) {\n    navController.navigate(Profile(userId = userId))\n}\n\nfun onOpenHomeAsRoot() {\n    navController.navigate(Home) {\n        popUpTo\u003CHome> { inclusive = true }\n        launchSingleTop = true\n    }\n}\n","ui\u002Fhome\u002FHomeScreen.kt",[183,1138,1139,1154,1171,1175,1179,1188,1197,1217,1227,1231],{"__ignoreMap":236},[240,1140,1141,1143,1146,1149,1151],{"class":242,"line":243},[240,1142,872],{"class":246},[240,1144,1145],{"class":491}," onOpenProfile",[240,1147,1148],{"class":260},"(userId: ",[240,1150,653],{"class":250},[240,1152,1153],{"class":260},") {\n",[240,1155,1156,1159,1161,1163,1165,1167,1169],{"class":242,"line":257},[240,1157,1158],{"class":260},"    navController.",[240,1160,978],{"class":491},[240,1162,644],{"class":260},[240,1164,983],{"class":491},[240,1166,986],{"class":260},[240,1168,264],{"class":246},[240,1170,991],{"class":260},[240,1172,1173],{"class":242,"line":277},[240,1174,507],{"class":260},[240,1176,1177],{"class":242,"line":292},[240,1178,296],{"emptyLinePlaceholder":295},[240,1180,1181,1183,1186],{"class":242,"line":299},[240,1182,872],{"class":246},[240,1184,1185],{"class":491}," onOpenHomeAsRoot",[240,1187,878],{"class":260},[240,1189,1190,1192,1194],{"class":242,"line":309},[240,1191,1158],{"class":260},[240,1193,978],{"class":491},[240,1195,1196],{"class":260},"(Home) {\n",[240,1198,1199,1202,1204,1206,1209,1211,1215],{"class":242,"line":370},[240,1200,1201],{"class":491},"        popUpTo",[240,1203,941],{"class":260},[240,1205,944],{"class":250},[240,1207,1208],{"class":260},"> { inclusive ",[240,1210,264],{"class":246},[240,1212,1214],{"class":1213},"sfNiH"," true",[240,1216,367],{"class":260},[240,1218,1219,1222,1224],{"class":242,"line":423},[240,1220,1221],{"class":260},"        launchSingleTop ",[240,1223,264],{"class":246},[240,1225,1226],{"class":1213}," true\n",[240,1228,1229],{"class":242,"line":428},[240,1230,1099],{"class":260},[240,1232,1233],{"class":242,"line":438},[240,1234,507],{"class":260},[179,1236,1237,1238,1241],{},"判断当前目的地时不要再比较字符串。使用 ",[183,1239,1240],{},"hasRoute","：",[230,1243,1246],{"className":482,"code":1244,"filename":1245,"language":472,"meta":236,"style":236},"import androidx.navigation.hasRoute\n\nval isHome = navController.currentBackStackEntry\n    ?.destination\n    ?.hasRoute\u003CHome>() == true\n","ui\u002Fscaffold\u002FAppScaffold.kt",[183,1247,1248,1255,1259,1271,1276],{"__ignoreMap":236},[240,1249,1250,1252],{"class":242,"line":243},[240,1251,587],{"class":246},[240,1253,1254],{"class":250}," androidx.navigation.hasRoute\n",[240,1256,1257],{"class":242,"line":257},[240,1258,296],{"emptyLinePlaceholder":295},[240,1260,1261,1263,1266,1268],{"class":242,"line":277},[240,1262,647],{"class":246},[240,1264,1265],{"class":260}," isHome ",[240,1267,264],{"class":246},[240,1269,1270],{"class":260}," navController.currentBackStackEntry\n",[240,1272,1273],{"class":242,"line":292},[240,1274,1275],{"class":260},"    ?.destination\n",[240,1277,1278,1281,1283,1285,1287,1290,1293],{"class":242,"line":299},[240,1279,1280],{"class":260},"    ?.",[240,1282,1240],{"class":491},[240,1284,941],{"class":260},[240,1286,944],{"class":250},[240,1288,1289],{"class":260},">() ",[240,1291,1292],{"class":246},"==",[240,1294,1226],{"class":1213},[209,1296,1297],{"id":1297},"读取导航参数",[1299,1300,1302],"h3",{"id":1301},"在-composable-中读取","在 Composable 中读取",[179,1304,1305,1306,1308,1309,1312,1313,1316],{},"在 ",[183,1307,816],{}," 的 lambda 里对 ",[183,1310,1311],{},"NavBackStackEntry"," 调用 ",[183,1314,1315],{},"toRoute\u003CT>()","，得到与路由定义一致的对象。",[230,1318,1320],{"className":482,"code":1319,"filename":821,"language":472,"meta":236,"style":236},"composable\u003CProfile> { backStackEntry ->\n    val profile = backStackEntry.toRoute\u003CProfile>()\n    ProfileScreen(userId = profile.userId)\n}\n",[183,1321,1322,1335,1353,1365],{"__ignoreMap":236},[240,1323,1324,1327,1329,1331,1333],{"class":242,"line":243},[240,1325,1326],{"class":491},"composable",[240,1328,941],{"class":260},[240,1330,983],{"class":250},[240,1332,1021],{"class":260},[240,1334,969],{"class":634},[240,1336,1337,1339,1341,1343,1345,1347,1349,1351],{"class":242,"line":257},[240,1338,883],{"class":246},[240,1340,1032],{"class":260},[240,1342,264],{"class":246},[240,1344,1037],{"class":260},[240,1346,1040],{"class":491},[240,1348,941],{"class":260},[240,1350,983],{"class":250},[240,1352,1047],{"class":260},[240,1354,1355,1358,1360,1362],{"class":242,"line":277},[240,1356,1357],{"class":491},"    ProfileScreen",[240,1359,986],{"class":260},[240,1361,264],{"class":246},[240,1363,1364],{"class":260}," profile.userId)\n",[240,1366,1367],{"class":242,"line":292},[240,1368,507],{"class":260},[1299,1370,1372],{"id":1371},"在-viewmodel-中读取","在 ViewModel 中读取",[179,1374,1375,1376,1379],{},"把同样的路由从 ",[183,1377,1378],{},"SavedStateHandle"," 解出来，进程被杀后系统恢复页面时参数仍然在。",[230,1381,1384],{"className":482,"code":1382,"filename":1383,"language":472,"meta":236,"style":236},"import androidx.lifecycle.SavedStateHandle\nimport androidx.lifecycle.ViewModel\nimport androidx.navigation.toRoute\n\nclass ProfileViewModel(\n    savedStateHandle: SavedStateHandle,\n) : ViewModel() {\n    private val profile = savedStateHandle.toRoute\u003CProfile>()\n    val userId: String = profile.userId\n}\n","ui\u002Fprofile\u002FProfileViewModel.kt",[183,1385,1386,1393,1400,1406,1410,1420,1430,1439,1462,1475],{"__ignoreMap":236},[240,1387,1388,1390],{"class":242,"line":243},[240,1389,587],{"class":246},[240,1391,1392],{"class":250}," androidx.lifecycle.SavedStateHandle\n",[240,1394,1395,1397],{"class":242,"line":257},[240,1396,587],{"class":246},[240,1398,1399],{"class":250}," androidx.lifecycle.ViewModel\n",[240,1401,1402,1404],{"class":242,"line":277},[240,1403,587],{"class":246},[240,1405,858],{"class":250},[240,1407,1408],{"class":242,"line":292},[240,1409,296],{"emptyLinePlaceholder":295},[240,1411,1412,1415,1418],{"class":242,"line":299},[240,1413,1414],{"class":246},"class",[240,1416,1417],{"class":250}," ProfileViewModel",[240,1419,906],{"class":260},[240,1421,1422,1425,1427],{"class":242,"line":309},[240,1423,1424],{"class":260},"    savedStateHandle: ",[240,1426,1378],{"class":250},[240,1428,1429],{"class":260},",\n",[240,1431,1432,1434,1437],{"class":242,"line":370},[240,1433,781],{"class":260},[240,1435,1436],{"class":250},"ViewModel",[240,1438,878],{"class":260},[240,1440,1441,1444,1447,1449,1451,1454,1456,1458,1460],{"class":242,"line":423},[240,1442,1443],{"class":634},"    private",[240,1445,1446],{"class":246}," val",[240,1448,1032],{"class":260},[240,1450,264],{"class":246},[240,1452,1453],{"class":260}," savedStateHandle.",[240,1455,1040],{"class":491},[240,1457,941],{"class":260},[240,1459,983],{"class":250},[240,1461,1047],{"class":260},[240,1463,1464,1466,1468,1470,1472],{"class":242,"line":428},[240,1465,883],{"class":246},[240,1467,650],{"class":260},[240,1469,653],{"class":250},[240,1471,688],{"class":246},[240,1473,1474],{"class":260}," profile.userId\n",[240,1476,1477],{"class":242,"line":438},[240,1478,507],{"class":260},[539,1480,1481,1482,1485,1486,1489],{},"Composable 和 ViewModel 都要从路由读 ID，不要一边 ",[183,1483,1484],{},"toRoute()","、一边再手写 ",[183,1487,1488],{},"savedStateHandle[\"userId\"]","。两套取值方式并存时，重构参数名很容易漏改其中一处。",[209,1491,1492],{"id":1492},"处理返回栈",[1299,1494,1495],{"id":1495},"弹出上一页",[179,1497,1498,1499,1502,1503,1506],{},"系统返回手势、导航栏 Up 和你自己的「返回」按钮应对齐到同一套 API：普通返回用 ",[183,1500,1501],{},"popBackStack()","，工具栏 Up 用 ",[183,1504,1505],{},"navigateUp()","（会考虑深层链接进入时的父图）。",[230,1508,1511],{"className":482,"code":1509,"filename":1510,"language":472,"meta":236,"style":236},"fun onBack() {\n    navController.popBackStack()\n}\n\nfun onNavigateUp() {\n    navController.navigateUp()\n}\n","ui\u002Fprofile\u002FProfileScreen.kt",[183,1512,1513,1522,1530,1534,1538,1547,1556],{"__ignoreMap":236},[240,1514,1515,1517,1520],{"class":242,"line":243},[240,1516,872],{"class":246},[240,1518,1519],{"class":491}," onBack",[240,1521,878],{"class":260},[240,1523,1524,1526,1528],{"class":242,"line":257},[240,1525,1158],{"class":260},[240,1527,1080],{"class":491},[240,1529,894],{"class":260},[240,1531,1532],{"class":242,"line":277},[240,1533,507],{"class":260},[240,1535,1536],{"class":242,"line":292},[240,1537,296],{"emptyLinePlaceholder":295},[240,1539,1540,1542,1545],{"class":242,"line":299},[240,1541,872],{"class":246},[240,1543,1544],{"class":491}," onNavigateUp",[240,1546,878],{"class":260},[240,1548,1549,1551,1554],{"class":242,"line":309},[240,1550,1158],{"class":260},[240,1552,1553],{"class":491},"navigateUp",[240,1555,894],{"class":260},[240,1557,1558],{"class":242,"line":370},[240,1559,507],{"class":260},[1299,1561,1562],{"id":1562},"清空返回栈后跳转",[179,1564,1565,1566,1569,1570,1573,1574,1132,1576,1579],{},"登录成功、完成引导这类「不应再回到上一页」的场景，先 ",[183,1567,1568],{},"popUpTo"," 起始目的地并设 ",[183,1571,1572],{},"inclusive","，再 ",[183,1575,978],{},[183,1577,1578],{},"launchSingleTop"," 避免栈顶已经是目标时再压一层。",[230,1581,1584],{"className":482,"code":1582,"filename":1583,"language":472,"meta":236,"style":236},"navController.navigate(Home) {\n    popUpTo\u003CLogin> { inclusive = true }\n    launchSingleTop = true\n}\n","ui\u002Flogin\u002FLoginScreen.kt",[183,1585,1586,1595,1613,1622],{"__ignoreMap":236},[240,1587,1588,1591,1593],{"class":242,"line":243},[240,1589,1590],{"class":260},"navController.",[240,1592,978],{"class":491},[240,1594,1196],{"class":260},[240,1596,1597,1600,1602,1605,1607,1609,1611],{"class":242,"line":257},[240,1598,1599],{"class":491},"    popUpTo",[240,1601,941],{"class":260},[240,1603,1604],{"class":250},"Login",[240,1606,1208],{"class":260},[240,1608,264],{"class":246},[240,1610,1214],{"class":1213},[240,1612,367],{"class":260},[240,1614,1615,1618,1620],{"class":242,"line":277},[240,1616,1617],{"class":260},"    launchSingleTop ",[240,1619,264],{"class":246},[240,1621,1226],{"class":1213},[240,1623,1624],{"class":242,"line":292},[240,1625,507],{"class":260},[789,1627,1628,1630,1631,1634,1635,1638],{},[183,1629,1501],{}," 在栈里只剩根目的地时会返回 ",[183,1632,1633],{},"false"," 且不关 Activity。根页的返回行为交给系统（预测性返回 \u002F ",[183,1636,1637],{},"OnBackPressedDispatcher","），不要在根页无条件再 pop 一次。",[209,1640,1641],{"id":1641},"接入深层链接",[179,1643,1644,1645,1648,1649,1651,1652,1655,1656,1659],{},"类型安全 API 用 ",[183,1646,1647],{},"navDeepLink\u003CT>(basePath = …)"," 声明 URI，路径参数与路由 ",[183,1650,575],{}," 的属性对应。同时在 ",[183,1653,1654],{},"AndroidManifest.xml"," 为 Activity 配置相同 scheme \u002F host 的 ",[183,1657,1658],{},"intent-filter","，否则系统不会把链接交到你的 App。",[230,1661,1663],{"className":482,"code":1662,"filename":821,"language":472,"meta":236,"style":236},"import androidx.navigation.navDeepLink\n\ncomposable\u003CProfile>(\n    deepLinks = listOf(\n        navDeepLink\u003CProfile>(basePath = \"https:\u002F\u002Farturoyi.dev\u002Fprofile\"),\n    ),\n) { backStackEntry ->\n    val profile = backStackEntry.toRoute\u003CProfile>()\n    ProfileScreen(userId = profile.userId)\n}\n",[183,1664,1665,1672,1676,1687,1699,1719,1724,1731,1749,1759],{"__ignoreMap":236},[240,1666,1667,1669],{"class":242,"line":243},[240,1668,587],{"class":246},[240,1670,1671],{"class":250}," androidx.navigation.navDeepLink\n",[240,1673,1674],{"class":242,"line":257},[240,1675,296],{"emptyLinePlaceholder":295},[240,1677,1678,1680,1682,1684],{"class":242,"line":277},[240,1679,1326],{"class":491},[240,1681,941],{"class":260},[240,1683,983],{"class":250},[240,1685,1686],{"class":260},">(\n",[240,1688,1689,1692,1694,1697],{"class":242,"line":292},[240,1690,1691],{"class":260},"    deepLinks ",[240,1693,264],{"class":246},[240,1695,1696],{"class":491}," listOf",[240,1698,906],{"class":260},[240,1700,1701,1704,1706,1708,1711,1713,1716],{"class":242,"line":299},[240,1702,1703],{"class":491},"        navDeepLink",[240,1705,941],{"class":260},[240,1707,983],{"class":250},[240,1709,1710],{"class":260},">(basePath ",[240,1712,264],{"class":246},[240,1714,1715],{"class":270}," \"https:\u002F\u002Farturoyi.dev\u002Fprofile\"",[240,1717,1718],{"class":260},"),\n",[240,1720,1721],{"class":242,"line":309},[240,1722,1723],{"class":260},"    ),\n",[240,1725,1726,1729],{"class":242,"line":370},[240,1727,1728],{"class":260},") { backStackEntry ",[240,1730,969],{"class":634},[240,1732,1733,1735,1737,1739,1741,1743,1745,1747],{"class":242,"line":423},[240,1734,883],{"class":246},[240,1736,1032],{"class":260},[240,1738,264],{"class":246},[240,1740,1037],{"class":260},[240,1742,1040],{"class":491},[240,1744,941],{"class":260},[240,1746,983],{"class":250},[240,1748,1047],{"class":260},[240,1750,1751,1753,1755,1757],{"class":242,"line":428},[240,1752,1357],{"class":491},[240,1754,986],{"class":260},[240,1756,264],{"class":246},[240,1758,1364],{"class":260},[240,1760,1761],{"class":242,"line":438},[240,1762,507],{"class":260},[230,1764,1769],{"className":1765,"code":1766,"filename":1767,"language":1768,"meta":236,"style":236},"language-xml shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\u003Cactivity android:name=\".MainActivity\">\n    \u003Cintent-filter>\n        \u003Caction android:name=\"android.intent.action.VIEW\" \u002F>\n        \u003Ccategory android:name=\"android.intent.category.DEFAULT\" \u002F>\n        \u003Ccategory android:name=\"android.intent.category.BROWSABLE\" \u002F>\n        \u003Cdata\n            android:scheme=\"https\"\n            android:host=\"arturoyi.dev\"\n            android:pathPrefix=\"\u002Fprofile\" \u002F>\n    \u003C\u002Fintent-filter>\n\u003C\u002Factivity>\n","app\u002Fsrc\u002Fmain\u002FAndroidManifest.xml","xml",[183,1770,1771,1800,1809,1835,1859,1882,1889,1908,1926,1946,1955],{"__ignoreMap":236},[240,1772,1773,1775,1779,1782,1785,1788,1790,1792,1795,1797],{"class":242,"line":243},[240,1774,941],{"class":246},[240,1776,1778],{"class":1777},"swJcz","activity",[240,1780,1781],{"class":634}," android",[240,1783,1784],{"class":246},":",[240,1786,1787],{"class":634},"name",[240,1789,264],{"class":246},[240,1791,330],{"class":246},[240,1793,1794],{"class":270},".MainActivity",[240,1796,330],{"class":246},[240,1798,1799],{"class":246},">\n",[240,1801,1802,1805,1807],{"class":242,"line":257},[240,1803,1804],{"class":246},"    \u003C",[240,1806,1658],{"class":1777},[240,1808,1799],{"class":246},[240,1810,1811,1814,1817,1819,1821,1823,1825,1827,1830,1832],{"class":242,"line":277},[240,1812,1813],{"class":246},"        \u003C",[240,1815,1816],{"class":1777},"action",[240,1818,1781],{"class":634},[240,1820,1784],{"class":246},[240,1822,1787],{"class":634},[240,1824,264],{"class":246},[240,1826,330],{"class":246},[240,1828,1829],{"class":270},"android.intent.action.VIEW",[240,1831,330],{"class":246},[240,1833,1834],{"class":246}," \u002F>\n",[240,1836,1837,1839,1842,1844,1846,1848,1850,1852,1855,1857],{"class":242,"line":292},[240,1838,1813],{"class":246},[240,1840,1841],{"class":1777},"category",[240,1843,1781],{"class":634},[240,1845,1784],{"class":246},[240,1847,1787],{"class":634},[240,1849,264],{"class":246},[240,1851,330],{"class":246},[240,1853,1854],{"class":270},"android.intent.category.DEFAULT",[240,1856,330],{"class":246},[240,1858,1834],{"class":246},[240,1860,1861,1863,1865,1867,1869,1871,1873,1875,1878,1880],{"class":242,"line":299},[240,1862,1813],{"class":246},[240,1864,1841],{"class":1777},[240,1866,1781],{"class":634},[240,1868,1784],{"class":246},[240,1870,1787],{"class":634},[240,1872,264],{"class":246},[240,1874,330],{"class":246},[240,1876,1877],{"class":270},"android.intent.category.BROWSABLE",[240,1879,330],{"class":246},[240,1881,1834],{"class":246},[240,1883,1884,1886],{"class":242,"line":309},[240,1885,1813],{"class":246},[240,1887,1888],{"class":1777},"data\n",[240,1890,1891,1894,1896,1899,1901,1903,1906],{"class":242,"line":370},[240,1892,1893],{"class":634},"            android",[240,1895,1784],{"class":246},[240,1897,1898],{"class":634},"scheme",[240,1900,264],{"class":246},[240,1902,330],{"class":246},[240,1904,1905],{"class":270},"https",[240,1907,274],{"class":246},[240,1909,1910,1912,1914,1917,1919,1921,1924],{"class":242,"line":423},[240,1911,1893],{"class":634},[240,1913,1784],{"class":246},[240,1915,1916],{"class":634},"host",[240,1918,264],{"class":246},[240,1920,330],{"class":246},[240,1922,1923],{"class":270},"arturoyi.dev",[240,1925,274],{"class":246},[240,1927,1928,1930,1932,1935,1937,1939,1942,1944],{"class":242,"line":428},[240,1929,1893],{"class":634},[240,1931,1784],{"class":246},[240,1933,1934],{"class":634},"pathPrefix",[240,1936,264],{"class":246},[240,1938,330],{"class":246},[240,1940,1941],{"class":270},"\u002Fprofile",[240,1943,330],{"class":246},[240,1945,1834],{"class":246},[240,1947,1948,1951,1953],{"class":242,"line":438},[240,1949,1950],{"class":246},"    \u003C\u002F",[240,1952,1658],{"class":1777},[240,1954,1799],{"class":246},[240,1956,1957,1960,1962],{"class":242,"line":659},[240,1958,1959],{"class":246},"\u003C\u002F",[240,1961,1778],{"class":1777},[240,1963,1799],{"class":246},[188,1965,1966,1967,1970,1971,564,1973,564,1976,1979,1980,1132],{},"自定义 ",[183,1968,1969],{},"NavType"," 只在参数不是 Navigation 内置支持的类型时才需要。",[183,1972,653],{},[183,1974,1975],{},"Int",[183,1977,1978],{},"Boolean","、枚举走默认序列化即可；嵌套对象或列表先考虑改成 ID，而不是立刻写一套 JSON ",[183,1981,1969],{},[209,1983,1984],{"id":1984},"下一步",[1986,1987,1988,1996,2008],"ul",{},[1989,1990,1991,1992,1995],"li",{},"回到 ",[197,1993,1994],{"href":39},"Android 分类"," 查看同栏目其他笔记",[1989,1997,1998,1999,2004,2005,2007],{},"对照 ",[197,2000,2003],{"href":2001,"rel":2002},"https:\u002F\u002Fdeveloper.android.com\u002Fguide\u002Fnavigation\u002Fdesign\u002Ftype-safety",[201],"类型安全目的地"," 补齐测试与 ",[183,2006,1240],{}," 断言",[1989,2009,2010,2011,2014,2015,2017,2018,2020],{},"需要多模块、多返回栈或底部导航时，再拆嵌套 ",[183,2012,2013],{},"navigation\u003CT>"," 图，而不是继续把所有 ",[183,2016,1326],{}," 堆在一个 ",[183,2019,206],{}," 里",[2022,2023,2024],"style",{},"html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}",{"title":236,"searchDepth":257,"depth":257,"links":2026},[2027,2028,2029,2030,2031,2035,2039,2040],{"id":211,"depth":257,"text":211},{"id":557,"depth":257,"text":557},{"id":798,"depth":257,"text":799},{"id":1113,"depth":257,"text":1113},{"id":1297,"depth":257,"text":1297,"children":2032},[2033,2034],{"id":1301,"depth":277,"text":1302},{"id":1371,"depth":277,"text":1372},{"id":1492,"depth":257,"text":1492,"children":2036},[2037,2038],{"id":1495,"depth":277,"text":1495},{"id":1562,"depth":277,"text":1562},{"id":1641,"depth":257,"text":1641},{"id":1984,"depth":257,"text":1984},"从依赖、类型安全路由到 NavHost、跳转、读参、返回栈与深层链接，按任务顺序在 Jetpack Compose 中接入 Navigation。","md",[2044,2048],{"label":2045,"icon":38,"to":2046,"target":2047},"官方 Compose Navigation","https:\u002F\u002Fdeveloper.android.com\u002Fdevelop\u002Fui\u002Fcompose\u002Fnavigation","_blank",{"label":2049,"icon":96,"to":2001,"target":2047},"类型安全路由",{"date":2051,"tags":2052},"2026-08-31",[2053,2054],"Compose","Navigation",{"icon":48},{"title":2057,"description":2058},"在 Jetpack Compose 中搭建类型安全 Navigation","从添加依赖、定义类型安全路由到搭建 NavHost，再到跳转、读参、返回栈与深层链接，按任务顺序在 Jetpack Compose 中接入 Navigation，避开字符串路由的常见坑。","nTAmKhH1DNl_OJ46hcniifALRCgqGbEjlVGPe7B62yc",[2061,2063],{"title":37,"path":39,"stem":43,"description":2062,"icon":38,"children":-1},"Android 开发实践与笔记。",{"title":56,"path":52,"stem":53,"description":2064,"icon":57,"children":-1},"hidden-dex-minidemo 把业务实现编成加密 DEX。运行时由 so 解密后在内存里加载。主 DEX 只保留公开接口。",1790767045843]