Android Navigation的四大要点你都知道吗?

2024-01-21

在JetPack中有一个组件是Navigation,顾名思义它是一个页面导航组件,相对于其他的第三方导航,不同的是它是专门为Fragment的页面管理所设计的。它对于单个Activity的App来说非常有用,因为以一个Activity为架构的App页面的呈现都是通过不同的Fragment来展示的。所以对于Fragment的管理至关重要。通常的实现都要自己维护Fragment之间的栈关系,同时要对Fragment的Transaction操作非常熟悉。为了降低使用与维护成本,所以就有了今天的主角Navigation。

对于Navigation的使用,我将其归纳于以下四点:

  • Navigation的基本配置
  • Navigation的跳转与数据传递
  • Navigation的页面动画
  • Navigation的deepLink

* 2*

配置

在使用之前需要引入Navigation的依赖,然后我们需要为Navigation创建一个配置文件,它将位于res/navigation/nav_graph.xml。为了方便理解文章中的代码,我写了一个Demo,大家可以通过Android精华录查看。

在我的Demo中打开nav_graph.xml你将清晰的看到它们页面间的关系纽带

img

一共有6个页面,最左边的为程序入口页面,它们间的线条指向为它们间可跳转的方向。

我们再来看它们的xm配置

 1<navigation xmlns:android="http://schemas.android.com/apk/res/android"
 2    xmlns:app="http://schemas.android.com/apk/res-auto"
 3    xmlns:tools="http://schemas.android.com/tools"
 4    android:id="@+id/nav_graph"
 5    app:startDestination="@id/welcome_fragment">
 6
 7    <fragment
 8        android:id="@+id/welcome_fragment"
 9        android:name="com.idisfkj.androidapianalysis.navigation.fragment.WelcomeFragment"
10        android:label="welcome_fragment"
11        tools:layout="@layout/fragment_welcome">
12
13        <action
14            android:id="@+id/action_go_to_register_page"
15            app:destination="@id/register_fragment" />
16
17        <action
18            android:id="@+id/action_go_to_order_list_page"
19            app:destination="@id/order_list_fragment"/>
20
21    </fragment>
22
23    <fragment
24        android:id="@+id/register_fragment"
25        android:name="com.idisfkj.androidapianalysis.navigation.fragment.RegisterFragment"
26        android:label="register_fragment"
27        tools:layout="@layout/fragment_register">
28
29        <action
30            android:id="@+id/action_go_to_shop_list_page"
31            app:destination="@id/shop_list_fragment" />
32
33    </fragment>
34
35    ...
36</navigation>

页面标签主要包含navigation、fragment与action

  • navigation: 定义导航栈,可以进行嵌套定义,各个navigation相互独立。它有一个属性startDestination用来定义导航栈的根入口fragment
  • fragment: 顾名思义fragment页面。通过name属性来定义关联的fragment
  • action: 意图,可以理解为Intent,即跳转的行为。通过destination来关联将要跳转的目标fragment。

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

在配置完之后,我们还需要将其关联到Activity中。因为所有的Fragment都离不开Activity。

Navigation为我们提供了两个配置参数: defaultNavHost与navGraph,所以在Activity的xml中需要如下配置

 1<?xml version="1.0" encoding="utf-8"?>
 2<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3    xmlns:app="http://schemas.android.com/apk/res-auto"
 4    xmlns:tools="http://schemas.android.com/tools"
 5    android:layout_width="match_parent"
 6    android:layout_height="match_parent"
 7    android:background="@android:color/background_light"
 8    android:orientation="vertical"
 9    tools:context=".navigation.NavigationMainActivity">
10
11    <fragment
12        android:id="@+id/nav_host_fragment"
13        android:name="androidx.navigation.fragment.NavHostFragment"
14        android:layout_width="match_parent"
15        android:layout_height="match_parent"
16        app:defaultNavHost="true"
17        app:navGraph="@navigation/nav_graph" />
18
19</LinearLayout>
  • defaultNavHost: 将设备的回退操作进行拦截,并将其交给Navigation进行管理。
  • navGraph: Navigation的配置文件,即上面我们配置的nav_graph.xml文件

