RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 971797
Accepted
cheerful_weasel
cheerful_weasel
Asked:2020-04-20 02:56:17 +0000 UTC2020-04-20 02:56:17 +0000 UTC 2020-04-20 02:56:17 +0000 UTC

从 savedInstanceState 恢复后,LinearLayout 的子视图不会被移除

  • 772

我有一个输入字段的动态列表。那些。根据用户对某些值的选择,将显示输入字段列表。因此,我必须以编程方式将这些字段 (EditText) 添加到我专门放置在标记中的空 LinearLayout。代码是在某个时刻添加的(当用户在微调器中选择了所需的类别时)。创建输入字段的代码如下:

    fun generateAdditionalFields(fields: ArrayList<String>) {
        tempAdditionalFields.removeAll(tempAdditionalFields)
        var isFirst = true
        fields.forEach {
            tempAdditionalFields.add(makeEditText(it, it, isFirst))
            isFirst = false
        }
        additional_fields_block.removeAllViews()
        tempAdditionalFields.forEach {
            additional_fields_block.addView(it)
        }
    }

    fun makeEditText(hint: String, name: String, first: Boolean) : EditText {
        val editText = EditText(ContextThemeWrapper(this, R.style.MainInput), null, 0)
        editText.hint = hint
        editText.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
        editText.tag = name
        if (!first) editText.setMargin(topMargin = dpToPix(5f))
        return editText
    }

我还有一个列表来保存这些输入字段tempAdditionalFields,以便以后可以保存用户的输入。

当用户切换类别时,旧的输入字段将被删除(从列表和从LinearLayout)并重新生成。

一切正常,没有问题。但我决定在设备屏幕旋转时修改代码并保存数据,并在重新创建活动后恢复它们。通常这个操作没有问题。但是在这种情况下,在重新创建活动之后,我恢复了列表tempAdditionalFields,然后将其中的所有内容添加EditText回 LinearLayout,但随后它给出了一个错误,他们说这些视图已经包含在那里。然后我在添加之前打电话additional_fields_block.removeAllViews(),仍然得到同样的错误。然后我删除了添加。但是屏幕上会显示全新的输入字段。是的,这些是重新创建活动之前的输入字段,但没有输入的文本。虽然在恢复列表中tempAdditionalFields输入的文字是。为了实验,我一般去掉这个列表的恢复。甚至在恢复后删除了这些输入字段的添加。结果是一样的。最有趣的是,该方法additional_fields_block.removeAllViews()在重新创建后不起作用。或者更确切地说,如果我在onCreateor onStartor中调用它onResume。但是,如果您创建一个按钮并在其上挂一个侦听器,并且当您单击它时,设置相同的视图删除,那么当您单击它时,它会按原样删除。

我没有发布所有代码,因为它有很多。但这里有一些部分。

创建:

    var step = 1
    var avatar_id : Int? = null
    var tempAdditionalFields = LinkedList<EditText>()
    var companies = LinkedList<Company>()
    val companiesAdapter = CompaniesShortListAdapter(companies)
    var dontSwitchFields = false

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_create_user)
        if (!restoreFromSavedInstance(savedInstanceState)){
            GetCompaniesListTask().execute()
        } else dontSwitchFields = true
        switchUserInfoBtnsVis()
        switchFirmNameBtnsVis()
        switchChooseRoleBtnsVis()
        setListeners()
        switchStep(step)
    }

保存和恢复方法(这里我为实验更改并注释掉了一些行):

    override fun onSaveInstanceState(outState: Bundle?) {
        outState?.let {bundle ->
            bundle.putInt("step", step)
            avatar_id?.let { bundle.putInt("avatar_id", it) }

            bundle.putSerializable("tempAdditionalFields", tempAdditionalFields)
            bundle.putSerializable("companies", companies)
        }
        super.onSaveInstanceState(outState)
    }

    fun restoreFromSavedInstance(savedInstanceState: Bundle?): Boolean {
        savedInstanceState?.let { bundle ->
            step = bundle.getInt("step")
switchStep(step)
            avatar_id = bundle.getInt("avatar_id")
//            tempAdditionalFields.removeAll(tempAdditionalFields)
//            tempAdditionalFields.addAll(bundle.getSerializable("tempAdditionalFields") as Collection<EditText>)
/*            tempAdditionalFields.forEach {
                Log.e("TEST_EDIT", "edit: ${it.text}")
            }*/
            additional_fields_block.removeAllViews()
            companies.removeAll(companies)
            companies.addAll(bundle.getSerializable("companies") as Collection<Company>)
            companiesAdapter.notifyDataSetChanged()
            return true
        }
        return false
    }

