【问题标题】:Android TextView : "Do not concatenate text displayed with setText"Android TextView:“不要用 setText 连接显示的文本”
【发布时间】:2016-01-14 21:02:06
【问题描述】:

我正在通过以下方式使用 setText() 设置文本。

prodNameView.setText("" + name);

prodOriginalPriceView.setText("" + String.format(getString(R.string.string_product_rate_with_ruppe_sign), "" + new BigDecimal(price).setScale(2, RoundingMode.UP)));

其中第一个是简单使用,第二个是设置文本和格式化文本。

Android Studio 非常有趣,我使用了菜单 Analyze -> Code Cleanup,我得到了上面两行的建议。

不要连接用 setText 显示的文本。使用资源字符串 与占位符。少... (Ctrl+F1)

当调用 TextView#setText:

  • 永远不要调用 Number#toString() 来格式化数字;它不会正确处理分数分隔符和特定于语言环境的数字。考虑 使用具有正确格式规范(%d 或 %f)的 String#format 反而。
  • 不要传递字符串文字(例如“Hello”)来显示文本。硬编码文本无法正确翻译成其他语言。 考虑改用 Android 资源字符串。
  • 不要通过连接文本块来构建消息。此类消息无法正确翻译。

为此我能做些什么?任何人都可以帮助解释这是什么以及我应该怎么做?

