Застарілий Html.fromHtml в Android N


300

Я використовую Html.fromHtmlдля перегляду html у TextView.

Spanned result = Html.fromHtml(mNews.getTitle());
...
...
mNewsTitle.setText(result);

Але Html.fromHtmlтепер застаріла в Android N +

Що / Як знайти новий спосіб зробити це?

Відповіді:


616

оновлення : як зазначено нижче @Andy, компанія Google створила HtmlCompatзамість наведеного нижче методу. Додайте цю залежність implementation 'androidx.core:core:1.0.1 у файл build.gradle свого додатка. Переконайтеся, що ви використовуєте останню версію androidx.core:core.

Це дозволяє використовувати:

HtmlCompat.fromHtml(html, HtmlCompat.FROM_HTML_MODE_LEGACY);

Більше про різні прапори ви можете прочитати на HtmlCompat-документації

оригінальна відповідь: В Android N вони запровадили новий Html.fromHtmlметод. Html.fromHtmlтепер потрібен додатковий параметр, названий прапорами. Цей прапор дає вам більше контролю над тим, як відображається ваш HTML-код.

На Android N і вище слід використовувати цей новий метод. Старіший метод застарілий і може бути видалений у майбутніх версіях Android.

Ви можете створити власний Util-метод, який використовуватиме старий метод на старих версіях та новіший метод на Android N і вище. Якщо ви не додаєте версію, перевірте, що ваш додаток не працює на нижчих версіях Android. Ви можете використовувати цей метод у своєму класі Util.

@SuppressWarnings("deprecation")
public static Spanned fromHtml(String html){
    if(html == null){
        // return an empty spannable if the html is null
        return new SpannableString("");
    }else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        // FROM_HTML_MODE_LEGACY is the behaviour that was used for versions below android N
        // we are using this flag to give a consistent behaviour
        return Html.fromHtml(html, Html.FROM_HTML_MODE_LEGACY);
    } else {
        return Html.fromHtml(html);
    }
}

Ви можете перетворити HTML.FROM_HTML_MODE_LEGACYв додатковий параметр, якщо хочете. Це дає вам більше контролю над тим, який прапор використовувати.

Ви можете прочитати більше про різні прапори в документації до класу Html


2
Який прапор позначає нуль?
заборона-геоінженерія

4
Html.FROM_HTML_MODE_LEGACY
заборона-геоінженерія

14
ах, чекаючи, коли з’явиться щось на зразок HtmlCompat
vanomart

12
Також корисно додати //noinspection deprecationкоментар просто під заголовком, elseщоб уникнути попереджень про ворсинки.
Тед Хопп

1
Ви можете побачити, що робить кожен із цих прапорів у цьому дописі в блозі: medium.com/@yair.kukielka/…
Яїр Кукієлка,

95

У мене було багато цих попереджень, і я завжди використовую FROM_HTML_MODE_LEGACY, тому я створив помічник класу під назвою HtmlCompat, що містить наступне:

   @SuppressWarnings("deprecation")
   public static Spanned fromHtml(String source) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            return Html.fromHtml(source, Html.FROM_HTML_MODE_LEGACY);
        } else {
            return Html.fromHtml(source);
        }
    }

2
Такий же ефект, як прийнята відповідь, але +1 через анотацію SuppressWarnings
Стойчо Андрєєв,

Чи можете ви дати невелике пояснення щодо цього режиму?
Ранджіт Кумар

ви можете надати всі HtmlCompact може бути на git hub, це виглядає круто
shareef

@shareef Я б хотів, але це справді просто нудний клас корисності з цим єдиним методом в ньому ....
k2col

61

Порівняйте прапори відHtml ().

<p style="color: blue;">This is a paragraph with a style</p>

<h4>Heading H4</h4>

<ul>
   <li style="color: yellow;">
      <font color=\'#FF8000\'>li orange element</font>
   </li>
   <li>li #2 element</li>
