Android TextView: «Не объединяйте текст, отображаемый с setText»

136

Я устанавливаю текст с помощью 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 () для форматирования чисел; он не будет правильно обрабатывать разделители дробей и цифры, зависящие от языка. Вместо этого рассмотрите возможность использования формата String # с соответствующими спецификациями формата (% d или% f).
  • Не передавайте строковый литерал (например, «Hello») для отображения текста. Жестко закодированный текст нельзя правильно перевести на другие языки. Вместо этого рассмотрите возможность использования строк ресурсов Android.
  • Не создавайте сообщения, объединяя фрагменты текста. Такие сообщения нельзя правильно перевести.

Что я могу для этого сделать? Кто-нибудь может помочь объяснить, что это за штука и что мне делать?

Пратик Бутани
источник
1
Это означает, что вам следует передать только Stringв setText(). Пример: setText(name)вместо setText("" + name). Потому что, если вы объедините текст, он не будет переведен, как если бы вы использовали жестко закодированный текст в качестве уведомления о сообщении,
г-н Нео
Но это даст, NPEесли nameбудетNULL
Pratik Butani
проверка nameнет NULLперед использованием setText()функции.
Мистер Нео
2
Вы не должны объединять строковый ресурс с некоторым значением, вместо этого используйте заполнители в строковом ресурсе. Итак, в своем 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/…
CodeBreakers

Ответы:

294

Ресурс имеет загружаемую версию getString, которая принимает varargsтип Object: getString (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 может обрабатывать нулевые значения. Если имя равно null, текст не будет отображаться.

Черный пояс
источник
1
предполагая, что на вашем BigDecimal вы вызовете значение с плавающей запятой: добавьте %1$fв свою строку в strings.xml, а затем вызовитеsetText(getString(R.string.string_product_rate_with_ruppe_sign, new BigDecimal(price).setScale(2, RoundingMode.UP).floatValue() ));
Blackbelt
это во второй части ответа. Посмотрите
Blackbelt
Я хочу показать целое число. Строка стоит $ s и десятичная $ d. Итак, целое число означает?
reegan29,
если вы имеете в виду "заполнитель", вы можете использовать %1$d. @ reegan29
Blackbelt
3
Для всех, кто ищет API, в котором перечислены типы форматов: developer.android.com/reference/java/util/Formatter#syntax
Брент
34

Не запутайтесь с % 1 $ s и % 2 $ d в принятом ответе. Вот несколько дополнительных сведений.

  • Спецификаторы формата могут иметь следующий синтаксис:

% [ argument_index$]format_specifier

  1. Необязательный параметр argument_index указывается как число, заканчивающееся на «$» после «%», и выбирает указанный аргумент в списке аргументов. На первый аргумент ссылается «1 $» , на второй - «2 $» и т. Д.
  2. Обязательный спецификатор формата - это символ, указывающий, как должен быть отформатирован аргумент. Набор допустимых преобразований для данного аргумента зависит от типа данных аргумента .

пример

Мы создадим следующую отформатированную строку, в которую серые части вставляются программно.

Привет Test! у вас есть 0новые сообщения

Ваш string resource:

<string name = "welcome_messages"> Здравствуйте %1$s! У вас есть %2$dновые сообщения </ string>

Выполните string substitutionследующие действия:

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

Примечание:

  • % 1 $ s будет заменен строкой "Test"
  • % 2 $ d будет заменен строкой "0"
Риссмон Суреш
источник
16

Я столкнулся с тем же сообщением об ошибке 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));
}

После этого моя ошибка исчезла. Поведение в приложении не изменилось, и мое количество продолжало отображаться так, как я хотел, теперь без ошибки ворса.

user1580203
источник
10

Вы должны проверить эту тему и использовать заполнитель, подобный его (не тестировался)

<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);
ThomasThiebaud
источник
10

Не объединяйте текст внутри вашего метода setText () , объединяйте все , что вы хотите, в String и помещайте это значение 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));
Ashana.Jackol
источник
Зачем? Какие преимущества у одного есть у другого?
Fureeish
4

проблема в том, что вы добавляете ""в начале каждой строки.

lint просканирует передаваемые аргументы setTextи выдаст предупреждения, в вашем случае актуально следующее предупреждение:

Не создавайте сообщения, объединяя фрагменты текста. Такие сообщения нельзя правильно перевести.

поскольку вы объединяете каждую строку с "".

удалите эту конкатенацию, поскольку передаваемые вами аргументы уже являются текстовыми. Кроме того, вы можете использовать, .toString()если это вообще необходимо, в другом месте вместо конкатенации вашей строки с""

Рахул Тивари
источник
0

Если вам не нужна поддержка i18n, вы можете отключить эту проверку ворса в Android Studio.

Файл -> Настройки -> Редактор -> Инспекции -> Android -> Lint -> Интернационализация TextView (снимите этот флажок)

ssynhtn
источник
0

Вы можете использовать это, это работает для меня

title.setText(MessageFormat.format("{0} {1}", itemList.get(position).getOppName(), itemList.get(position).getBatchNum()));
Бахман Карами
источник
0
prodNameView.setText("" + name); //this produce lint error

val nameStr="" + name;//workaround for quick warning fix require rebuild
prodNameView.setText(nameStr);
Скорпен
источник
-1

Не сходите с ума, это слишком просто.

String firstname = firstname.getText().toString();
String result = "hi "+ firstname +" Welcome Here";
            mytextview.setText(result);
mwaqas
источник