除此之外,fragment的name属性必须为NavHostFragment,因为它会作为我们配置的所有fragment的管理者。具体通过内部的NavController中的NavigationProvider来获取Navigator抽象实例,具体实现类是FragmentNavigator,所以最终通过它的navigate方法进行创建我们配置的Fragment,并且添加到NavHostFragment的FrameLayout根布局中。

此时如果我们直接运行程序后发现已经可以看到入口页面WelcomeFragment

img

但点击register等操作你会发现点击跳转无效,所以接下来我们需要为其添加跳转

* 3*

跳转

由于我们之前已经在nav_graph.xml中定义了action,所以跳转的接入非常方便,每一个action的关联跳转只需一行代码

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

代码中的id就是配置的action的id,内部原理是先获取到对应的NavController,通过点击的view来遍历找到最外层的parent view,因为最外层的parent view会在配置文件导入时,即NavHostFragment中的onViewCreated方法中进行关联对应的NavController

 1    @Override
 2    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
 3        super.onViewCreated(view, savedInstanceState);
 4        if (!(view instanceof ViewGroup)) {
 5            throw new IllegalStateException("created host view " + view + " is not a ViewGroup");
 6        }
 7        Navigation.setViewNavController(view, mNavController);
 8        // When added programmatically, we need to set the NavController on the parent - i.e.,
 9        // the View that has the ID matching this NavHostFragment.
10        if (view.getParent() != null) {
11            View rootView = (View) view.getParent();
12            if (rootView.getId() == getId()) {
13                Navigation.setViewNavController(rootView, mNavController);
14            }
15        }
16    }

然后再调用navigate进行页面跳转处理,最终通过FragmentTransaction的replace进行Fragment替换

 1    -------------- NavController ------------------
 2
 3    private void navigate(@NonNull NavDestination node, @Nullable Bundle args,
 4            @Nullable NavOptions navOptions, @Nullable Navigator.Extras navigatorExtras) {
 5        boolean popped = false;
 6        if (navOptions != null) {
 7            if (navOptions.getPopUpTo() != -1) {
 8                popped = popBackStackInternal(navOptions.getPopUpTo(),
 9                        navOptions.isPopUpToInclusive());
10            }
11        }
12        Navigator<NavDestination> navigator = mNavigatorProvider.getNavigator(
13                node.getNavigatorName());
14        Bundle finalArgs = node.addInDefaultArgs(args);
15        # ---- 关键代码 -------
16        NavDestination newDest = navigator.navigate(node, finalArgs,
17                navOptions, navigatorExtras);
18        ....
19    }
20
21    -------------- FragmentNavigator ------------------
22
23    public NavDestination navigate(@NonNull Destination destination, @Nullable Bundle args,
24            @Nullable NavOptions navOptions, @Nullable Navigator.Extras navigatorExtras) {
25        if (mFragmentManager.isStateSaved()) {
26            Log.i(TAG, "Ignoring navigate() call: FragmentManager has already"
27                    + " saved its state");
28            return null;
29        }
30        String className = destination.getClassName();
31        if (className.charAt(0) == '.') {
32            className = mContext.getPackageName() + className;
33        }
34        final Fragment frag = instantiateFragment(mContext, mFragmentManager,
35                className, args);
36        frag.setArguments(args);
37        final FragmentTransaction ft = mFragmentManager.beginTransaction();
38
39        int enterAnim = navOptions != null ? navOptions.getEnterAnim() : -1;
40        int exitAnim = navOptions != null ? navOptions.getExitAnim() : -1;
41        int popEnterAnim = navOptions != null ? navOptions.getPopEnterAnim() : -1;
42        int popExitAnim = navOptions != null ? navOptions.getPopExitAnim() : -1;
43        if (enterAnim != -1 || exitAnim != -1 || popEnterAnim != -1 || popExitAnim != -1) {
44            enterAnim = enterAnim != -1 ? enterAnim : 0;
45            exitAnim = exitAnim != -1 ? exitAnim : 0;
46            popEnterAnim = popEnterAnim != -1 ? popEnterAnim : 0;
47            popExitAnim = popExitAnim != -1 ? popExitAnim : 0;
48            ft.setCustomAnimations(enterAnim, exitAnim, popEnterAnim, popExitAnim);
49        }
50
51        # ------ 关键代码 ------
52        ft.replace(mContainerId, frag);
53        ft.setPrimaryNavigationFragment(frag);
54        ...
55    }

