解读Bento Android框架的开源细节

xiaohui 安全工具 2019年5月22日发布
Favorite收藏

导语:在这篇文章中,研发人员将详细解释Bento的工作原理,以及Yelp开源Bento Android框架,用于模块化UI开发的内幕。

Bento是一个用于构建模块化Android用户界面的开源框架,由Yelp研发。在过去的一年中,研发人员已经看到了在最关键的模块化UI开发上使用Bento可以提高开发人员的工作效率和产品设计的灵活性。在这篇文章中,研发人员将详细解释Bento的工作原理,以及Yelp开源Bento Android框架,用于模块化UI开发的内幕。

什么是Bento?

Bento桌面的信息以卡片的形式呈现给用户,从未接来电到截图提醒,从音乐播放到日历行程。获得授权后,Bento会嵌入联系人、日历、Email、浏览搜索记录和音乐播放记录等,记住用户的一些基本信息和个人喜好,在下一次用户进行某些动作的时候,直接向云端服务器发送数据然后予以相应反馈,用户甚至不需要专门下载相应的 App 。Bento的另一大亮点是,这款第三方 Launcher 还带有推荐功能。从用户浏览喜好或潜在需求出发,提供推荐类服务的应用有很多,比如Google Now(它是谷歌在I/O开发者大会上随安卓4.1系统同时推出的一款应用,它会全面了解你的各种习惯和正在进行的动作,并利用它所了解的来为你提供相关信息)。但与它们不同的是,Bento所有服务都是在定制化的手机桌面完成的,这种桌面式的功能触发器直接决定了用户使用手机的方式。

所以,Yelp的开发人员用Bento形象地命令了这个框架。 Bento的字面意思是便当的意思,顾名思义,Bento框架就是要随时方便用户。Bento盒顾名思义就是一个装有各种分隔装置的容器,用于将不同的“美味”彼此分开。

许多Android应用程序都有一个基于列表的用户界面,使用RecyclerView来显示程序的视图。RecyclerView是support:recyclerview-v7中提供的控件,最低兼容到android 3.0版本。RecyclerView是一种类似于ListView的一个滑动列表,但是RecyclerView和ListView相比,RecyclerView比ListView更好,RecyclerView支持横向滑动,RecyclerView没有点击事件,需要自己加入,还可以做出各种炫酷的效果动画,更符合高内聚低耦合。

在底层级别上,RecyclerView通过引用有序的数据列表并在屏幕上为该列表中的每个数据项创建视图来工作。如果你的列表由同质数据类组成,那么这种方法非常有效。但是当你需要在列表中管理无限数量的数据和视图类时,这种方法的弱点就暴露出来了。如果你需要在除RecyclerView之外的用户界面中使用相同的视图类(例如ViewPager或ListView),这种方法也会不好用。

Bento被设计出来的目的,就是旨在通过提供一个框架来管理处理不同视图类的复杂性以及列表中每个视图的动态位置来解决以上出现的问题。 Bento还可用于管理其他父视图类(例如ViewPagers和ListViews)中的视图,但同时Bento也保留了RecyclerView的优势(如ViewHolder和视图回收)。

Bento如何运行?

Bento将不同的视图类和与显示这些视图类并与之交互的逻辑分组到“组件”中,组件可以是从简单文本视图到由其他组件组成复杂组件。

组件的核心是提供数据项的独立元素,关联的ComponentViewHolder类将使视图不断inflate化并将提供的数据项绑定到复杂的视图中。ViewHolder通常还会将组件或某些presenter绑定到视图,以处理任何用户交互。

为了演示组件的工作原理,我会在下面列出+要显示在屏幕上的组件的数据流图表。

1.jpg

1.首先,底层页面视图需要显示内容,因此它要求ComponentController呈现一个视图。

2.ComponentController需要将更新的视图返回到底层页面视图,因此,基于控制器维护的内部组件列表,它通过在页面视图需要的位置对列表中的组件调用getHolderType来创建一个新的ComponentViewHolder。此方法会返回ComponentViewHolder类,然后通过反射实例化该类。

3.由于这是组件第一次创建视图,因此需要对布局进行inflate化处理。 为此,ComponentController需要在新创建的ComponentViewHolder上调用inflate方法来创建视图。