</ul>

<blockquote>This is a blockquote</blockquote>

Text after blockquote
Text before div

<div>This is a div</div>

Text after div

FROM_HTML ФЛАГИ


Чи можете ви поділитися вхідним HTML також? Це допоможе краще зрозуміти конверсію.
Kalpesh Patel

Я бачу, що атрибути стилю не реалізовані, чи є спосіб їх реалізувати?
Крістін


25

Якщо вам пощастило розвиватися в Kotlin, просто створіть функцію розширення:

fun String.toSpanned(): Spanned {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        return Html.fromHtml(this, Html.FROM_HTML_MODE_LEGACY)
    } else {
        @Suppress("DEPRECATION")
        return Html.fromHtml(this)
    }
}

І тоді так солодко використовувати його всюди:

yourTextView.text = anyString.toSpanned()

5
ви можете зберегти типізації, видаливши Spannedтаreturn
Minami

14

відHtml

Цей метод був застарілий у рівні 24 API .

Слід використовувати FROM_HTML_MODE_LEGACY

Окремі елементи на рівні блоку з порожніми рядками (два символи нового рядка) між ними. Це спадкова поведінка до Н.

Код

if (Build.VERSION.SDK_INT >= 24)
        {
            etOBJ.setText(Html.fromHtml("Intellij \n Amiyo",Html.FROM_HTML_MODE_LEGACY));

         }
 else
        {
           etOBJ.setText(Html.fromHtml("Intellij \n Amiyo"));
        }

Для Котліна

fun setTextHTML(html: String): Spanned
    {
        val result: Spanned = if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
            Html.fromHtml(html, Html.FROM_HTML_MODE_LEGACY)
        } else {
            Html.fromHtml(html)
        }
        return result
    }

Дзвінок

 txt_OBJ.text  = setTextHTML("IIT Amiyo")

Чи можете ви дати невелике пояснення щодо цього режиму?
Ранджіт Кумар

якщо ви хочете, щоб SDK обробляв перевірки версій, використовуйте: HtmlCompat.fromHtml("textWithHtmlTags", HtmlCompat.FROM_HTML_MODE_LEGACY)
Wajid Ali

8

Від офіційного документа:

fromHtml(String)метод API був застарілий у рівні 24 API fromHtml(String, int) .

  1. TO_HTML_PARAGRAPH_LINES_CONSECUTIVEВаріант для toHtml(Spanned, int): Обертання послідовних рядків тексту, розділених '\n'внутрішніми <p> елементами.

  2. TO_HTML_PARAGRAPH_LINES_INDIVIDUALВаріант для toHtml(Spanned, int): Оберніть кожен рядок тексту, розміщений '\n'всередині а <p>чи <li> елементом.

https://developer.android.com/reference/android/text/Html.html


8

Якщо ви використовуєте Kotlin , я досяг цього, використовуючи розширення Kotlin:

fun TextView.htmlText(text: String){
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        setText(Html.fromHtml(text, Html.FROM_HTML_MODE_LEGACY))
    } else {
        setText(Html.fromHtml(text))
    }
}

Тоді називайте це так:

textView.htmlText(yourHtmlText)

5

Просто для розширення відповіді від @Rockney та @ k2col покращений код може виглядати так:

@NonNull
public static Spanned fromHtml(@NonNull String html) {
    if (CompatUtils.isApiNonLowerThan(VERSION_CODES.N)) {
        return Html.fromHtml(html, Html.FROM_HTML_MODE_LEGACY);
    } else {
        //noinspection deprecation
        return Html.fromHtml(html);
    }
}

Де CompatUtils.isApiNonLowerThan:

public static boolean isApiNonLowerThan(int versionCode) {
    return Build.VERSION.SDK_INT >= versionCode;
}

Різниця полягає в тому, що додаткової локальної змінної немає та депрекація є лише у elseгалузі. Таким чином, це не буде придушувати всіх методів, а єдину гілку.

