我想在具有数千个(> 1.000)网格单元的片段中显示网格布局。为了节省代码行,我想在创建片段时以编程方式添加网格单元。网格单元不需要做更多的事情,而只是每个网格单元单独显示某种颜色。
问题是,每当创建片段时,UI都会阻塞几秒钟,因为必须首先设置网格布局。
我尝试使用AsyncLayoutInflater
,但这并不能真正解决我的问题,因为xml布局本身很小,并且在不阻塞UI的情况下会膨胀。在xml布局膨胀后创建并向网格布局添加数千个视图是阻止UI的原因。
所以我的问题是,如何在不阻止UI的情况下将所有这些网格单元添加到后台的网格布局中?
我的代码:
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.grid_fragment, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setupGrid()
}
private fun setupGrid() {
// Row and column count is currently set to 60
for (yPos in 0 until gridLayout.rowCount) {
for (xPos in 0 until gridLayout.columnCount) {
val gridCell = ImageView(activity)
val params = GridLayout.LayoutParams(GridLayout.spec(yPos, 1f), GridLayout.spec(xPos, 1f))
gridCell.layoutParams = params
gridLayout.addView(gridCell)
}
}
}
我的xml文件:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:android="http://schemas.android.com/apk/res/android">
<GridLayout
android:id="@+id/gridLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="240dp"
android:layout_marginBottom="240dp"
android:columnCount="60"
android:rowCount="60"
android:orientation="horizontal" />
</RelativeLayout>
屏幕截图应如下所示:
非常感谢!
答案 0 :(得分:0)
好的,就像Android文档所说的那样,永远不要在UI线程之外的任何视图上调用任何方法或构造函数,因为它不是线程安全的。它可以编译并实际运行,但是使用不安全。
我想出了一个解决方案/解决方法,它实际上只会延迟UI块,而用户可能会不注意它。这可能仅在我的特定情况下有效,因为仅在建立网络连接后,我才用数千个视图填充网格。填充视图仍会阻止UI,但用户可能不会注意到它。下面将对如何减少阻塞UI时间进行一些调整。
关键是要使用OnLayoutChangedListener。将所有视图添加到gridLayout后,我将调用gridLayout.addOnChangeListener并实现侦听器以处理网格单元的布局参数。
这是代码:
fun configureGridLayout(gridHeight: Int, gridWidth: Int) {
println("Setting grid dimensions to: ${gridHeight}x${gridWidth}")
runOnUiThread {
gridLayout.rowCount = gridHeight
gridLayout.columnCount = gridWidth
for (g in 0 until gridHeight * gridWidth) {
val gridCell = View(context!!)
gridLayout.addView(gridCell)
}
gridLayout.addOnLayoutChangeListener(LayoutChangeListener(gridLayout, this))
}
}
// This callback is fired when fragment was completely rendered in order to reduce UI blocking time
class LayoutChangeListener(private val gridLayout: GridLayout, private val gridLayoutConfiguredListener: GridLayoutConfiguredListener) : View.OnLayoutChangeListener {
override fun onLayoutChange(v: View?, left: Int, top: Int, right: Int, bottom: Int, oldLeft: Int, oldTop: Int, oldRight: Int, oldBottom: Int) {
v?.removeOnLayoutChangeListener(this)
val gridRowCount = gridLayout.rowCount
val gridColumnCount = gridLayout.columnCount
val gridHeight = gridLayout.height
val gridWidth = gridLayout.width
val margin = 1
val h = gridHeight / gridRowCount
val w = gridWidth / gridColumnCount
for (yPos in 0 until gridRowCount) {
for (xPos in 0 until gridColumnCount) {
val params = GridLayout.LayoutParams()
params.height = h - 2 * margin
params.width = w - 2 * margin
params.setMargins(margin, margin, margin, margin)
// Use post to get rid of "requestView() was called twice" errors
gridLayout.getChildAt(yPos * gridColumnCount + xPos).post {
gridLayout.getChildAt(yPos * gridColumnCount + xPos).layoutParams = params
}
}
}
gridLayoutConfiguredListener.onGridLayoutConfigured()
}
}