源码就分析到这里了,如果需要深入了解,建议阅读NavHostFragment、NavController、NavigatorProvider与FragmentNavigator

* 4*

传参

以上是页面的无参跳转,那么对于有参跳转又该如何呢?

大家想到的应该都是bundle,将传递的数据填入到bundle中。没错Navigator提供的navigate方法可以进行传递bundle数据?

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

这种传统的方法在传递数据类型上并不能保证其一致性,为了减少人为精力上的错误,Navigation提供了一个Gradle插件,专门用来保证数据的类型安全。

使用它的话需要引入该插件,方式如下

1buildscript {
2    repositories {
3        google()
4    }
5    dependencies {
6        def nav_version = "2.1.0"
7        classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version"
8    }
9}

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

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

而它的使用方式也很简单,首先参数需要在nav_graph.xml中进行配置。

 1    <fragment
 2        android:id="@+id/shop_list_fragment"
 3        android:name="com.idisfkj.androidapianalysis.navigation.fragment.ShopListFragment"
 4        android:label="shop_list_fragment"
 5        tools:layout="@layout/fragment_shop_list">
 6
 7        <action
 8            android:id="@+id/action_go_to_shop_detail_page"
 9            app:destination="@id/shop_detail_fragment">
10
11            <argument
12                android:name="title"
13                app:argType="string" />
14
15        </action>
16
17    </fragment>
18
19    <fragment
20        android:id="@+id/shop_detail_fragment"
21        android:name="com.idisfkj.androidapianalysis.navigation.fragment.ShopDetailFragment"
22        android:label="shop_detail_fragment"
23        tools:layout="@layout/fragment_shop_detail">
24
25        <action
26            android:id="@+id/action_go_to_cart_page"
27            app:destination="@id/cart_fragment"
28            app:popUpTo="@id/cart_fragment"
29            app:popUpToInclusive="true" />
30
31        <argument
32            android:name="title"
33            app:argType="string" />
34
35    </fragment>

现在我们从ShopListFragment跳转到ShopDetailFragment,需要在ShopListFragment的对应action中添加argument,声明对应的参数类型与参数名,也可以通过defaultValue定义参数的默认值与nullable标明是否可空。对应的ShopDetailFragment接收参数也是一样。

另外popUpTo与popUpToInclusive属性是为了实现跳转到CartFragment时达到SingleTop效果。

下面我们直接看在代码中如何使用这些配置的参数,首先是在ShopListFragment中

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

还是创建一个createNavigateOnClickListener,只不过现在传递的不再是跳转的action id,而是通过插件自动生成的ShopListFragmentDirections.actionGoToShopDetailPage方法。一旦我们如上配置了argument,插件就会自动生成一个以[类名]+Directions的类,而自动生成的类本质是做了跳转与参数的封装,源码如下

 1class ShopListFragmentDirections private constructor() {
 2    private data class ActionGoToShopDetailPage(val title: String) : NavDirections {
 3        override fun getActionId(): Int = R.id.action_go_to_shop_detail_page
 4
 5        override fun getArguments(): Bundle {
 6            val result = Bundle()
 7            result.putString("title", this.title)
 8            return result
 9        }
10    }
11
12    companion object {
13        fun actionGoToShopDetailPage(title: String): NavDirections = ActionGoToShopDetailPage(title)
14    }
15}

本质是将action id与argument封装成一个NavDirections,内部通过解析它来获取action id与argument,从而执行跳转。

而对于接受方ShopDetailFragment,插件页面自动帮我们生成一个ShopDetailFragmentArgs,以[类名]+Args的类。所以我们需要做的也非常简单

 1class ShopDetailFragment : Fragment() {
 2
 3    private val args by navArgs<ShopDetailFragmentArgs>()
 4
 5    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
 6        return inflater.inflate(R.layout.fragment_shop_detail, container, false).apply {
 7            title.text = args.title
 8            add_cart.setOnClickListener(Navigation.createNavigateOnClickListener(ShopDetailFragmentDirections.actionGoToCartPage()))
 9        }
10    }
11
12}

