Html.fromHtml przestarzałe w Androidzie N.


300

Używam Html.fromHtmldo przeglądania HTML w TextView.

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

Ale Html.fromHtmlteraz jest przestarzałe w Androidzie N +

Co / Jak mogę znaleźć nowy sposób na zrobienie tego?

Odpowiedzi:


616

aktualizacja : jak wspomniano poniżej @Andy , stworzył Google, HtmlCompatktórego można użyć zamiast poniższej metody. Dodaj tę zależność implementation 'androidx.core:core:1.0.1 do pliku build.gradle swojej aplikacji. Upewnij się, że używasz najnowszej wersjiandroidx.core:core .

Pozwala to na użycie:

HtmlCompat.fromHtml(html, HtmlCompat.FROM_HTML_MODE_LEGACY);

Możesz przeczytać więcej o różnych flagach w dokumentacji HtmlCompat

oryginalna odpowiedź: w Androidzie N wprowadzono nową Html.fromHtmlmetodę. Html.fromHtmlwymaga teraz dodatkowego parametru o nazwie flagi. Ta flaga zapewnia większą kontrolę nad sposobem wyświetlania kodu HTML.

W systemie Android N i nowszym powinieneś użyć tej nowej metody. Starsza metoda jest przestarzała i może zostać usunięta w przyszłych wersjach Androida.

Możesz utworzyć własną metodę Util, która będzie używać starej metody w starszych wersjach i nowszej metody w systemie Android N i nowszych. Jeśli nie dodasz wersji, sprawdź, czy aplikacja działa na niższych wersjach Androida. Możesz użyć tej metody w swojej klasie 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);
    }
}

Jeśli chcesz, możesz przekonwertować parametr HTML.FROM_HTML_MODE_LEGACYna dodatkowy. Daje to większą kontrolę nad tym, której flagi użyć.

Możesz przeczytać więcej o różnych flagach w dokumentacji klasy HTML


2
Którą flagę reprezentuje zero?
zakaz geoinżynierii

4
Html.FROM_HTML_MODE_LEGACY
zakaz geoinżynierii

14
ah, czekam na pojawienie się czegoś takiego jak HtmlCompat
vanomart

12
Przydatne jest również dodanie //noinspection deprecationkomentarza tuż pod elseostrzeżeniem, aby uniknąć ostrzeżeń.
Ted Hopp,

1
Możesz zobaczyć, co robią te flagi w tym poście na blogu: medium.com/@yair.kukielka/…
Yair Kukielka

95

Miałem wiele takich ostrzeżeń i zawsze używam FROM_HTML_MODE_LEGACY, więc stworzyłem klasę pomocniczą o nazwie HtmlCompat zawierającą:

   @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
Ten sam efekt, co zaakceptowana odpowiedź, ale +1 ze względu na adnotację SuppressWarnings
Stoycho Andreev

Czy możesz podać małe wyjaśnienie dotyczące tego trybu?
Ranjith Kumar

można zapewnić wszystkim HTMLCompact może być na git huba wygląda cool
SHAREEF

@shareef Chciałbym, ale to naprawdę nudna klasa narzędziowa z tą pojedynczą metodą…
k2col

61

Porównaj flagi 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

FLAGI FROM_HTML


Czy możesz również udostępnić wejściowy kod HTML? Pomoże to w lepszym zrozumieniu konwersji.
Kalpesh Patel,

Widzę, że atrybuty stylu nie są zaimplementowane, czy istnieje sposób na ich wdrożenie?
Christine


25

Jeśli masz szczęście rozwijać się w Kotlin, po prostu utwórz funkcję rozszerzenia:

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)
    }
}

A potem tak słodko jest używać go wszędzie:

yourTextView.text = anyString.toSpanned()

5
możesz zapisywać pisma, usuwając Spannedireturn
Minami

14

fromHtml

Ta metoda została uznana za przestarzałą na poziomie interfejsu API 24 .

