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теперь требуется дополнительный параметр с именем flags. Этот флаг дает вам больше контроля над тем, как отображается ваш 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

Сравните флаги fromHtml ().

<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? Это поможет лучше понять конверсию.
— Калпеш Патель

Я вижу, что атрибуты стиля не реализованы, есть ли способ их реализовать?
— Кристина


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
— Минами

14

fromHtml

Этот метод устарел на уровне API 24 .

Вы должны использовать 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)
— Ваджид Али

8

Из официального документа:

fromHtml(String)Метод не рекомендуется использовать на уровне API 24. используйте 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получаю ошибку сборки для values-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 [... raw html data ...]]>

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.