Kotlin-Java互操作不适用于varargs

我想抽象出在Android获取资源的方法,因此编写了一个类ResourceProvider,该类实际上提供了资源:

@Singleton
class ResourceProvider @Inject constructor(private val context: Context) {
fun getString(@StringRes id: Int): String {
    return context.getString(id)
}

fun getString(@StringRes id: Int, vararg formatArgs: Any): String {
    return context.getString(id, formatArgs)
}
...
}

这里没什么特别的,只是在Context上调用方法.
当我想使用参数获取String时遇到问题,我创建了以下示例:

var fromContext = requireContext().getString(R.string.one_parameter_string, "Text")
Log.i("fromContext", fromContext)
var fromWrapper = resourceProvider.getString(R.string.one_parameter_string, "Text")
Log.i("fromWrapper", fromWrapper)

fromContext = requireContext().getString(R.string.two_parameter_string, "Text", "Text")
Log.i("fromContext", fromContext)
fromWrapper = resourceProvider.getString(R.string.two_parameter_string, "Text", "Text")
Log.i("fromWrapper", fromWrapper)

以下是String资源:

<string formatted="false" name="two_parameter_string">Text with parameters: %s, %s</string>
<string formatted="false" name="one_parameter_string">Text with parameter: %s</string>

如您所见,我直接在Context和ResourceProvider类上调用了相同的方法.我希望得到相同的结果,但实际上这是控制台中打印的内容

I/fromContext: Text with parameter: Text
I/fromWrapper: Text with parameter: [Ljava.lang.Object;@6d43f06
I/fromContext: Text with parameters: Text, Text
D/AndroidRuntime: Shutting down VM
E/AndroidRuntime: FATAL EXCEPTION: main
    Process: xxx.xxx.xxx, PID: 22963
    java.util.MissingFormatArgumentException: Format specifier '%s'
        at java.util.Formatter.format(Formatter.java:2522)
        at java.util.Formatter.format(Formatter.java:2458)
        at java.lang.String.format(String.java:2814)
        at android.content.res.Resources.getString(Resources.java:472)
        at android.content.Context.getString(Context.java:572)
        at xxx.xxx.xxx.utils.ResourceProvider.getString(ResourceProvider.kt:21)
        at xxx.xxx.xxx.views.trial.TrialFragment.onViewCreated(TrialFragment.kt:45)
        at androidx.fragment.app.FragmentManagerImpl.movetoState(FragmentManager.java:1471)
        at androidx.fragment.app.FragmentManagerImpl.addAddedFragments(FragmentManager.java:2646)
        at androidx.fragment.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2416)
        at androidx.fragment.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManager.java:2372)
        at androidx.fragment.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:2273)
        at androidx.fragment.app.FragmentManagerImpl$1.run(FragmentManager.java:733)
        at android.os.Handler.handleCallback(Handler.java:789)
        at android.os.Handler.dispatchMessage(Handler.java:98)
        at android.os.Looper.loop(Looper.java:164)
        at android.app.ActivityThread.main(ActivityThread.java:6944)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)

如您所见,直接在Context上调用它没有缺陷,但是使用我的包装器调用相同的方法使它打印Object.toString(),在第二种情况下崩溃.

这是getString(@StringRes id:Int,vararg formatArgs:Any)方法的反编译版本:

@NotNull
public final String getString(@StringRes int id, @NotNull Object... formatArgs) {
  Intrinsics.checkParameterIsNotNull(formatArgs, "formatArgs");
  String var10000 = this.context.getString(id, new Object[]{formatArgs});
  Intrinsics.checkExpressionValueIsNotNull(var10000, "context.getString(id, formatArgs)");
  return var10000;
}

有什么问题以及如何解决

解决方法:

您需要使用传播运算符(*)来调用context.getString,即,您需要使用* formatArgs:

@Singleton
class ResourceProvider @Inject constructor(private val context: Context) {
  fun getString(@StringRes id: Int): String {
    return context.getString(id)
  }

  fun getString(@StringRes id: Int, vararg formatArgs: Any): String {
    return context.getString(id, *formatArgs)
  }
...
}

您可以在kotlin reference regarding variable number of arguments (varargs)中了解更多信息.

如果不这样做,则将给定对象(在本例中为formatArgs-array)视为要传递给vararg方法的单个对象,该对象因此将被包装到Object [] {formatArgs }.

相关文章

Android性能优化——之控件的优化 前面讲了图像的优化,接下...
前言 上一篇已经讲了如何实现textView中粗字体效果,里面主要...
最近项目重构,涉及到了数据库和文件下载,发现GreenDao这个...
WebView加载页面的两种方式 一、加载网络页面 加载网络页面,...
给APP全局设置字体主要分为两个方面来介绍 一、给原生界面设...
前言 最近UI大牛出了一版新的效果图,按照IOS的效果做的,页...