Android N 中不推荐使用 Html.fromHtml

Posted

技术标签:

【中文标题】Android N 中不推荐使用 Html.fromHtml【英文标题】:Html.fromHtml deprecated in Android N 【发布时间】:2016-10-20 15:49:37 【问题描述】:

我正在使用html.fromHtmlTextView 中查看html。

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

Html.fromHtml 现在在 android N+ 中已弃用

什么/如何找到执行此操作的新方法?

【问题讨论】:

【参考方案1】:

更新: 正如@Andy mentioned below 谷歌已经创建了HtmlCompat 可以用来代替下面的方法。添加这个依赖implementation 'androidx.core:core:1.0.1 到您的应用程序的 build.gradle 文件。确保您使用最新版本的androidx.core:core

这允许您使用:

HtmlCompat.fromHtml(html, HtmlCompat.FROM_HTML_MODE_LEGACY);

您可以在HtmlCompat-documentation 上阅读有关不同标志的更多信息

原答案: 在 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 class documentation

【讨论】:

零代表哪个标志? Html.FROM_HTML_MODE_LEGACY 啊,等待HtmlCompat之类的出现 else 下方添加//noinspection deprecation 评论也很有用,以避免出现lint 警告。 您可以在这篇博文中看到每个标志的作用:medium.com/@yair.kukielka/…【参考方案2】:

我收到了很多这样的警告,而且我总是使用 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);
        
    

【讨论】:

与接受的答案效果相同,但由于 SuppressWarnings 注释而 +1 你能简单解释一下这个模式吗? 你能提供所有 HtmlCompact 可能在 git hub 上看起来很酷 @shareef 我会,但它实际上只是一个无聊的实用程序类,其中只有一个方法......【参考方案3】:

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

【讨论】:

你能分享输入HTML吗?这将有助于更好地理解转换。 我看到style属性没有实现,有没有办法实现?【参考方案4】:

或者你可以使用androidx.core.text.HtmlCompat:

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

HtmlCompat docs

【讨论】:

你甚至可以在 Android 5 上使用它? @CDrosos 是的,它是支持库的一部分【参考方案5】:

如果你有幸在 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()

【讨论】:

你可以通过删除Spannedreturn来保存打字【参考方案6】:

fromHtml

此方法在 API 级别 24已弃用

你应该使用 FROM_HTML_MODE_LEGACY

用空行分隔块级元素(两个换行符 字符)之间。这是 N 之前的遗留行为。

代码

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

对于 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
    

打电话

 txt_OBJ.text  = setTextHTML("IIT Amiyo")

【讨论】:

你能简单解释一下这个模式吗? 如果您希望 SDK 处理版本检查,请使用:HtmlCompat.fromHtml("textWithHtmlTags", HtmlCompat.FROM_HTML_MODE_LEGACY)【参考方案7】:

如果您使用的是 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)

【讨论】:

else部分不需要添加,fromHtml方法默认为低级api设备处理 您可以将 if/else 替换为:HtmlCompat.fromHtml(text, HtmlCompat.FROM_HTML_MODE_LEGACY)【参考方案8】:

来自官方文档:

fromHtml(String) 方法在 API 级别 24 中已弃用。使用 fromHtml(String, int) 而是。

    TO_HTML_PARAGRAPH_LINES_CONSECUTIVE toHtml(Spanned, int) 的选项:将由'\n' 分隔的连续文本行包裹在&lt;p&gt; 内 元素。

    TO_HTML_PARAGRAPH_LINES_INDIVIDUAL toHtml(Spanned, int) 的选项:将由 '\n' 分隔的每一行文本包裹在 &lt;p&gt;&lt;li&gt; 内 元素。

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

【讨论】:

【参考方案9】:

只是为了扩展@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) 方法时,它会有所帮助。

【讨论】:

【参考方案10】:

你可以使用

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

仅针对单个语句而不是整个方法禁止检查。

【讨论】:

【参考方案11】:

这是我的解决方案。

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

    

【讨论】:

【参考方案12】:

只做一个函数:

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

【讨论】:

【参考方案13】:

框架类已被修改为需要一个标志来通知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 15targetSdkVersion 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。我还能怎么用?【参考方案14】:

尝试以下方法来支持基本的 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;
                
            
        
    

在Activity上设置文字如下图

@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文本为

【讨论】:

以上是关于Android N 中不推荐使用 Html.fromHtml的主要内容,如果未能解决你的问题,请参考以下文章

Android Q 中不推荐使用 PreferenceManager getDefaultSharedPreferences

Android P 中不推荐使用的片段

Xamarin.Android 中不推荐使用某些 NotificationBuilder 方法,我应该使用哪些方法?

在 API 29 java android 中不推荐使用 getBitmap

新行 (\n) 在 android 中不支持?

Java 9 中不推荐使用 Observer。我们应该使用啥来代替它?