Fixed
Status Update
Comments
il...@google.com <il...@google.com> #2
From what I can see, this is already the case when Safe Args generates Kotlin code (when you use apply plugin: 'androidx.navigation.safeargs.kotlin'), so this looks like an issue solely on the Java code gen.
an...@gmail.com <an...@gmail.com> #3
I just checked with kotlin codegen, it is working fine. I agree, it seems like a problem solely with java codegen. It doesn't comply with the Kotlin generated SafeArg data classes.
ap...@google.com <ap...@google.com> #4
Project: platform/frameworks/support
Branch: androidx-master-dev
commit 749f41de3d69a818277551fdbe11c3856cb9dfb9
Author: Jeremy Woods <jbwoods@google.com>
Date: Fri Oct 04 10:48:26 2019
Generate default values for safe_args in Java
Currently the safe args generation for java code does not contain
default Arg values. The default arg values are provided by the Kotlin
safe args generation and we should be as uniform as possible across both
languages.
Test: ./gradlew --rerun-tasks navigation:navigation-safe-args-gradle-plugin:test
navigation:navigation-safe-args-generator:test
BUG: 140123727
Change-Id: I43447755e29d6640e227b5608ca2fd3ea1a45e0b
M navigation/navigation-safe-args-generator/src/main/kotlin/androidx/navigation/safe/args/generator/java/JavaNavWriter.kt
M navigation/navigation-safe-args-generator/src/tests/test-data/expected/java_nav_writer_test/MainFragmentArgs.java
https://android-review.googlesource.com/1133164
https://goto.google.com/android-sha1/749f41de3d69a818277551fdbe11c3856cb9dfb9
Branch: androidx-master-dev
commit 749f41de3d69a818277551fdbe11c3856cb9dfb9
Author: Jeremy Woods <jbwoods@google.com>
Date: Fri Oct 04 10:48:26 2019
Generate default values for safe_args in Java
Currently the safe args generation for java code does not contain
default Arg values. The default arg values are provided by the Kotlin
safe args generation and we should be as uniform as possible across both
languages.
Test: ./gradlew --rerun-tasks navigation:navigation-safe-args-gradle-plugin:test
navigation:navigation-safe-args-generator:test
BUG: 140123727
Change-Id: I43447755e29d6640e227b5608ca2fd3ea1a45e0b
M navigation/navigation-safe-args-generator/src/main/kotlin/androidx/navigation/safe/args/generator/java/JavaNavWriter.kt
M navigation/navigation-safe-args-generator/src/tests/test-data/expected/java_nav_writer_test/MainFragmentArgs.java
jb...@google.com <jb...@google.com> #5
This has been fixed internally and will be available in the Navigation 2.2.0-beta01 release.
an...@gmail.com <an...@gmail.com> #6
Many many thanks for fixing this. Waiting for the release.
ra...@gmail.com <ra...@gmail.com> #7
Null Default value for a string, returns "@null"
<argument
android:name="deepLinkToken"
android:defaultValue="@null"
app:argType="string"
app:nullable="true" />
```
And if I do
```
val args by navArgs<FragmentArgs>()
args.deepLinkToken // returns "@null@
```
Using '2.2.0-rc02'
<argument
android:name="deepLinkToken"
android:defaultValue="@null"
app:argType="string"
app:nullable="true" />
```
And if I do
```
val args by navArgs<FragmentArgs>()
args.deepLinkToken // returns "@null@
```
Using '2.2.0-rc02'
jb...@google.com <jb...@google.com> #8
Re #7 - please file a separate bugs with a project that reproduce your separate issue. If the issue you are mentioning is covered by https://issuetracker.google.com/issues/141613546 , feel free to +1.
Description
Version used: 2.1.0-rc01
Devices/Android versions reproduced on:
Proposal: Safe Arg generated Builder Classes should have default values inside.
This is actually not a bug for navigation component but a kind of side effect which can make this feature more versatile.
In my scenario, we were trying to use generated safe arg Builder classes to pass arguments to the fragments in our project, as the normal bundle arguments are not type safe and kinda messy to work with.
The project I'm working on is relative large, in our team we decided to migrate gradually to navigation component.
As a first step we wanted to put the fragment in a nav graph just to generate safe args so that we can use those classes to safely pass arguments to our existing fragment with fragment transaction and eventually use the graph in future point. So we are trying to use Safe arg as mentioned below:
ChoosePackageFragmentArgs args =
new ChoosePackageFragmentArgs.Builder("testName", "testPackage")
.setIsExtend(true)
.build();
ChoosePackageFragment fragment = new ChoosePackageFragment();
fragment.setArguments(args.toBundle());
getSupportFragmentManager().beginTransaction()
.replace(R.id.container, fragment)
.addToBackStack(null)
.commit();
As you can see from the above example the "isExtend" property is optional and has a default value false which is set in the graph like this,
<argument
android:name="isExtend"
app:argType="boolean"
android:defaultValue="false" />
However if we use the generated safe arg builder class (ChoosePackageFragmentArgs) to pass the arguments to ChoosePackageFragment, without setting "isExtend" the ChoosePackageFragmentArgs.fromBundle(requireArguments()).getIsExtend() throws a NullPointerException because the builder doesn't set the default value when we call the args.toBundle() on the builder instance.
Moreover, when we try to call the getter method it can't find a value from the map, so it tries to cast a null value to (boolean), thus throwing the NullPointerException. Remember we're not using a NavController, just trying to take advantage of SafeArg feature.
This is the code from ChoosePackageFragmentArgs.Builder:
public class ChoosePackageFragmentArgs implements NavArgs {
....
@SuppressWarnings("unchecked")
public boolean getIsExtend() {
return (boolean) arguments.get("isExtend");
}
...
}
We were wondering why the default value is not present in the object. After digging for a while we've found that NavController.navigate() pulls the default values from NavAction.getDefaultArguments(); as we're not using NavComponent we're actually not getting the default value from Builder. Here's the code that pulls default args in NavComponent Library.
Code from NavController.java:
final NavAction navAction = currentNode.getAction(resId);
Bundle combinedArgs = null;
if (navAction != null) {
if (navOptions == null) {
navOptions = navAction.getNavOptions();
}
destId = navAction.getDestinationId();
Bundle navActionArgs = navAction.getDefaultArguments();
if (navActionArgs != null) {
combinedArgs = new Bundle();
combinedArgs.putAll(navActionArgs);
}
}
Suggestion:
If the safe arg plugin added the default values to the Builder while generating those SafeArgs Builder classes, the conventional fragment approach could get huge benefit out of it, and as these classes are accessible apis, I believe it makes more sense to have predictable behaviour for Builder classes as that seems like a standard predictable behaviour.