通过navArgs来获取ShopDetailFragmentArgs对象,它其中包含了传递过来的页面数据。

* 5*

动画

在action中不仅可以配置跳转的destination,还可以定义对应页面的转场动画,使用非

 1<?xml version="1.0" encoding="utf-8"?>
 2<navigation xmlns:android="http://schemas.android.com/apk/res/android"
 3    xmlns:app="http://schemas.android.com/apk/res-auto"
 4    xmlns:tools="http://schemas.android.com/tools"
 5    android:id="@+id/nav_graph"
 6    app:startDestination="@id/welcome_fragment">
 7
 8    <fragment
 9        android:id="@+id/welcome_fragment"
10        android:name="com.idisfkj.androidapianalysis.navigation.fragment.WelcomeFragment"
11        android:label="welcome_fragment"
12        tools:layout="@layout/fragment_welcome">
13
14        <action
15            android:id="@+id/action_go_to_register_page"
16            app:destination="@id/register_fragment"
17            app:enterAnim="@anim/slide_in_right"
18            app:exitAnim="@anim/slide_in_left"
19            app:popEnterAnim="@anim/slide_out_left"
20            app:popExitAnim="@anim/slide_out_right" />
21
22        <action
23            android:id="@+id/action_go_to_order_list_page"
24            app:destination="@id/order_list_fragment"
25            app:enterAnim="@anim/slide_in_right"
26            app:exitAnim="@anim/slide_in_left"
27            app:popEnterAnim="@anim/slide_out_left"
28            app:popExitAnim="@anim/slide_out_right" />
29
30    </fragment>
31    ...
32</navigation>

对应四个动画配置参数

  • enterAnim: 配置进场时目标页面动画
  • exitAnim: 配置进场时原页面动画
  • popEnterAnim: 配置回退pop时目标页面动画
  • popExitAnim: 配置回退pop时原页面动画

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

img

* 6*

deepLink

我们回想一下对于多个Activity我需要实现deepLink效果,应该都是在AndroidManifest.xml中进行配置scheme、host等。而对于单个Activity也需要实现类似的效果,Navigation也提供了对应的实现,而且操作更简单。

Navigation提供的是deepLink标签,可以直接在nav_graph.xml进行配置,例如?

 1    <fragment
 2        android:id="@+id/register_fragment"
 3        android:name="com.idisfkj.androidapianalysis.navigation.fragment.RegisterFragment"
 4        android:label="register_fragment"
 5        tools:layout="@layout/fragment_register">
 6
 7        <action
 8            android:id="@+id/action_go_to_shop_list_page"
 9            app:destination="@id/shop_list_fragment"
10            app:enterAnim="@anim/slide_in_right"
11            app:exitAnim="@anim/slide_in_left"
12            app:popEnterAnim="@anim/slide_out_left"
13            app:popExitAnim="@anim/slide_out_right" />
14
15        <deepLink app:uri="api://register/" />
16
17    </fragment>

上面通过deepLink我配置了一个跳转到注册页RegisterFragment,写法非常简单,直接配置uri即可;同时还可以通过占位符配置传递参数,例如?

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

这时我们就可以在注册页面通过argument获取key为id的数据。

当然要实现上面的效果,我们还需要一个前提,需要在AndroidManifest.xml中将我们的deepLink进行配置,在Activity中使用nav-graph标签

 1    <application
 2        ...
 3        android:theme="@style/AppTheme">
 4        <activity android:name=".navigation.NavigationMainActivity" >
 5            <intent-filter>
 6                <action android:name="android.intent.action.VIEW"/>
 7                <action android:name="android.intent.action.MAIN" />
 8
 9                <category android:name="android.intent.category.LAUNCHER" />
10            </intent-filter>
11            <nav-graph android:value="@navigation/nav_graph"/>
12        </activity>
13        ...
14    </application>

现在只需将文章中的demo安装到手机上,再到网页中配置以下链接

api://register/

点击之后就会启动App,并定位到注册界面。是不是非常简单呢?

最后我们再来看下效果?

img

