Html.fromHtml deprecated in Android N
Asked Answered
S

15

406

I am using Html.fromHtml to view html in a TextView.

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

But Html.fromHtml is now deprecated in Android N+

What/How do I find the new way of doing this?

Selenite answered 19/6, 2016 at 7:0 Comment(0)
A
815

update: as @Andy mentioned below Google has created HtmlCompat which can be used instead of the method below. Add this dependency implementation 'androidx.core:core:1.0.1 to the build.gradle file of your app. Make sure you use the latest version of androidx.core:core.

This allows you to use:

HtmlCompat.fromHtml(html, HtmlCompat.FROM_HTML_MODE_LEGACY);

You can read more about the different flags on the HtmlCompat-documentation

original answer: In Android N they introduced a new Html.fromHtml method. Html.fromHtml now requires an additional parameter, named flags. This flag gives you more control about how your HTML gets displayed.

On Android N and above you should use this new method. The older method is deprecated and may be removed in the future Android versions.

You can create your own Util-method which will use the old method on older versions and the newer method on Android N and above. If you don't add a version check your app will break on lower Android versions. You can use this method in your Util class.

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

You can convert the HTML.FROM_HTML_MODE_LEGACY into an additional parameter if you want. This gives you more control about it which flag to use.

You can read more about the different flags on the Html class documentation

Aisne answered 19/6, 2016 at 7:53 Comment(10)
Which flag does the zero represent?Pusey
Html.FROM_HTML_MODE_LEGACYPusey
ah, waiting for something like HtmlCompat to appearEarpiece
It's also useful to add a //noinspection deprecation comment just under the else to avoid lint warnings.Cabot
You can see what each of these flags do in this blog post: medium.com/@yair.kukielka/…Shermanshermie
And this seems to be deprecated as well and can be replaced by Html.FromHtml(htmlText, Android.Text.FromHtmlOptions.ModeLegacy);Putandtake
Why is it deprecated? What's better to use now? Why the need for the function you wrote, if the code behind the deprecated functions already use this flag?Backgammon
For me @SuppressWarnings("deprecation") did not work. I used @Suppress("deprecation") instead.Amby
@Earpiece Aaaand HtmlCompat including HtmlCompat.fromHtml is a thing now =)Fasano
Core library has String extension parseAsHtml() that will do exactly thisBread
M
103

I had a lot of these warnings and I always use FROM_HTML_MODE_LEGACY so I made a helper class called HtmlCompat containing the following:

   @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);
        }
    }
Mysticism answered 3/10, 2016 at 22:2 Comment(5)
Same effect like the accepted answer, but +1 because of SuppressWarnings annotationDissect
Can you give small explanation about this mode?Unessential
could you provide all HtmlCompact may be on git hub it looks coolYawp
@Yawp I would but it's really just a boring utility class with this single method in it....Mysticism
You can also just use HtmlCompat and avoid checking Android version.Pelayo
O
79

Compare of the flags of 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 FLAGS

Orpha answered 25/10, 2016 at 13:29 Comment(2)
Can you please share input HTML also? This would help in better understanding the conversion.Bruis
I see that the style attributes are not implemented, is there a way to implement them?Kellie
B
66

Or you can use androidx.core.text.HtmlCompat:

HtmlCompat.fromHtml("<b>HTML</b>", HtmlCompat.FROM_HTML_MODE_LEGACY)

HtmlCompat docs

Beebe answered 1/9, 2018 at 18:2 Comment(2)
you can use this even on Android 5?Tweeny
@Tweeny yes, it is part of support libraryBonus
L
30

If you are lucky enough to develop on Kotlin, just create an extension function:

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

And then it's so sweet to use it everywhere:

yourTextView.text = anyString.toSpanned()
Longlegged answered 30/8, 2017 at 14:48 Comment(1)
you may save typings by remove Spanned and returnEidolon
A
16

fromHtml

