英文:
How is safe args in navigation component type safe (Android)?
问题
在正常的片段事务中,我们会将数据传递如下:
Fragment fragment = new Fragment();
Bundle bundle = new Bundle();
bundle.putInt(key, value);
fragment.setArguments(bundle);
这也是类型安全的吗?
那么当我们说安全参数是类型安全时,这意味着什么?
当我们说安全参数是类型安全时,确切地说类型安全是什么意思?
提前感谢!
英文:
In a normal fragment transaction we would pass data as:
Fragment fragment = new Fragment();
Bundle bundle = new Bundle();
bundle.putInt(key, value);
fragment.setArguments(bundle);
Isn't this type safe too?
So what does it mean when we say that safe args are type safe?
What exactly does type safety mean when we say that safe args are type safe?
Thanks in advance!
答案1
得分: 2
Sure, here is the translated text:
是的,您提供了在片段之间传递参数的常规方式。这是类型安全的,因为 Bundle
类提供了用于存储和获取不同类型数据的 API。这意味着您不会遇到使用它时的 ClassCastException
(详细解释见下文)。
> 那么当我们说安全参数是类型安全时,这意味着什么?
我想您在谈论 安全参数,它是一种为 Android 提供了一种类型安全且易于使用的机制,用于在 Android 导航组件中传递数据的 Gradle 插件。
使用 Safe Args,您可以在 XML 文件中为每个目标定义参数,插件会为每个目标生成一个强类型的类,其中包含每个参数的访问方法。这些类有助于确保参数是正确类型的,并防止因不正确的参数值而引起的运行时错误。这使得这种传递参数的方式是类型安全的,您可以在使用 Android 导航组件 时使用它。
因此,您可以像这样定义您的片段:
<fragment
android:id="@+id/destination_fragment"
android:name="packageName.DestinationFragment">
<argument
android:name="firstArg"
app:argType="integer"
android:defaultValue="0" />
<argument
android:name="secondArg"
app:argType="string"
android:defaultValue="" />
</fragment>
然后,使用 Safe Args 传递参数启动此片段:
val action = FragmentDirections.actionSourceFragmentToDestinationFragment(firstArg = 12345, secondArg = "Hello World!")
findNavController().navigate(action)
更新
当您使用标准的方式在片段之间传递对象时,它在编译时不会被检查。因此,例如,如果您将 Int
值放入 Bundle
中,并尝试使用相同的键获取 String
,它将返回默认值。
例如,在下面的示例中,value
变量的值将为 null:
val bundle = Bundle().apply {
putInt("key", 1)
}
val value = bundle.getString("key")
println(value) // null!
您可以看到为什么会发生这种情况,这是因为 BaseBundle.getString()
方法:
@Nullable
public String getString(@Nullable String key) { // key = "hey"
unparcel();
final Object o = mMap.get(key); // 这里我们得到了 Integer = 1
try {
return (String) o; // 尝试将 Integer 强制转换为 String
} catch (ClassCastException e) {
typeWarning(key, o, "String", e);
return null; // 捕获到 ClassCastException => 返回 null!
}
}
英文:
Yes, you provided the regular form of passing arguments between fragments. This is type safe because Bundle
class provide API to put and get data of different types. It means that you will not encounter ClassCastException
using it (see detailed explanation below)
> So what does it mean when we say that safe args are type safe?
I presume you're talking about Safe args, which is a Gradle plugin for Android that provides a type-safe and easy-to-use mechanism for passing data between destinations in the Android Navigation component.
With Safe Args, you define the arguments for each destination in an XML file, and the plugin generates a strongly-typed class for each destination that contains accessor methods for each argument. These classes help to ensure that the arguments are of the correct type and prevent runtime errors caused by incorrect argument values. That makes this way of passing type safe and you can use it when you're using Android Navigation component.
So you can define your fragments like this:
<fragment
android:id="@+id/destination_fragment"
android:name="packageName.DestinationFragment">
<argument
android:name="firstArg"
app:argType="integer"
android:defaultValue="0" />
<argument
android:name="secondArg"
app:argType="string"
android:defaultValue="" />
</fragment>
And start this fragment, passing arguments with Safe Args:
val action = FragmentDirections.actionSourceFragmentToDestinationFragment(firstArg = 12345, secondArg = "Hello World!")
findNavController().navigate(action)
Update
When you use the standard way of passing objects between fragments, it is not being checked on the compile time. So for instance, if you put Int
value in a Bundle
and try to get a String
with a same key it will return the default value.
For example the value of value
variable will be null in the example below:
val bundle = Bundle().apply {
putInt("key", 1)
}
val value = bundle.getString("key")
println(value) // null!
You can see why it happens in a BaseBundle.getString()
method:
@Nullable
public String getString(@Nullable String key) { // key = "hey"
unparcel();
final Object o = mMap.get(key); // Here we got Integer = 1
try {
return (String) o; // Trying to cast Integer to String
} catch (ClassCastException e) {
typeWarning(key, o, "String", e);
return null; // ClassCastException was caught => return null!
}
}
答案2
得分: 0
Regarding to type safe Bundle
, I recently build a tool to achieve that.
Leverage on some Kotlin feature (value class, extension function, etc), we can easily use Bundle
in a much safer way.
Example usage:
val textKey = StringKey("SomeStringKey")
val intKey = IntKey("SomeIntKey")
val bundle = Bundle()
bundle.put(textKey, "Some text") // only String value is acceptable
bundle.put(intKey, 12345) // only Int value is acceptable
val text = bundle.get(textKey, "") // guarantee result to be a String
val int = bundle.get(intKey, -1) // guarantee result to be an Int
The concept is we associate type info in the key string like StringKey
, IntKey
where it's a value class in Kotlin will compile back to String
in the end but able to provide type information at build time.
And the extension function get
and set
will check these info to ensure everything is matched.
GitHub link: https://github.com/Jintin/TypedBundle
英文:
Regarding to type safe Bundle
, I recently build a tool to achieve that.
Leverage on some Kotlin feature (value class, extension function, etc), we can easily use Bundle
in a much safer way.
Example usage:
val textKey = StringKey("SomeStringKey")
val intKey = IntKey("SomeIntKey")
val bundle = Bundle()
bundle.put(textKey, "Some text") // only String value is acceptable
bundle.put(intKey, 12345) // only Int value is acceptable
val text = bundle.get(textKey, "") // guarantee result to be a String
val int = bundle.get(intKey, -1) // guarantee result to be an Int
The concept is we associate type info in the key string like StringKey
, IntKey
where it's a value class in Kotlin will compile back to String
in the end but able to provide type information at build time.
And the extension function get
and set
will check these info to ensure everything is matched.
github link : https://github.com/Jintin/TypedBundle
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论