Powinieneś użyć FROM_HTML_MODE_LEGACY

Oddziel elementy na poziomie bloku pustymi liniami (dwa znaki nowej linii) pomiędzy nimi. Jest to starsze zachowanie przed N.

Kod

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"));
        }

Dla Kotlina

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
    }

Połączenie

 txt_OBJ.text  = setTextHTML("IIT Amiyo")

Czy możesz podać małe wyjaśnienie dotyczące tego trybu?
Ranjith Kumar

jeśli chcesz, aby SDK obsługiwał sprawdzanie wersji, użyj: HtmlCompat.fromHtml("textWithHtmlTags", HtmlCompat.FROM_HTML_MODE_LEGACY)
Wajid Ali,

8

Z oficjalnego dokumentu:

fromHtml(String)metoda została wycofana z interfejsu API na poziomie 24. użyj fromHtml(String, int) zamiast tego.

  1. TO_HTML_PARAGRAPH_LINES_CONSECUTIVEOpcja toHtml(Spanned, int): Zawijaj kolejne wiersze tekstu ograniczonego przez elementy '\n'wewnętrzne <p>.

  2. TO_HTML_PARAGRAPH_LINES_INDIVIDUALOpcja toHtml(Spanned, int): Zawijaj każdą linię tekstu ograniczonego '\n'wewnątrz elementu <p>lub <li> elementu.

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


8

Jeśli używasz Kotlin , osiągnąłem to, używając rozszerzenia 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))
    }
}

Następnie nazwij to tak:

textView.htmlText(yourHtmlText)

5

Aby rozszerzyć odpowiedź z @Rockney i @ k2col, ulepszony kod może wyglądać następująco:

@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);
    }
}

Gdzie CompatUtils.isApiNonLowerThan:

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

Różnica polega na tym, że nie ma dodatkowej zmiennej lokalnej, a wycofanie następuje tylko w elseoddziale. Dlatego nie spowoduje to pominięcia wszystkich metod oprócz pojedynczej gałęzi.

Może to pomóc, gdy Google zdecyduje się w niektórych przyszłych wersjach Androida na wycofanie nawet tej fromHtml(String source, int flags)metody.


4

Możesz użyć

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

aby ukryć inspekcję tylko dla pojedynczej instrukcji, ale nie dla całej metody.


2

Klasa frameworka została zmodyfikowana, aby wymagać flagi do informowania fromHtml() sposobie przetwarzania linii. Zostało to dodane w Nougat i dotyczy tylko problemu niezgodności tej klasy we wszystkich wersjach Androida.

Opublikowałem bibliotekę kompatybilności, aby ustandaryzować i backportować klasę oraz zawierać więcej wywołań zwrotnych elementów i stylów:

https://github.com/Pixplicity/HtmlCompat

Chociaż jest podobny do klasy Html frameworka, konieczne były pewne zmiany sygnatur, aby umożliwić więcej wywołań zwrotnych. Oto przykład ze strony 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);

Gdy korzystam z biblioteki w aplikacji, która używa minSdkVersion 15i targetSdkVersion 23pojawia się błąd kompilacji dla wartości v24.xml : Error:(3) Error retrieving parent for item: No resource found that matches the given name 'android:TextAppearance.Material.Widget.Button.Borderless.Colored'.Twoja biblioteka jest oczywiście docelowa na poziomie API 25. Jak mogę go nadal używać?
JJD

2

Oto moje rozwiązanie.

 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

po prostu wykonaj funkcję:

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

-2

Spróbuj wykonać poniższe czynności, aby obsługiwać podstawowe tagi HTML, w tym tagi ul ol li. Utwórz moduł obsługi znaczników, jak pokazano poniżej

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;
                }
            }
        }
    }
}

Ustaw tekst w polu Aktywność, jak pokazano poniżej

@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();
        }

    }

I tekst HTML w plikach ciągów zasobów jako

<! [CDATA [... surowe dane HTML ...]]>

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.