15

我实际上正在开发一个 Android 应用程序,我应该在其上显示基于 JSON 文档中包含的元数据的动态表单。基本上它的工作方式(没有细节)是一个 JSON 文档代表一个表单的结构:

{
    "fields": [
        {
            "name": "fieldA",
            "type": "STRING",
            "minCharacters": 10,
            "maxCharacters": 100
        },
        {
            "name": "fieldB",
            "type": "INTEGER",
            "min": 10,
            "max": 100
        },
        {
            "name": "fieldC",
            "type": "BOOLEAN_CHECKBOX",
            "defaultValue": true
        }
        ...
    ],
    "name": "Form A"
}

当应用程序收到其中一个 JSON 文档时,我实际上正在做的是它遍历每个字段并将其解析为适当的视图(EditText、Checkbox、自定义视图等),向视图添加一个标签(将能够轻松检索它)并将视图添加到LinearLayout. 这是它实际工作方式的伪代码:

//Add form title
linearLayout.addView(new TextView(form.name));
//Add form fields
for(Field field: form.fields) {
    View view;
    switch(field.type){
        case STRING: view = new EditText();
        ...
    }
    view.setTag(field.id);
    linearLayout.addView(view);
}

这样做的问题是,对于大型表单(如 >20 个字段),它需要增加大量视图,并且 UI 线程会遭受很多损失。要考虑的另一点是单个屏幕可能有多种形式(一个接一个垂直排序)。

为了避免 UI 线程过载,我想到了 2 个可能的解决方案:

  1. 使用 RecyclerView
  2. 使用Facebook 的 Litho

但是在考虑这两种解决方案时,我想到了多个问题:

  1. 使用 Litho 是一个很好的用例吗?还是使用 RecyclerView 就足够了?
  2. 我的观点状态如何?如果我使用回收模式,我是否能够保持每个字段的状态(甚至是那些不在屏幕上的字段),从而能够在不丢失数据的情况下保存表单?
  3. 如果我使用回收模式显示一个表单,我将如何处理多个表单?我们可以嵌套 RecyclerView 吗?表单需要像在垂直 RV 内一样依次显示,但如果表单本身是 RV,我应该如何处理?

这更像是一个“良好实践”的问题,并给出了实现我的目标的正确方法或正确方法之一,而不是需要代码示例的特定答案等。

在此先感谢您的时间。

4

4 回答 4

12

在为移动应用程序架构时,我想解决以下问题:

使用 Litho 是一个很好的用例吗?还是使用 RecyclerView 就足够了?

  1. 视图是否被正确回收: 这对我们意味着什么,考虑每个屏幕创建 40-50 个视图,当用户移出视图时,系统不应该将所有视图标记为 GC,而应该在某种归档列表中当我们再次需要它时,我们应该能够从中获取。

    为什么需要这样做:GC 是最昂贵的操作,会导致应用程序渲染抖动,我们尝试通过不清除视图来最小化此时调用的 GC

    为此,我想使用光刻,理由在这里,因为您的要求似乎有更多的可变viewtypes参考计数

    结论:Litho +1,RecyclerView +0

我的观点状态如何?如果我使用回收模式,我是否能够保持每个字段的状态(甚至是那些不在屏幕上的字段),从而能够在不丢失数据的情况下保存表单?

  1. 在 RecyclerView 中保存 EditText 内容这是组件之一,但同样的逻辑也应该应用于复选框或单选按钮。或者在状态维护中为光刻在这里

    结论:Litho +1、RecyclerView +1 都有特定的 API 来实现状态维护

如果我使用回收模式显示一个表单,我将如何处理多个表单?我们可以嵌套 RecyclerView 吗?表单需要像在垂直 RV 内一样依次显示,但如果表单本身是 RV,我应该如何处理?

  1. 这必须通过用户体验和技术能力来解决:根据用户行为恕我直言,我不鼓励嵌套垂直滚动,但是其他人能够实现它,您可以轻松找到如何在 SO 中实现。最佳解决方案是在 Andriod 或 litho 的回收站视图中进行水平滚动,如下所示

注意:如果您需要了解实施细节,请将其作为单独的问题提出,我很乐意为您提供帮助


更新#1:

这样做的问题是,对于大型表单(如 >20 个字段),它需要增加大量视图,并且 UI 线程会遭受很多损失。

UI 创建/布局必须在后端执行,只有添加到视图必须在 UI 线程上完成。并且 litho 是内置的。然而,同样可以实现本机回收器视图,但您必须离开 UI 线程并定期发布到 UI。


于 2017-08-02T03:49:32.677 回答
4

好的,这里有两个不同的问题。一是过度使用 UI 线程,二是保持匿名视图的状态。关于第一部分:

1.-Litho 可以帮助您。但是您必须将所有逻辑移至光刻组件而不是 android 小部件。因为我不知道你的代码库,所以我不知道这有多难。recyclerview 将有助于视图回收,但这只有在你身体健康的情况下才重要,使用列表。

2.-它可以,只要您有办法保留小部件状态的表示,您可以将其传递给适配器然后返回视图(我假设您通过代码生成所有窗口然后为零参考他们)等等。听起来很乱,而且很乱,所以我不会尝试。

3.-你可以,但是很乱。在这种情况下,最好的方法是在垂直回收器视图中放置水平回收器视图。将 recyclerviews 嵌套在另一个具有相同方向的 recyclerview 中会产生有趣的问题,例如“为什么这个单元格不滚动”。如果视图不需要它,我会避免使用 recyclerview 作为父视图。

现在,解决方案:

A)UI 重载:根据您的伪代码,您并没有夸大东西。您正在创建恰好是 View 子类的 java 对象。这很好,因为在后台线程中创建对象比在后台线程中膨胀(解析 XML 并将其用作参数以通过调用构造函数生成给定资源的相同副本)要容易得多。虽然 LinearLayout 上下文构造函数需要执行 UI 线程,但其他东西,如 textviews,则不需要。因此,您可以在 asynctask 中创建后者,并在生成整个层次结构后,执行需要 UI 线程的方法并将生成的布局添加到窗口中。对于不支持异步创建为 java 对象的视图类,您可以拥有一个仅包含该组件的 XML 文件,像 linearLayout 一样,然后使用支持包 asyncLayoutInflater 异步创建。该解决方案可以在任何代码库中实现,并允许您使 UI 生成完全异步。

B) 跟踪视图状态:同样,我假设您的视图层次结构是匿名的。如果是这样,您需要生成一个接口,您可以将其用作合约,以从生命周期感知组件(如活动)调用状态保存和状态加载。创建这样的接口后,子类化小部件并在每个小部件中创建一个订阅/事件总线系统,每次触发时都会从小部件保存/加载状态。这样,屏幕上的每个组件都可以在保持匿名的同时记住它们的状态。

于 2017-08-07T07:54:30.240 回答
3

只需使用 RecyclerView 并在运行时创建视图(您不是在膨胀,而是在实例化)动态创建和添加视图不应在中端设备上显着减慢 UI 线程。如果是这样,请调查其他地方的瓶颈

您可以通过在 RecyclerView 甚至是由 ScrollView 托管的 LinearLayout 中动态添加/删除/设置具有大量视图的文本来执行简单的基准测试,您会看到它变得流畅

于 2017-08-07T09:20:46.853 回答
2

使用android提供的jetpack composer

https://developer.android.com/jetpack/compose

于 2020-12-04T15:29:32.077 回答