4.接下来,研发人员需要使用数据填充视图,并确保它将对用户输入作出响应。在创建的ComponentViewHolder实例上调用bind方法,该方法提供了一个数据项和一个presenter。它们是通过调用相应组件的getPresenter和getItem方法的ComponentController生成的。presenter是执行某些业务逻辑或处理用户交互的任何对象。在许多情况下,它是Component类本身。数据项通常是一个数据类,其中包含要显示给用户的视图属性和字符串。

5.视图将使用数据项进行更新,并且事件侦听器将绑定到presenter,然后将视图传递回要呈现的底层页面视图。

组件在其父视图中的顺序由ComponentController决定,而这正是Bento盒中的神奇之处,它允许研发人员动态地向订单添加、删除和插入组件,这就像在一个简单的列表数据结构中操作一样。它还提供了一个抽象化操作,研发人员可以使用它来将此功能应用于不同的视图类,例如RecyclerView,ListView,ViewPager和其他许多其他类。例如,recoverclerviewcomponentcontroller处理与recoverclerview类和适配器通信的复杂编排,以确定跨度和位置,使得在列表中管理不同的组件集变得非常简单。研发人员还可以使用ComponentGroup创建不同组件的分组,以将组件的逻辑分组保存在列表中。

Bento框架可以轻松地将复杂的界面分解为一组易于理解、模块化、动态和可测试的组件。

具体示例

让研发人员看一个如何构建一个只呈现一些文本的底层组件的示例,下面是一个非常简单的Component类的示例:

class ExampleComponent(private val text: String): Component() {
    override fun getCount() = 1
    override fun getPresenter(position: Int) = this
    override fun getItem(position: Int) = text
    override fun getHolderType(position: Int) = ExampleViewHolder::class.java
}

在上图中,你可以看到其中已经覆盖了抽象组件类的一些方法。让研发人员来解读一下其中的每个方法:

1.getCount:组件可以在内部由一系列项组成,在以上的简单示例中,其中就只有一个项目。如果需要,每个位置的组件中的每个项目都可以拥有自己的presenter、数据项和ViewHolder类,但通常最好将其分解为不同的组件,除非所有项目都具有相同的ViewHolder和presenter。

2.getPresenter:presenter是组件的大脑,它知道如何响应用户交互并执行其他复杂的活动。在某种程度上,每个Bento组件都是它自己的MVP生态系统,其中组件是Presenter,ComponentViewHolder是视图,数据项是模型。

3.getItem:该项是与指定位置的组件关联的数据,在本文的示例中,数据就是研发人员想要显示的文本。

4.getHolderType:持有者类是由Bento框架通过反射实例化的类,它负责扩展组件的布局并将数据项绑定到视图。来看看本示例中的ExampleViewHolder类:

class ExampleViewHolder: ComponentViewHolder<ExampleComponent, String>() {
    private lateinit var textView: TextView
    override fun inflate(parent: ViewGroup) =
            parent.inflate<TextView>(R.layout.example_component_layout)
            .also { textView = it }
    override fun bind(presenter: ExampleComponent, element: String) {
        textView.text = element
    }
}

就像研发人员在使用RecyclerViews时看到的ViewHolder模式一样,Bento的ViewHolder可以按着inflate和bind方法进行不同的划分。

inflate :它的作用就是扩展已有的布局文件,它的根目录只包含一个简单的TextView元素。然后研发人员返回经过扩展的视图,并在textView中存储对它的引用,以便稍后在绑定数据时使用它。

Bind:只要组件中的项目准备好显示在屏幕上,就会调用此方法。对于组件类中的getCount定义的每个项,它都会调用一次。 bind方法提供对presenter的引用,以及此ViewHolder所代表的组件中位置的相应数据项。换句话说,presenter参数是从某个位置i调用getPresenter(i)获得的,元素参数也是从调用getItem(i)得到的相同位置i获得的。

注意:绑定方法通常是在视图在列表中循环使用时调用,因此性能应该是此方法的高优先级。

现在研发人员就有一个组件和一个ComponentViewHolder,它将获取一些字符串并将其绑定到TextView以显示用户。那么研发人员如何实际使用该组件呢?只需创建一个ComponentController来组织所有组件即可。对于此示例,研发人员将使用简单的RecyclerViewComponentController。以下是一个示例活动:

class ExampleActivity: AppCompatActivity() {
    private val componentController by lazy {
        RecyclerViewComponentController(recyclerView)
    }
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_recycler_view)
        componentController.addComponent(ExampleComponent("Hello World!"))
    }
}

