【翻译】TextClassification介绍(三)

TextClassification介绍(一)

一、说明

这是一个关于介绍 TextClassification API 的系列文章,总共分三篇,本文是最后一篇。上一篇在此:【翻译】TextClassification介绍(二)

原文作者:Mark Allison
阅读时间: 5 分钟
原文链接:https://blog.stylingandroid.com/textclassification-part-3/

二、正文

在 API 26 (奥利奥)中安卓引入了一个新的文字功能系统: TextClassification 。这个系统将会在 API 28 ( π )中进一步改进完善。在本次简短的系列中,我们主要会探讨它是一个什么样的系统,如何使用它,以及如何为它添加一些自定义行为。

上一篇文章中我们开始研究自定义 TextClassifier 的实现,并研究了如何实现我们自己的“文本选择建议”。在本系列的最后一篇文章中,我们将会实现相应的 classifyText() 方法,并应用到我们自定义的 TextClassifier 文本分类器的实现中。

这里的 classifyText() 方法的实现实际上非常简单直接。我们检查选择的文本是否与请求中所选择的相匹配,如果相匹配则返回一个 TextClassification 的实例,这个我们稍后再详细了解。如果选择的文本与我们的正则表达式不匹配,那么我们会将结果进行回滚(也就是 TextClassifier 的默认实现):

override fun classifyText(request: TextClassification.Request): TextClassification {
    //line 36
    return if (regex.matches(request.subSequence())) {
        factory.buildTextClassification(
                //line 38
                request.subSequence().toString(),
                listOf(TextClassifier.TYPE_URL to 1.0f),
                listOf(factory.buildRemoteAction(
                        context,
                        R.drawable.ic_stylingandroid,
                        stylingAndroid,
                        contentDescription,
                        stylingAndroidUri
                ))
        )
    } else {
        fallback.classifyText(request)
    }
}

private fun TextClassification.Request.subSequence() =
        text.subSequence(startIndex, endIndex)

这里有一个 TextClassification.Request 的扩展函数,它返回文本中已选择的子文本 subSequence ,我们正是使用它来匹配正则表达式(第 36 行)。然后,我们构建一个 TextClassification 对象,它需要一些参数,包括匹配到的字符串(第 38 行),分类类型与其各自的可信度分数列表(第 39 行),以及一列 RemoteAction 实例对象,每个 RemoteAction 对象对应一个分类类型条目(第 39-45 行)。

这里的 buildRemoteAction() 方法返回每个 RemoteAction 实例:

override fun buildRemoteAction(
        context: Context,
        drawableId: Int,
        title: String,
        contentDescription: String,
        uri: String
): RemoteAction {
    return RemoteAction(
            Icon.createWithResource(context, drawableId),
            title,
            contentDescription,
            PendingIntent.getActivity(
                    context,
                    0,
                    Intent(Intent.ACTION_VIEW, Uri.parse(uri)),
                    0
            )
    )
}

这里 RemoteAction 的构造函数需要四个参数:一个 Icon 对象,它将显示为操作按钮中的一部分;一个要显示的文字;一个表示可访问的内容描述;最后还需一个 PendingIntent 对象,它表示用户在点击操作按钮时将会执行的操作。在我们的示例代码中,我们使用了一个 Styling Android 标志图形作为图标,使用了 “Styling Android” 作为标题,以及简单的一些内容描述,再加一个能登录浏览器打开 URL 链接 "https://blog.stylingandroid.com" 的 PendingIntent 对象。

buildTextClassification() 函数使用 TextClassification.Builder 实例来创建 TextClassification 对象:

override fun buildTextClassification(
        text: String,
        entityTypes: List<Pair<String, Float>>,
        actions: List<RemoteAction>
): TextClassification {
    return TextClassification.Builder()
            .run {
                setText(text)
                entityTypes.forEach { setEntityType(it.first, it.second) }
                actions.forEach { addAction(it) }
                build()
            }
}

这里需要传递三个参数:匹配到的文本,一系列以类型及其对应的可信度范围作为 Pair 的列表,以及与每个类型/置信度组合所对应的 RemoteActions 列表。在这里示例中,这些参数分别是被选定的子字符串,包含一对 TextClassifier.TYPE_URL 及其可信度为 1.0f 组成的 Pair 的列表,以及一列包含我们刚刚说过的 RemoteAction 类单例的列表。

TextClassifier 已经完成了,剩下的事情就是将它连接到我们的 TextView 文本控件中:

class MainActivity : AppCompatActivity() {

    private val emailText = "dummy@email.com"
    private val urlText = "https://blog.stylingandroid.com"
    private val hybridText = "Email: $emailText"

    private lateinit var textClassificationManager: TextClassificationManager

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        textClassificationManager = getSystemService(Context.TEXT_CLASSIFICATION_SERVICE) as TextClassificationManager

        classifier()

        text1.textClassifier = StylingAndroidTextClassifier(this, textClassificationManager.textClassifier)
    }

    private fun classifier() = async(CommonPool) {
        val textClassifier = textClassificationManager.textClassifier
        val emailClassification = textClassifier.classifyText(emailText, 0, emailText.length, LocaleList.getDefault())
        println(emailClassification)
        val urlClassification = textClassifier.classifyText(urlText, 0, urlText.length, LocaleList.getDefault())
        println(urlClassification)
        val suggestions = textClassifier.suggestSelection(hybridText, 10, 11, LocaleList.getDefault())
        println(suggestions)
    }
}

一行代码就可以实现我们要做的一切。我们创建了一个自定义 TextClassifier 对象,并将其作为参数传递给默认的 TextClassifier 对象的构造函数,并将 TextViewtextClassifier 属性设置为我们的自定义实例。

我们目前得到的文本处理行为是:如果用户长时间按下的文字是无法识别的类型,那就只有简单的复制,粘贴和选择所有的选项功能;如果他们长时间按下系统默认的文本分类器所支持的任何类型,那么他们会得到我们在第一篇文章中所看到的所有相同的行为和动作;但是,如果他们长按 "Styling Android" 字符串(或者与正则表达式相匹配的类似字符串),那么将获得我们所自定义的“流行广告”操作,这个操作将启动浏览器并登录加载链接: https://blog.stylingandroid.com

custom.gif

TextClassifier 文本分类器中还有一个机制,用来识别具体的文本类型,然后使用文本生成链接,不过在本系列文章中我们不会去研究它,因为我们这里所看到的技术已经涵盖了 TextViewWebView 内置的一些主要功能。如果看到这里有人对此感兴趣,那么请告诉我,我将会单独写一篇文章作详细说明。

三、总结

这篇文章的源代码可以在这里找到: https://github.com/StylingAndroid/TextClassification/tree/Part3

© 2018 , Mark Allison 。保留所有版权。

我的博客地址: http://liuqingwen.me ,欢迎关注我的微信公众号:

IT自学不成才

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,869评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,716评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,223评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,047评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,089评论 6 395
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,839评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,516评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,410评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,920评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,052评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,179评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,868评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,522评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,070评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,186评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,487评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,162评论 2 356

推荐阅读更多精彩内容