【问题讨论】:

  • 这意味着您应该只将String 传递给setText()。例如:setText(name) 而不是 setText("" + name)。因为如果你连接文本,它不会像你使用硬编码文本作为消息通知那样被翻译
  • 但是如果nameNULL,它会给出NPE
  • 在使用setText()函数之前检查name不是NULL
  • 您不应将字符串资源与某些值连接,而应在字符串资源中使用占位符。所以在你的 string.xml 你做:<string name="string_product_rate_with_ruppe_sign">Something %1$d</string> 在你的 java 代码中你做这样的事情:prodOriginalPriceView.setText(getString(R.string.string_product_rate_with_ruppe_sign), price);(你可以在 xml 文件中进行格式化:[developer.android.com/guide/topics/resources/…

标签: android concatenation textview string-concatenation


【解决方案1】:

Resource 具有 getString 的 get 重载版本,它采用 Object 类型的 varargsgetString(int, java.lang.Object...)。如果您在 strings.xml 中正确设置了字符串,并使用了正确的占位符,则可以使用此版本来检索最终字符串的格式化版本。例如。

<string name="welcome_messages">Hello, %1$s! You have %2$d new messages.</string>

使用getString(R.string.welcome_message, "Test", 0);

android 将返回一个带有

的字符串
 "Hello Test! you have 0 new messages"

关于 setText("" + name);

您的第一个示例 prodNameView.setText("" + name); 对我来说没有任何意义。 TextView 能够处理空值。如果 name 为 null,则不会绘制任何文本。

【讨论】:

  • 假设您将在 BigDecimal 上调用浮点值:在 strings.xml 中将 %1$f 添加到您的字符串,然后调用 setText(getString(R.string.string_product_rate_with_ruppe_sign, new BigDecimal(price).setScale(2, RoundingMode.UP).floatValue() ));
  • 它在答案的第二部分。看看
  • 我想显示一个整数 .String 代表 $s 和十进制 $d。所以整数代表?
  • 如果您指的是“占位符”,您可以使用%1$d。 @reegan29
  • 对于寻找列出格式类型的 API 的任何人:developer.android.com/reference/java/util/Formatter#syntax
【解决方案2】:

不要与接受的答案中的 %1$s%2$d 混淆。这里有一些额外的信息。

  • 格式说明符可以是以下语法:

%[argument_index$]format_specifier

  1. 可选的argument_index被指定为在“%”之后以“$”结尾的数字,并在参数列表中选择指定的参数。第一个参数由 "1$" 引用,第二个参数由 "2$" 引用,依此类推。
  2. 必需的格式说明符是一个字符,指示应如何格式化参数。给定参数的有效转换集取决于参数的数据类型。

示例

我们将创建以下格式化字符串,其中灰色部分以编程方式插入。

你好Test!你有0 新消息

你的string resource

你好,%1$s!你有%2$d新 消息

执行string substitution,如下所示:

getString(R.string.welcome_message, "Test", 0);

注意:

  • %1$s 将替换为字符串“Test”
  • %2$d 将替换为字符串“0”

【讨论】:

    【解决方案3】:

    我遇到了相同的 lint 错误消息并以这种方式解决了它。

    最初我的代码是:

    private void displayQuantity(int quantity) {
        TextView quantityTextView = (TextView) findViewById(R.id.quantity_text_view);
        quantityTextView.setText("" + quantity);
    }
    

    我收到以下错误

    Do not concatenate text displayed with setText. Use resource string with placeholders.
    

    所以,我将此添加到strings.xml

    <string name="blank">%d</string>
    

    这是我的初始“”+我的数字(数量)的占位符。

    注意:我的quantity 变量是之前定义的,是我想附加到字符串的。结果我的代码是

    private void displayQuantity(int quantity) {
        TextView quantityTextView = (TextView) findViewById(R.id.quantity_text_view);
        quantityTextView.setText(getString(R.string.blank, quantity));
    }
    

    在此之后,我的错误消失了。应用程序中的行为没有改变,我的数量继续按我想要的方式显示,没有出现 lint 错误。

    【讨论】:

      【解决方案4】:

      不要在你的 setText() 方法中连接文本,在 String 中连接你想要的任何内容,并将该字符串值放入你的 setText() 方法。

      例如:正确的方法

      int min = 120;
      int sec = 200;
      int hrs = 2;
      
      String minutes = String.format("%02d", mins);
      String seconds = String.format("%02d", secs);
      String newTime = hrs+":"+minutes+":"+seconds;
      
      text.setText(minutes);
      

      不要在 setText() 中像

      那样连接
      text.setText(hrs+":"+String.format("%02d", mins)+":"+String.format("%02d", secs));
      

      【讨论】:

      • 为什么?两者各有什么优势?
      • 这是一个便宜的骗子。使用 '@SuppressLint("SetTextI18n")' 会更容易。
      【解决方案5】:

      您应该检查此thread 并使用像他的占位符(未测试)

      <string name="string_product_rate_with_ruppe_sign">Price : %1$d</string>
      
      String text = String.format(getString(R.string.string_product_rate_with_ruppe_sign),new BigDecimal(price).setScale(2, RoundingMode.UP));
      prodOriginalPriceView.setText(text);
      

      【讨论】:

        【解决方案6】:

        问题是因为您在每个字符串的开头附加了""

        lint 将扫描传递给 setText 的参数并生成警告,在您的情况下,以下警告是相关的:

        不要通过以下方式构建消息 连接文本块。这样的消息不能正确 已翻译。

        当您将每个字符串与"" 连接时。

        删除此连接,因为您传递的参数已经是文本。此外,如果在其他任何地方都需要,您可以使用.toString(),而不是使用"" 连接您的字符串

        【讨论】:

          【解决方案7】:

          别生气,这太简单了。

          String firstname = firstname.getText().toString();
          String result = "hi "+ firstname +" Welcome Here";
                      mytextview.setText(result);
          

          【讨论】:

            【解决方案8】:

            你可以用这个,它对我有用

            title.setText(MessageFormat.format("{0} {1}", itemList.get(position).getOppName(), itemList.get(position).getBatchNum()));
            

            【讨论】:

              【解决方案9】:

              如果您不需要支持 i18n,可以在 Android Studio 中禁用此 lint 检查

              文件 -> 设置 -> 编辑器 -> 检查 -> Android -> Lint -> TextView 国际化(取消选中此项)

              【讨论】:

              • @SuppressLint("SetTextI18n") 采用不太激进的方法。
              【解决方案10】:
              prodNameView.setText("" + name); //this produce lint error
              
              val nameStr="" + name;//workaround for quick warning fix require rebuild
              prodNameView.setText(nameStr);
              

              【讨论】:

                【解决方案11】:

                我使用 String.format 修复了它

                之前:

                textViewAddress.setText("Address"+address+"\n"+"nCountry"+"\n"+"City"+"city"+"\n"+"State"+"state")
                

                之后:

                textViewAddress.setText(
                     String.format("Address:%s\nCountry:%s\nCity:%s\nState:%s", address, country, city, state));
                       
                

                【讨论】:

                  【解决方案12】:

                  如果是 textView,你可以这样使用:myTextView.text = ("Hello World") 在 editText 你可以使用 myTextView.setText("Hello World")

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2013-04-30
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    相关资源
                    最近更新 更多