使用 Android 构建动态表单的解决方案

Solution to build dynamic forms with Android

我实际上正在开发一个 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. 使用Litho by Facebook

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

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

这更像是一个 "good practice" 问题,它给出了实现我的目标的正确方法或正确方法之一,而不是需要代码示例等的具体答案。

提前感谢您的宝贵时间。

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

Is it a good use case to use Litho? Or using a RecyclerView is enough?

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

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

    为此我想使用光刻,理由是 here as your requirement seems to have more of variable count of viewtypesreference

    结论:Litho +1,RecyclerView +0

What about the state of my views? If I use a Recycling pattern, would I be able to keep the state of each of my fields (even those off-screen) and so being able to save the form without losing data?

  1. This is one the component but same logic should be appliced to checkbox or as well. or as in state-maintenance for litho is here

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

If I use a Recycling pattern to display one form, how would I handle multiple forms? Can we have nested RecyclerView? Forms need to be displayed one after another like inside a vertical RV but if forms themselves are RV, how should I handle this?

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

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


更新 #1:

The issue with this is that with large forms (like >20 fields), it need to inflate lot of views and the UI thread suffer a lot.

UI creation/layout 必须在后端执行,只有添加到视图必须在 UI 线程上完成。光刻技术做到了 in-built。然而,同样可以实现本机回收器视图,但是你必须定期关闭 UI 线程和 post 到 UI.


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

1.-Litho 可以帮助您解决这个问题。但是您必须将所有逻辑转移到 litho 组件而不是 android 小部件。因为我不知道你的代码库,所以我不知道这有多难。 recyclerview 将有助于视图回收,但只有在您使用列表的情况下,这才重要。

2.-它可以,只要你有办法保持小部件状态的表示,你可以传递给适配器然后返回到视图(我假设你生成所有 windows 通过代码,然后对它们有零引用)等等。听起来很乱,而且很乱,就不试了。

3.-可以,但是很乱。在这种情况下,最好的方法是在垂直回收视图中放置水平回收视图。将 recyclerviews 嵌套在另一个具有相同方向的 recyclerview 中会产生有趣的问题,例如 "Why this cell is not scrolling"。如果视图不需要它,我会避免使用 recyclerview 作为父视图。

现在,解决方案:

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

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

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

您可以通过 adding/removing/setting 在 RecyclerView 或什至由 ScrollView 托管的 LinearLayout 中动态显示大量视图的文本执行简单的基准测试,您会发现它很顺利

使用 android

提供的 Jetpack Composer

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