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.