android final参数,Android应用开发之Android Jetpack-Navigation 使用中参数的传递方法
本文将带你了解Android应用开发之Android Jetpack-Navigation 使用中参数的传递方法,希望本文对大家学Android有所帮助。
由于使用了Navigation,导致Fragment的创建行为完全交给了系统。也就是说,以前的那种通过#Fragment.newInstance(Args...)方式传递参数的方式就被切断了,没有办法快乐的在fragment之间传参了~~。但是不要担心,google爸爸早就帮我们想好了方式,下面我们来一条一条的看看吧:
1.通过NavController.navigate(int, bundle)方法传参。
这个是Navigation中提供的最原始的一种参数传递的方法,我们只需要在使用这个函数导航的时候,将原先需要在newInstance()中传递的bundle对象放在改方法的第二个参数中。系统就会帮我们将bundle传递到目标fragment/activity的argument/Intent中,只需要和之前一样,在跳转到的fragment/activity中调用getArgument()/getIntent(),就可以获得我们传递的Bundle对象。我们来看看源码,探索下系统到底怎么是帮我们实现的吧!(没有兴趣的同学可以直接跳过)
public final void navigate(@IdRes int resId, @Nullable Bundle args) { navigate(resId, args, null);}
可以看到在这个方法体中系统只是简单的帮我们做了转调。我们继续:
NavController.java:
public void navigate(@IdRes int resId, @Nullable Bundle args, @Nullable NavOptions navOptions) {... node.navigate(args, navOptions);}
NavDestination.java:
public void navigate(@Nullable Bundle args, @Nullable NavOptions navOptions) { Bundle defaultArgs = getDefaultArguments(); Bundle finalArgs = new Bundle(); finalArgs.putAll(defaultArgs); if (args != null) { finalArgs.putAll(args); } mNavigator.navigate(this, finalArgs, navOptions);}
public abstract void navigate(@NonNull D destination, @Nullable Bundle args, @Nullable NavOptions navOptions);
最后我们可以看到,它指向了到了一个抽象类(Navigator)中的抽象方法。
这个抽象方法具体有3个主要实现:
1.ActivityNavigator.navigate(...):
@Overridepublic void navigate(@NonNull Destination destination, @Nullable Bundle args, @Nullable NavOptions navOptions) { if (destination.getIntent() == null) { throw new IllegalStateException("Destination " + destination.getId() + " does not have an Intent set."); } Intent intent = new Intent(destination.getIntent()); if (args != null) { intent.putExtras(args); String dataPattern = destination.getDataPattern(); if (!TextUtils.isEmpty(dataPattern)) { // Fill in the data pattern with the args to build a valid URI StringBuffer data = new StringBuffer(); Pattern fillInPattern = Pattern.compile("\\{(.+)\\}"); Matcher matcher = fillInPattern.matcher(dataPattern); while (matcher.find()) { String argName = matcher.group(1); if (args.containsKey(argName)) { matcher.appendReplacement(data, ""); data.append(Uri.encode(args.getString(argName))); } else { throw new IllegalArgumentException("Could not find " + argName + " in " + args + " to fill data pattern " + dataPattern); } } matcher.appendTail(data); intent.setData(Uri.parse(data.toString())); } } if (navOptions != null && navOptions.shouldClearTask()) { intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); } if (navOptions != null && navOptions.shouldLaunchDocument() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { intent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT); } else if (!(mContext instanceof Activity)) { // If we're not launching from an Activity context we have to launch in a new task. intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); } if (navOptions != null && navOptions.shouldLaunchSingleTop()) { intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); } if (mHostActivity != null) { final Intent hostIntent = mHostActivity.getIntent(); if (hostIntent != null) { final int hostCurrentId = hostIntent.getIntExtra(EXTRA_NAV_CURRENT, 0); if (hostCurrentId != 0) { intent.putExtra(EXTRA_NAV_SOURCE, hostCurrentId); } } } final int destId = destination.getId(); intent.putExtra(EXTRA_NAV_CURRENT, destId); NavOptions.addPopAnimationsToIntent(intent, navOptions); mContext.startActivity(intent); if (navOptions != null && mHostActivity != null) { int enterAnim = navOptions.getEnterAnim(); int exitAnim = navOptions.getExitAnim(); if (enterAnim != -1 || exitAnim != -1) { enterAnim = enterAnim != -1 enterAnim : 0; exitAnim = exitAnim != -1 exitAnim : 0; mHostActivity.overridePendingTransition(enterAnim, exitAnim); } } // You can't pop the back stack from the caller of a new Activity, // so we don't add this navigator to the controller's back stack dispatchOnNavigatorNavigated(destId, BACK_STACK_UNCHANGED);}
2.FragmentNavigator.navigate(...)
@Overridepublic void navigate(@NonNull Destination destination, @Nullable Bundle args, @Nullable NavOptions navOptions) { final Fragment frag = destination.createFragment(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); final StateFragment oldState = getState(); if (oldState != null) { ft.remove(oldState); } final @IdRes int destId = destination.getId(); final StateFragment newState = new StateFragment(); newState.mCurrentDestId = destId; ft.add(newState, StateFragment.FRAGMENT_TAG); final boolean initialNavigation = mFragmentManager.getFragments().isEmpty(); final boolean isClearTask = navOptions != null && navOptions.shouldClearTask(); // TODO Build first class singleTop behavior for fragments final boolean isSingleTopReplacement = navOptions != null && oldState != null && navOptions.shouldLaunchSingleTop() && oldState.mCurrentDestId == destId; if (!initialNavigation && !isClearTask && !isSingleTopReplacement) { ft.addToBackStack(getBackStackName(destId)); } else { ft.runOnCommit(new Runnable() { @Override public void run() { dispatchOnNavigatorNavigated(destId, isSingleTopReplacement BACK_STACK_UNCHANGED : BACK_STACK_DESTINATION_ADDED); } }); } ft.commit(); mFragmentManager.executePendingTransactions();}
3.NavGraphNavigation.navigate(...):
@Overridepublic void navigate(@NonNull NavGraph destination, @Nullable Bundle args, @Nullable NavOptions navOptions) { int startId = destination.getStartDestination(); if (startId == 0) { throw new IllegalStateException("no start destination defined via" + " app:startDestination for " + (destination.getId() != 0 NavDestination.getDisplayName(mContext, destination.getId()) : "the root navigation")); } NavDestination startDestination = destination.findNode(startId, false); if (startDestination == null) { final String dest = NavDestination.getDisplayName(mContext, startId); throw new IllegalArgumentException("navigation destination " + dest + " is not a direct child of this NavGraph"); } dispatchOnNavigatorNavigated(destination.getId(), BACK_STACK_DESTINATION_ADDED); startDestination.navigate(args, navOptions);}
看了源码是不是觉得其实很简单。
主要注意的是第三个NavGraphNavigator它其实也是一个转调,他将这个Bundle传递给了startDestination的navigate方法。也就是回到了NavDestination的navigate方法,其实也就是分情况调用ActivityNavigator或FragmentNavigator的Navigate。
2.通过ViewModle传参(只支持Fragment导航)
ViewModel也是Android JetPack中引入的一个lib(其实之前在android架构组建里已经被引入了),主要是为了解决在android/Fragment中onConfigrationChange导致的状态丢失问题,和Fragment的参数传递问题,因为很多时候依附在同一个activity伤的多个fragment其实是如果一个逻辑单元的。这个我将来应该也会专门介绍,不了解的同学可以把它想象成Activity/fragment的一个内部属性或者可以看看网上其他的关于ViewModel的教程。
在Fragment中使用:
?1ViewModelProviders.of(FragmentActivity)
获得Activity的ViewModel,只要多Fragment attach到的是同一个activity对象。那么他们返回ViewModel就是同一个,这样就不用关心Fragment。而只用在ViewModel中保存需要的属性,他们就可以在不同fragment之间共享啦。
3.通过官方专门添加的lib SafeArgs
需要在你的Root Project中添加如下依赖,添加后你的root Project依赖部分应该大致如下(注意红色部分):
buildscript { apply from:'dependencies.gradle' repositories { google() jcenter() } dependencies { classpath 'com.android.tools.build:gradle:3.2.0-alpha14' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "android.arch.navigation:navigation-safe-args-gradle-plugin:1.0.0-alpha01" // NOTE: Do not place your application dependencies here; they belong // in the inpidual module build.gradle files }}
并在你需要使用safeArgs的project的build.gradle中引入这个插件,引入后你的build.gradle大致如下(还是注意红色部分):
apply plugin: 'com.android.application'apply plugin: 'kotlin-android'apply plugin: 'kotlin-android-extensions'apply plugin: 'kotlin-kapt'apply plugin: 'androidx.navigation.safeargs'android { compileSdkVersion sdk_version defaultConfig { applicationId "com.example.xwh.myapplication" minSdkVersion rootProject.ext.mini_sdk_version versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } dexOptions { // Sets the maximum number of DEX processes // that can be started concurrently. maxProcessCount 8 // Sets the maximum memory allocation pool size // for the dex operation. javaMaxHeapSize "2g" // Enables Gradle to pre-dex library dependencies. preDexLibraries true }} dependencies { //do not modify dependencies here, modify in root project's depencencies.gradle implementation fileTree(include: ['*.jar'], dir: 'libs') def deps = rootProject.ext.project_dependencies.get(getProject().getName()) deps.libs.each { dep -> implementation dep } deps.textLibs.each { dep -> testImplementation dep } deps.androidTestLibs.each { dep -> androidTestImplementation dep } //java //deps.annceationProcessors.each { dep -> annotationProcessor dep } //kotlin deps.annceationProcessors.each { dep -> kapt dep } deps.projects.each { dep -> implementation project dep } //add other ext dependencies below }
然后你就可以在你的nav_graph.xml中通过 右侧的click+to add arguments按钮添加safeArgs了
添加之后要怎么做呢?你需要build这个项目,这个时候android studio会自动帮你生成几个类。他的生成规则是:你原Fragment的名称+'Directions',比如你的framgnet名称是FragmentA 那他就会帮你生成一个叫做FragmentADirections的类,这个类里还有一个静态内部类,名字为你在xml中定义的Action,如果你你这个fragment标签里有argument子标签(即配置过safeArg)。那么,这个静态内部类还会为你生成这些参数作为他的属性。这样你就可以愉快的传递参数了。传递参数的关键代码如下:
nav_graph.xml:
"@+id/fragmentStep2" tools:layout="@layout/fragment_step2" android:name="com.example.xwh.myapplication.FragmentStep2" android:label="FragmentStep2" > "test" android:defaultValue="11111" app:type="integer" /> "@+id/action_fragmentStep2_to_fragmentStep3" app:destination="@id/fragmentStep3" app:enterAnim="@anim/nav_default_enter_anim" app:exitAnim="@anim/nav_default_exit_anim" app:popEnterAnim="@anim/nav_default_pop_enter_anim" app:popExitAnim="@anim/nav_default_pop_exit_anim" />
跳转到Fragment的部分代码:(kotlin)
val directions = FragmentStep1Directions.action_step1_to_step2().run { setTest(111)}Navigation.findNavController(it) .navigate(directions)
自动生成的类:
public class FragmentStep1Directions { public static Action_step1_to_step2 action_step1_to_step2() { return new Action_step1_to_step2(); } public static class Action_step1_to_step2 implements NavDirections { private int test = 11111; public Action_step1_to_step2() { } public Action_step1_to_step2 setTest(int test) { this.test = test; return this; } public Bundle getArguments() { Bundle __outBundle = new Bundle(); __outBundle.putInt("test", this.test); return __outBundle; } public int getActionId() { return com.example.xwh.myapplication.R.id.action_step1_to_step2; } }}
参数接收:
val test = FragmentStep2Args.fromBundle(arguments).test
可以看到safeArgs还会帮你生成一个叫做"你的fragment名称"+‘Args’名称的类,其实参数真正的传递者还是fragment的arguments属性。
本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注职坐标移动开发之Android频道!
android final参数,Android应用开发之Android Jetpack-Navigation 使用中参数的传递方法相关推荐
- android ndk 多线程mk,NDK开发之Android.mk文件编写
8种机械键盘轴体对比 本人程序员,要买一个写代码的键盘,请问红轴和茶轴怎么选? 现在我们把android稍微写复杂些.在项目根目录下创建一个lib1文件夹 结构如图: test10.h和test11. ...
- 3G应用开发之Android 传智播客 基础知识总结
3G应用开发之Android Android应用开发之3G 3G应用开发之Android 3G应用开发之Android 应用开发之 讲师: 讲师:黎活明 北京传智 播客教育 www.itcast.c ...
- android 函数返回string,Android应用开发之android 对话框对于返回值的处理方法
本文将带你了解Android应用开发之android 对话框对于返回值的处理方法,希望本文对大家学Android有所帮助. android对话框是异步的,因此无法获得其返回值. 例如: 我们给出一个提 ...
- 镜像处理坐标 android,Android应用开发之Android重写ImageView实现图片镜像效果的代码教程...
本文将带你了解Android应用开发之Android重写ImageView实现图片镜像效果的代码教程,希望本文对大家学Android有所帮助. 前两天朋友问我一个问题,如何实现从手机系统相册加载一张图 ...
- android添加截图功能,Android应用开发之Android 5.0及以上编程实现屏幕截图功能的方法...
本文将带你了解Android应用开发Android 5.0及以上编程实现屏幕截图功能的方法,希望本文对大家学Android有所帮助. 本文实例讲述了Android 5.0及以上编程实现屏幕截图功能 ...
- android图片保存形式,Android应用开发之Android ScrollView截图和图片保存到相册的方式...
本文将带你了解Android应用开发之Android ScrollView截图和图片保存到相册的方式,希望本文对大家学Android有所帮助. 1.1首先来看你一种截取屏幕,这种代码有缺陷,只能截取一 ...
- android 开发art,Android应用开发之Android 系统启动原理(art 虚拟机)
本文将带你了解Android应用开发之Android 系统启动原理(art 虚拟机),希望本文对大家学Android有所帮助. Android 系统启动原理(art 虚拟机) 一.虚拟机的启动 A ...
- android 电量详情,Android应用开发之Android 8.0 电池-)耗电详情获取方法
本文将带你了解Android应用开发之Android 8.0 电池-)耗电详情获取方法,希望本文对大家学Android有所帮助. Android 8.0 电池-)耗电详情获取方法 主要介绍UI位置和基 ...
- android 接口实现方法,Android应用开发之Android 请求网络接口实现方法
本文将带你了解Android应用开发之Android 请求网络接口实现方法,希望本文对大家学Android有所帮助. public class Fragment01 extends Fragmen ...
最新文章
- Android 属性动画(Property Animation) ValueAnimator 的介绍
- Python3中global/nonlocal用法
- 简单套路发高分文章--杨树内生和根际微生物组结构
- java椭圆按钮_JAVA按钮重载如何实现椭圆按钮
- Centos 下 Nginx 信号控制
- Java定义接口变量为接收类型有什么好处(面向接口编程)
- Python机器学习基础教程-第2章-监督学习之K近邻
- C和指针 (pointers on C)——第七章:函数(上)
- @成都的Coder ,一起探讨终端架构持续演进
- android常见面试问题
- SAP Spartacus 关于列表点击focus Accessibility的需求
- LeetCode 445. 两数相加 II(链表大数加法)
- c语言中index函数,MATCH+INDEX函数详解
- 数据库期末知识点汇总
- OBS Studio是一款非常专业的视频直播录制软件,完全免费
- 【博士论文】深度学习的对抗攻击与鲁棒性测评
- mysql outer join报错_千与千寻-MySQL联结join
- opencv实战3-处理图像的颜色
- [原创]服装鞋帽企业配送中心优化方案 WMS仓储管理系统
- python 换脸 github_AI 换脸项目 ALAE 登顶 Github,AI 换脸又升级?
热门文章
- vue下载excel直接上代码
- 奔驰网络语言c class,重新定义豪华,全新一代奔驰C-Class正式官宣亮相
- oracle 19c驱动和18c的区别,什么是Oracle 18c的版本号?(What is the version number of Oracle 18c?)...
- 《操作系统实验》C++实现生产者-消费者问题
- 路演与答辩-技巧与展示
- 毫米波雷达数据处理_“毫米波雷达+5G”的新战场
- 代码生成器 websocket即时通讯 shiro redis 后台框架源码
- 华为h12m03装系统_Huawei MateBook 一键恢复出厂/重装系统/系统还原 操作指导
- 推荐一个永久45G,支持WebDav的海外网盘infiniCloud
- PS4怪物猎人世界服务器稳定吗,怪物猎人世界pc和ps4能联机吗 附两个版本画质对比...