android - 指定的孩子已经有父母
问题描述
用户单击一个按钮,editText 中的数据将发送到该片段。这些数据应该被放入一个新的表行,但是在单击将数据发送到这个片段的按钮后,我总是得到这个 logcat:
Process: com.example.nlp_expense_tracker, PID: 32439
java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
at android.view.ViewGroup.addViewInner(ViewGroup.java:5235)
at android.view.ViewGroup.addView(ViewGroup.java:5064)
at android.view.ViewGroup.addView(ViewGroup.java:5004)
at android.view.ViewGroup.addView(ViewGroup.java:4976)
这是我处理收到的数据的片段:
class HistoryFragment : Fragment() {
private val dataStore = ArrayList<String>()
private val dataAmount = ArrayList<String>()
private val dataDate = ArrayList<String>()
private lateinit var store: TextView
private lateinit var amount: TextView
private lateinit var date: TextView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,savedInstanceState: Bundle?):
View {val view: View = inflater.inflate(R.layout.fragment_history, container, false)
date= view.findViewById(R.id.date)
store= view.findViewById(R.id.store)
amount = view.findViewById(R.id.amount)
val table : TableLayout = view.findViewById(R.id.tableHistorie)
val row : TableRow = view.findViewById(R.id.tableRowOne)
// Use the Kotlin extension in the fragment-ktx artifact
setFragmentResultListener("requestKey") { requestKey, bundle ->
// We use a String here, but any type that can be put in a Bundle is supported
val result = bundle.getString("bundleKey")
dataStore.add(result.toString())
for(i in dataStore.indices)
{
val storeName = dataStore [i]
store.text = storeName
}
row.addView(store)
table.addView(row)
}
setFragmentResultListener("requestKey2") { requestKey, bundle ->
// We use a String here, but any type that can be put in a Bundle is supported
val result2 = bundle.getString("bundleKey2")
// Do something with the result
dataAmount.add(result2.toString())
for(i in dataAmount.indices)
{
val storeName = dataAmount [i]
amount.text = storeName
}
row.addView(amount)
table.addView(row)
}
setFragmentResultListener("requestKey3") { requestKey, bundle ->
// We use a String here, but any type that can be put in a Bundle is supported
val result3 = bundle.getString("bundleKey3")
// Do something with the result
dataDate.add(result3.toString())
for(i in dataDate.indices)
{
val storeName = dataDate [i]
date.text = storeName
}
row.addView(date)
table.addView(row)
}
return view
}
}
这个片段的 XML:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TableLayout
android:id="@+id/tableHistorie"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:stretchColumns="+"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<TableRow
android:id="@+id/tableRowOne"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="@+id/store"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Store" />
<TextView
android:id="@+id/amount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Amount spent" />
<TextView
android:id="@+id/date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Date" />
</TableRow>
</TableLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
解决方案
inflater.inflate(R.layout.fragment_history, container, false)
创建类似于上图的视图层次结构(从 xml 创建视图对象的实例)。view.findViewById
返回已经存在的视图,view
如果不存在则返回 null。- 当框架向父视图添加一些视图时,它会将父视图的引用写入子视图,但在检查子视图是否已经在
ViewGroup.addViewInner
和View.assignParent
方法中具有父视图(对父视图的引用)之前。
您做了什么:您查看存在的视图(在屏幕上绘制)并尝试将其更多地放到 tableRowOne 中。你不能这样做。
我有一个建议你真正想要做什么:向 tableView 添加新行。如果我是对的,你有一些选择:
- 通过每个创建 TableRow 的新实例和 TextView 的 3 个实例,然后将 textviews 放到新的 TableRow 中,然后将它们添加到表中,如下所示:
table.addView(
TableRow().apply{
addView(TextView())
addView(TextView())
addView(TextView())
}
)
- 使用与第 1 段相同的方法,将行布局放在单独的 xml 中,名称例如“row_layout.xml”。
<?xml version="1.0" encoding="utf-8"?>
<TableRow
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/tableRowOne"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="@+id/store"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Store" />
<TextView
android:id="@+id/amount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Amount spent" />
<TextView
android:id="@+id/date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Date" />
</TableRow>
然后使用标签在主布局中包含行布局包括:
...
<TableRow
android:id="@+id/tableRowOne"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<include layout="@layout/row_layout" />
....
但是单独布局文件的主要意义是使用布局充气器来创建新行:
val newRow: View = inflater.inflate(R.layout.row_layout, table, false)
val newstore= newRow.findViewById(R.id.store)
newstore.text = "some text"
table.add(newRow)
- 我认为最好的方法是为你的表使用 RecyclerView。您的行将是ViewHolder 的视图。带有 recyclerView 的 Google 示例应用。
推荐阅读
- ios - 是否可以获取 iphone 的物理键(音量、电源、主页)的映射并触发它们?
- python - 当 text 与 dict 键相同时,将 text 替换为 dict 值。但是,当文本与列表中的值相同时,不要替换文本
- python - 安装包时 JetBrains DataSpell ModuleNotFoundError 错误
- eclipse - 在 IntelliJ 中运行新项目时出现挂钩错误
- javascript - 模态表单上的动态表格显示
- c# - 下拉菜单未保存 - MVC C# 共享组合类并保存到另一个表中
- environment-variables - Bitbucket 管道环境变量以触发管道步骤
- swift - 如何使用 Apple HealthKit 监控 headphoneAudioExposureEvent?
- css - 引导切换器不显示内容
- qt - QT QML将文本区域放在工具栏底部而不使用应用程序“标题”