Це може допомогти, коли Google вирішить у деяких майбутніх версіях Android знехтувати навіть fromHtml(String source, int flags)метод.


4

Можна використовувати

//noinspection deprecation
return Html.fromHtml(source);

придушити перевірку лише на одне твердження, але не на весь метод.


2

Рамковий клас було змінено, щоб вимагати прапор для інформування fromHtml() як обробляти розриви рядків. Це було додано в Nougat і стосується лише проблеми несумісності цього класу для версій Android.

Я опублікував бібліотеку сумісності, щоб стандартизувати та підтримувати клас та включати додаткові зворотні дзвінки для елементів та стилів:

https://github.com/Pixplicity/HtmlCompat

Хоча це схоже на клас Html рамки, деякі зміни підпису були потрібні, щоб дозволити більше зворотних викликів. Ось зразок зі сторінки GitHub:

Spanned fromHtml = HtmlCompat.fromHtml(context, source, 0);
// You may want to provide an ImageGetter, TagHandler and SpanCallback:
//Spanned fromHtml = HtmlCompat.fromHtml(context, source, 0,
//        imageGetter, tagHandler, spanCallback);
textView.setMovementMethod(LinkMovementMethod.getInstance());
textView.setText(fromHtml);

Коли я використовую вашу бібліотеку в додатку, який використовує, minSdkVersion 15і targetSdkVersion 23я отримую помилку збірки для значень-v24.xml : Очевидно,Error:(3) Error retrieving parent for item: No resource found that matches the given name 'android:TextAppearance.Material.Widget.Button.Borderless.Colored'. ваша бібліотека націлена на рівень API 25. Як я ще можу ним користуватися?
JJD

2

Ось моє рішення.

 if (Build.VERSION.SDK_INT >= 24) {
        holder.notificationTitle.setText(Html.fromHtml(notificationSucces.getMessage(), Html.FROM_HTML_MODE_LEGACY));
    } else {
        holder.notificationTitle.setText(Html.fromHtml(notificationSucces.getMessage()));

    }

1

просто зробіть функцію:

public Spanned fromHtml(String str){
  return Build.VERSION.SDK_INT >= 24 ? Html.fromHtml(str, Html.FROM_HTML_MODE_LEGACY) : Html.fromHtml(str);
}

-2

Спробуйте наступне, щоб підтримувати основні теги html, включаючи теги ul ol li. Створіть обробник тегів, як показано нижче

import org.xml.sax.XMLReader;

import android.app.Activity;
import android.os.Bundle;
import android.text.Editable;
import android.text.Html;
import android.text.Html.TagHandler;
import android.util.Log;

public class MyTagHandler implements TagHandler {
    boolean first= true;
    String parent=null;
    int index=1;
    @Override
    public void handleTag(boolean opening, String tag, Editable output,
                          XMLReader xmlReader) {

        if(tag.equals("ul")) parent="ul";
        else if(tag.equals("ol")) parent="ol";
        if(tag.equals("li")){
            if(parent.equals("ul")){
                if(first){
                    output.append("\n\t•");
                    first= false;
                }else{
                    first = true;
                }
            }
            else{
                if(first){
                    output.append("\n\t"+index+". ");
                    first= false;
                    index++;
                }else{
                    first = true;
                }
            }
        }
    }
}

Встановіть текст на Активність, як показано нижче

@SuppressWarnings("deprecation")
    public void init(){
        try {
            TextView help = (TextView) findViewById(R.id.help);
            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
                help.setText(Html.fromHtml(getString(R.string.help_html),Html.FROM_HTML_MODE_LEGACY, null, new MyTagHandler()));
            } else {
                help.setText(Html.fromHtml(getString(R.string.help_html), null, new MyTagHandler()));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

І HTML-текст на файлах рядкових ресурсів як

<! [CDATA [... необроблені HTML-дані ...]]>

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.