在示例中,研发人员创建了一个常规的活动,其内容视图布局只是一个reclerView,其id为recyclerView。在第一次引用ComponentController时,研发人员只是按着一般的情况初始化它,并通过传递recoverclerview的实例来创建它。之后,研发人员调用addComponent并引入一个ExampleComponent的新实例。通过以上的一番操作,一个Hello World文本字符串便会显示出来。以下是应用程序最后呈现出的样子:

5.png

这证明了, Bento也有帮助类来避免样板代码的功能。本示例组件类实际上非常简单,因此研发人员可以将它编写为SimpleComponent:

class SimpleExampleComponent(
    private val text: String
): SimpleComponent<Nothing>(ExampleViewHolder::class.java) {
    override fun getItem(position: Int) = text
}

它仍然使用研发人员之前的ExampleViewHolder,但现在研发人员不需要担心计数或presenter,并且在超级构造函数中指定了ViewHolder类。 Bento还包含许多组件的变体,包括用于重复视图的ListComponent,用于延迟加载的PaginatingListComponent,甚至用于可以水平滚动的组件集合的CarouselComponent。

具体表现特征

模块化

从上面的示例可以看出,组件是非常模块化的。该组件作为一个内聚度很高的整体存在,不依赖于它所插入的环境。这样做有很多好处,下面我会具体介绍。

可测试性

由于组件不依赖于Android框架,因此很容易对其逻辑进行单元测试。使用ComponentViewHolderTestCase测试ComponentViewHolder的逻辑也很容易,ComponentViewHolderTestCase会扩展视图并将其注入到绑定数据的测试活动中。然后,Espresso可以检查所有内容是否正确显示,并在用户交互期间在presenter上调用正确的方法。从集成测试的角度来看,bento-testing模块提供了一些BentoInteraction来测试用户所看到的整个组件屏幕。

可重复使用性

为一个环境创建的组件可以在使用任何类的ComponentController的许多不同屏幕上重用,这意味着可以轻松地将相同的组件放入RecyclerView,ListView或ViewPager中。

集成性

Bento会被逐步嵌入到现有的应用程序中,因此以后你无需从头开始重写应用程序或重新考虑整个应用程序架构。早在一年前,研发人员就已经将它集成到Yelp消费者和企业所有者应用程序中了。例如,在消费者应用程序的附近屏幕上,标题下方的所有内容(下面以红色标出)都是Bento组件。

7.png

研发人员还集成了一些工具,使现有应用程序的转换更加轻松。例如,对于那些仍然使用ListViews的用户,可以使用ListAdapterComponent将现有列表包装到其自己的组件中,并开始将列表中的项目转换为各自独立的组件。

可扩展性

从技术和组织的角度来看,Bento都是可扩展的。使用Bento的项目可以拥有的组件数量没有限制。由于可以很容易地将组件彼此隔离,因此也可以轻松将它们跨组件隔离,从而缩短构建所需的时间。由于研发人员可以使用RecyclerViews作为Bento的支持视图,因此在使用大量异构组件时也非常高效。更多模块化用户界面组件也意味着研发人员可以将组件的所有权分配给特定团队进行维护。由于许多不同团队可以在同一屏幕上同时拥有组件,这意味着软件维护的任务可以更均匀地分布,并且更容易对出现的漏洞进行分类。

低耗能性

Bento不使用类注释,因为不需要进行注释处理,这意味着编译时的耗能非常低。此外,由于Bento只包含少数几个类,因此它的存储占用空间非常小,aar库文件只有105.6 KB。

总结

Yelp开源Bento Android框架,用于模块化UI开发后,可以帮助Android研发人员高效地进行开发,并使开发后的产品高效可靠地执行新功能。但Bento仍然需要持续改进,主要集中在性能方面。研发人员目前没有异步布局扩展,其中每个布局都是从主UI线程扩张出来的。在通知ComponentGroup中的更改时,研发人员也没有进行优化。Bento Android的一部分仍然用Java编写,而其他部分用Kotlin编写。

本文翻译自:https://engineeringblog.yelp.com/2019/05/introducing-bento.html如若转载,请注明原文地址: https://www.4hou.com/tools/18051.html
点赞 5
  • 分享至
取消

感谢您的支持,我会继续努力的!

扫码支持

打开微信扫一扫后点击右上角即可分享哟

发表评论