This method was deprecated in API level 24.

You should use FROM_HTML_MODE_LEGACY

Separate block-level elements with blank lines (two newline characters) in between. This is the legacy behavior prior to N.

Code

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

For Kotlin

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
    }

Call

 txt_OBJ.text  = setTextHTML("IIT Amiyo")
Alburga answered 19/11, 2016 at 6:19 Comment(2)
Can you give small explanation about this mode?Unessential
if you want SDK to handle version checks, use: HtmlCompat.fromHtml("textWithHtmlTags", HtmlCompat.FROM_HTML_MODE_LEGACY)Firebox
C
11

If you're using Kotlin, I achieved this by using a Kotlin extension:

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

Then call it like:

textView.htmlText(yourHtmlText)
Cuckooflower answered 28/11, 2018 at 12:14 Comment(2)
you don't need to add the else part, fromHtml method handles it by default for lower api devicesJuline
You can replace the if/else with: HtmlCompat.fromHtml(text, HtmlCompat.FROM_HTML_MODE_LEGACY)Abscission
V
9

From official doc :

fromHtml(String) method was deprecated in API level 24. use fromHtml(String, int) instead.

  1. TO_HTML_PARAGRAPH_LINES_CONSECUTIVE Option for toHtml(Spanned, int): Wrap consecutive lines of text delimited by '\n' inside <p> elements.

  2. TO_HTML_PARAGRAPH_LINES_INDIVIDUAL Option for toHtml(Spanned, int): Wrap each line of text delimited by '\n' inside a <p> or a <li> element.

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

Vacla answered 19/6, 2016 at 7:10 Comment(0)
E
6

For Kotlin users, we can use String.parseAsHtml() extension function which uses HtmlCompat which in turn has compatibility checks.

This is available from the android core kotlin extensions available from androidx.core:core-ktx

Ethereal answered 16/9, 2022 at 4:55 Comment(0)
I
5

Just to extend the answer from @Rockney and @k2col the improved code can look like:

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

Where the CompatUtils.isApiNonLowerThan:

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

The difference is that there are no extra local variable and the deprecation is only in else branch. So this will not suppress all method but single branch.

It can help when the Google will decide in some future versions of Android to deprecate even the fromHtml(String source, int flags) method.

Impoverish answered 16/2, 2017 at 10:42 Comment(0)
K
4

You can use

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

to suppress inspection just for single statement but not the whole method.

Katabatic answered 30/12, 2016 at 8:38 Comment(0)
L
3

Here is my solution.

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

    }
Lions answered 17/1, 2019 at 7:57 Comment(0)
A
3

just make a function :

public Spanned fromHtml(String str){
  return Build.VERSION.SDK_INT >= 24 ? Html.fromHtml(str, Html.FROM_HTML_MODE_LEGACY) : Html.fromHtml(str);
}
Acquiescence answered 20/11, 2019 at 7:25 Comment(1)
why not FROM_HTML_MODE_COMPACT?Mend
C
2

The framework class has been modified to require a flag to inform fromHtml() how to process line breaks. This was added in Nougat, and only touches on the challenge of incompatibilities of this class across versions of Android.

I've published a compatibility library to standardize and backport the class and include more callbacks for elements and styling:

https://github.com/Pixplicity/HtmlCompat

While it is similar to the framework's Html class, some signature changes were required to allow more callbacks. Here's the sample from the GitHub page:

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);
Carbonization answered 14/3, 2017 at 15:56 Comment(1)
When I use your library on an app which uses minSdkVersion 15 and targetSdkVersion 23 I get a build error for 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'. Your library targets API level 25, obviously. How can still I use it?Wellread
U
-1

Try the following to support basic html tags including ul ol li tags. Create a Tag handler as shown below

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

Set the text on Activity as shown below

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

    }

And html text on resource string files as

<![CDATA[ ...raw html data ...]] >

Ulna answered 14/7, 2017 at 17:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.