有关Navigation暂时就到这里,通过这篇文章,希望你能够熟悉运用Navigation,并且发现单Activity的魅力。

* 7*

项目地址

* 7.1*

Android精华录

该库的目的是结合详细的Demo来全面解析Android相关的知识点, 帮助读者能够更快的掌握与理解所阐述的要点。

更多Android进阶指南 可以 扫码 解锁 《Android十大板块文档》

1.Android车载应用开发系统学习指南(附项目实战)

2.Android Framework学习指南,助力成为系统级开发高手

3.2024最新Android中高级面试题汇总+解析,告别零offer

4.企业级Android音视频开发学习路线+项目实战(附源码)

5.Android Jetpack从入门到精通,构建高质量UI界面

6.Flutter技术解析与实战,跨平台首要之选

7.Kotlin从入门到实战,全方面提升架构基础

8.高级Android插件化与组件化(含实战教程和源码)

9.Android 性能优化实战+360°全方面性能调优

10.Android零基础入门到精通,高手进阶之路

敲代码不易,关注一下吧。ღ( ´・ᴗ・` ) ????

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android Navigation的四大要点你都知道吗? 的相关文章

随机推荐

  • 使用说明书的重要性:为什么你的产品需要一份好的使用说明书?

    在如今竞争激烈的市场中 产品的质量和功能已经不再是唯一的竞争优势 良好的用户体验同样重要 而一份好的使用说明书则可以为用户提供更好的产品使用体验 进而提升产品的竞争力 一 使用说明书的重要性 1 使用说明书与用户体验的关系 使用说明书是产品
  • HarmonyOS 基于eTS高效开发HarmonyOS课程类应用

    随着HarmonyOS 3 0 Beta版的发布 API Version 8新增了大批JS eTS API接口 相信很多开发者已经迫不及待想体验基于eTS的HamronyOS应用开发 本期Codelab 我们将基于API Version 8
  • 题解 | #整数与IP地址间的转换#

    百度绝对是今年大厂最ex的 部门是深坑 真别去 我已经替大家踩过 我的金十二银一 Java高频面试题 线程池 入职有编制 退休有房子 Google暑期实习技术面一面 我与101 位架构师交谈的经验 许多人对负载均衡器 API 网关和 BFF
  • 用通俗易懂的方式讲解:使用 LlamaIndex 和 Eleasticsearch 进行大模型 RAG 检索增强生成

    检索增强生成 Retrieval Augmented Generation RAG 是一种结合了检索 Retrieval 和生成 Generation 的技术 它有效地解决了大语言模型 LLM 的一些问题 比如幻觉 知识限制等 随着 RAG
  • 为什么选择HelpLook而不是Document360:知识库工具分析

    在现今的信息化时代 企业们越来越倾向于使用知识库工具来收集 组织和分享他们的知识资源 HelpLook和Document360是市面上两款不错的知识库管理工具 那如果非要在他们之中选一个 还是建议HelpLook 以下是一些对比分析 希望可
  • 【无迹卡尔曼滤波】不确定和间接测量的非线性动力系统识别研究(Matlab代码实现)

    欢迎来到本博客 博主优势 博客内容尽量做到思维缜密 逻辑清晰 为了方便读者 座右铭 行百里者 半于九十 本文目录如下 目录 1 概述 2 运行结果 3 参考文献 4 Matlab代码及文章
  • 甜蜜而简洁 —— 深入了解Pytest插件pytest-sugar

    在日常的软件开发中 测试是确保代码质量的关键步骤之一 然而 对于测试报告的生成和测试结果的可读性 一直以来都是开发者关注的焦点 Pytest插件 pytest sugar 以其清晰而美观的输出 为我们提供了一种愉悦的测试体验 本文将深入介绍
  • 机器学习算法实战案例:LSTM实现多变量多步负荷预测

    文章目录 1 数据处理 1 1 数据集简介 1 2 数据集处理 2 模型训练与预测 2
  • 月薪2W的软件测试工程师,到底是做什么的?

    在生活中 我们常常会遇到以下几种窘迫时刻 准备骑共享单车出行 却发现扫码开锁半天 车子都没有反应 手机导航打车 却发现地图定位偏差很大 司机总是跑错地方 买个水 却遭遇自动售货机吐币 或者不找零钱 好不容易休息打个游戏 却一直出现卡顿 闪退
  • AI魔幻巨制电影《权力的游戏:重生之战》

    AI魔幻巨制电影 权力的游戏 重生之战 冰与火之歌 龙妈雪诺后裔是谁 你相信龙族的力量可以改变维斯特洛大陆的命运吗 在 权力的游戏 重生之战 中 维斯特洛大陆再次陷入混乱之中 但这一次的混乱并非来自家族之间的争斗 而是源自一场神秘的事件 一
  • 题解 | #获取员工其当前的薪水比其manager#

    我为什么拒了华为 offer 国家智能设计与数控技术创新中心 英语好技术烂的top2工科硕就业迷茫 坐等消息 华为ICT无线网络产品线面经 已完结 华为面经 ICT计算产品线 华为计算产品线实习面试 通软 凉凉 软开还是run开 国企银行的
  • 2024诸多大厂春招提前启动!Android的程序员还在等什么

    春招 提前批 已开 xdm别打瞌睡了 格力 顺丰 酷狗 沃尔玛中国 理想 科大讯飞等开启春招 开始收简历了 还有hc的企业提前抢人 春招时间短 节奏快 招满即止 就算挂了也绝不能不投 对企业来说 秋招和春招都是储备人才的黄金时期 春招中 除
  • 【牛客周赛Round 27】题目讲解

    题目一 小红的二进制删数字 小红拿到了一个二进制字符串 s 她可以删掉其中的一些字符 使得最终该字符串为一个2的幂 即可以表示为 2 k 形式的数 小红想知道 自己最少删几个字符可以达成 请你编写一个函数返回这个答案 具体思路 看到这道题目
  • Python常用的自动化小脚本!

    一 list转json string转json 可以使用Python内置的 json 模块将列表 List 和字符串 String 转换成JSON格式 List转JSON假设我们有一个列表 List my list apple banana
  • 做好这几件事,30岁的你也能转行鸿蒙(HarmonyOS)?

    当你年过30 不管你愿不愿意承认 你的精力都在走下坡路 25岁熬一个通宵能写出来的代码 30岁有可能需要一整天 当然你也可以选择不拼精力和体力 当自身的一线经验积累到一定程度后 就会选择慢慢过渡到管理者的角色 通过经验分享及任务分配来参与项
  • 题解 | #汇总各个部门当前员工的title类型的分配数目#

    百度提前批 C 后端开发 技术一面 百度离线搜索架构实习一二三面面经 2024面经总结 百度提前批一面 2024面经总结 百度秋招二面 百度 C 研发工程师 二面 25届百度C 实习一面 已oc 百度 C 日常实习 1 2面 百度 Java
  • 探索自动化测试断言:提升测试效率与质量的关键!

    前言 断言在自动化测试中起着关键的作用 它是验证测试结果是否符合预期的重要手段 如果在自动化测试过程中忽视了断言 那么这个测试就失去了其本质的意义 因为我们无法得知测试结果是否达到了预期的效果 因此 断言在自动化测试中的重要性不言而喻 那么
  • 华为OD机试2024年最新题库(Java)

    我是一名软件开发培训机构老师 我的学生已经有上百人通过了华为OD机试 学生们每次考完试 会把题目拿出来一起交流分享 重要 2024年1月 5月 考的都是OD统一考试 C卷 题库已经整理好了 命中率95 以上 这个专栏使用 Java 解法 问
  • 如何用GPT进行论文润色与改写?

    详情点击链接 如何用GPT GPT4进行论文润色与改写 一OpenAI 1 最新大模型GPT 4 Turbo 2 最新发布的高级数据分析 AI画图 图像识别 文档API 3 GPT Store 4 从0到1创建自己的GPT应用 5 模型Ge
  • Android Navigation的四大要点你都知道吗?

    在JetPack中有一个组件是Navigation 顾名思义它是一个页面导航组件 相对于其他的第三方导航 不同的是它是专门为Fragment的页面管理所设计的 它对于单个Activity的App来说非常有用 因为以一个Activity为架构