我了解系统本身会恢复这些添加的视图。但是在什么阶段呢?而且我知道在这种情况下,可以采用另一种方式,只需保存在字段中输入的数据,然后再次填写。但我想追根究底,为什么我不能删除在旋转屏幕之前添加的视图(EditText)

android
  • 1 1 个回答
  • 10 Views

1 个回答

  • Voted
  1. Best Answer
    cheerful_weasel
    2020-04-20T19:43:14Z2020-04-20T19:43:14Z

    总的来说,事实证明,问题同时出现在两个地方。简而言之,它们是:

    1. 在微调器中
    2. 在删除视图的方法中

    现在更详细地说,突然有人会派上用场。

    1. 微调器

    我的微调器上有一个监听器,我在其中处理onItemSelected. 当这个方法被触发时,我调用了输入字段的生成。那些。根据选择的类别,他们创建了自己的EditText并且每次都创建了编号。但我不认为这种方法在初始化微调器中的类别列表时也有效。那些。一旦类别列表(或适配器)连接到微调器,就会触发此方法。

    当我意识到这一点时,我改变了我的方法。我创建了一个变量,存储被选中的类别在微调器中的位置,默认为0,当方法被触发时,onItemSelected我检查这个变量的值是否与新的位置匹配。如果不匹配,那么用户已经改变了类别,然后我们将新的位置保存在这个变量中并执行我们需要的方法来生成输入字段。

    我在屏幕更改时保存并恢复此变量。我在微调器恢复之前从 onCreate 方法执行此操作。因此,当微调器恢复并设置旧位置时,它将匹配恢复的变量并且不会生成输入字段。

    这解决了从头开始重新创建视图的问题。但是错误问题仍然存在。java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.

    2. 删除视图

    如果我直接访问包含输入字段的视图并调用removeAllViews(),然后尝试添加输入字段,则会发生相同的错误。起初我将它的文本理解为“父视图已经包含这个子视图,首先将它从父视图中删除”。但是意思却有些不同“子视图已经有了父视图。首先,removeView()在子视图的父视图上调用方法。”

    虽然这两个句子看起来意思相同,但这并不完全正确。起初,我尝试直接在视图上调用此方法,将每个EditText恢复的数组分别传递给它。但它没有用。

    但事实证明,显然EditText's 属于旧的additional_fields_block(视图LinearLayout),而新的没有子视图。因此,他们的父母不是新的additional_fields_block,而是旧的。旧的additional_fields_block仍然存在于内存中,因为在EditText. 然后我创建了这个方法:

        fun restoreAdditionalFields(){
            tempAdditionalFields.forEach {
                (it.parent as ViewGroup).removeView(it)
                additional_fields_block.addView(it)
            }
        }
    

    那些。我从每个文本字段中获取祖先并从那里删除该文本字段,然后将其添加到新的additional_fields_block. 至少我是这么理解的。也许我的猜测是错误的,那么请纠正我。了解这种机制实际上是如何工作的很有趣。

    没错,从 onCreate 我的方法不起作用(没有发生错误,但也没有效果)。然后我把他的电话放到这个方法中:

        override fun onRestoreInstanceState(savedInstanceState: Bundle?) {
            super.onRestoreInstanceState(savedInstanceState)
            restoreAdditionalFields()
        }
    

    我不太明白为什么会这样。有人可以解释吗?

    • 1

相关问题

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    根据浏览器窗口的大小调整背景图案的大小

    • 2 个回答
  • Marko Smith

    理解for循环的执行逻辑

    • 1 个回答
  • Marko Smith

    复制动态数组时出错(C++)

    • 1 个回答
  • Marko Smith

    Or and If,elif,else 构造[重复]

    • 1 个回答
  • Marko Smith

    如何构建支持 x64 的 APK

    • 1 个回答
  • Marko Smith

    如何使按钮的输入宽度?

    • 2 个回答
  • Marko Smith

    如何显示对象变量的名称?

    • 3 个回答
  • Marko Smith

    如何循环一个函数?

    • 1 个回答
  • Marko Smith

    LOWORD 宏有什么作用?

    • 2 个回答
  • Marko Smith

    从字符串的开头删除直到并包括一个字符

    • 2 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5