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

本文详细介绍了AndroidNavigationComponent的使用,包括NavController的操作、NavDestination的导航逻辑、Fragment间页面跳转的处理(包括参数传递和动画设置),以及使用safeargs插件提高数据类型安全性。
摘要由CSDN通过智能技术生成

}

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

然后再调用navigate进行页面跳转处理,最终通过FragmentTransaction的replace进行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 navigator = mNavigatorProvider.getNavigator(
node.getNavigatorName());
Bundle finalArgs = node.addInDefaultArgs(args);

---- 关键代码 -------

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);
}

------ 关键代码 ------

ft.replace(mContainerId, frag);
ft.setPrimaryNavigationFragment(frag);

}

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

传参

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

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

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

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

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

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”

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

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

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

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

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

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

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)
}
}

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

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

class ShopDetailFragment : Fragment() {

private val args by navArgs()

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对象,它其中包含了传递过来的页面数据。

动画

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

<?xml version="1.0" encoding="utf-8"?>

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
img

要如何成为Android架构师?

搭建自己的知识框架,全面提升自己的技术体系,并且往底层源码方向深入钻研。
大多数技术人喜欢用思维脑图来构建自己的知识体系,一目了然。这里给大家分享一份大厂主流的Android架构师技术体系,可以用来搭建自己的知识框架,或者查漏补缺;

对应这份技术大纲,我也整理了一套Android高级架构师完整系列的视频教程,主要针对3-5年Android开发经验以上,需要往高级架构师层次学习提升的同学,在这里点击GitHub免费分享,希望能帮你突破瓶颈,跳槽进大厂;

最后我必须强调几点:

1.搭建知识框架可不是说你整理好要学习的知识顺序,然后看一遍理解了能复制粘贴就够了,大多都是需要你自己读懂源码和原理,能自己手写出来的。
2.学习的时候你一定要多看多练几遍,把知识才吃透,还要记笔记,这些很重要! 最后你达到什么水平取决你消化了多少知识
3.最终你的知识框架应该是一个完善的,兼顾广度和深度的技术体系。然后经过多次项目实战积累经验,你才能达到高级架构师的层次。

你只需要按照在这个大的框架去填充自己,年薪40W一定不是终点,技术无止境

必须强调几点:**

1.搭建知识框架可不是说你整理好要学习的知识顺序,然后看一遍理解了能复制粘贴就够了,大多都是需要你自己读懂源码和原理,能自己手写出来的。
2.学习的时候你一定要多看多练几遍,把知识才吃透,还要记笔记,这些很重要! 最后你达到什么水平取决你消化了多少知识
3.最终你的知识框架应该是一个完善的,兼顾广度和深度的技术体系。然后经过多次项目实战积累经验,你才能达到高级架构师的层次。

你只需要按照在这个大的框架去填充自己,年薪40W一定不是终点,技术无止境

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值