【问题标题】:Solution to build dynamic forms with Android用Android构建动态表单的解决方案
【发布时间】:2017-12-17 02:53:56
【问题描述】:

我实际上正在开发一个 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

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

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

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

提前感谢您的宝贵时间。

【问题讨论】:

  • 如果您担心回收表单视图,请使用 ArrayList 和适当的模型类来存储表单数据。为了在单个RecyclerView 中显示多个RecyclerViews,请使用NestedScrollView。您可以使用 NestedScrollView 并在其中添加 RecyclerView。其中,在运行时,将填充多个RecyclerViews。我没用过Litho,所以不能说话。如果您需要我发布任何代码或任何内容,也请告诉我。
  • 好吧,我真的不明白如果NestedScrollView 没有实现 ViewHolder 模式,它怎么能像RecyclerView 一样工作?也许如果你有时间,一些伪代码可以帮助我。
  • 好的。给我一些时间。我会用必要的代码 sn-ps 为你编译一个答案。

标签: android forms android-recyclerview litho


【解决方案1】:

使用android提供的jetpack composer

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

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        【解决方案4】:

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

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

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

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

          为此,我想使用 litho,理由是 here,因为您的要求似乎有更多的变量计数 viewtypesreference

          结论:Litho +1,RecyclerView +0

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

        1. Saving EditText content in RecyclerView 这是组件之一,但同样的逻辑也应该应用于复选框或radiobutton。或者在 state-maintenance 中,对于 litho 是 here

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

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

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

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


        更新#1:

        问题在于,对于大型表单(例如 >20 个字段),它需要增加大量视图,并且 UI 线程会受到很大影响。

        UI 创建/布局必须在后端执行,只有添加到视图必须在 UI 线程上完成。并且光刻做到了in-built。然而,同样可以实现原生回收器视图,但您必须离开 UI 线程并定期发布到 UI。


        【讨论】:

        • 我认为您和@Fco P. 给了我很好的信息,可以帮助我做出正确的决定。我仍然需要考虑它,但现在我应该更清楚地处理我的用例。我还提到了 Fco P. 的回答,因为他也应该得到一半的赏金,而且他的回答可能会帮助其他人:stackoverflow.com/a/45541920/3520621
        猜你喜欢
        • 1970-01-01
        • 2011-12-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-08-26
        • 1970-01-01
        • 2017-02-26
        • 2019-09-07
        相关资源
        最近更新 更多