如何在不阻止UI的情况下向GridLayout添加许多视图?

时间:2020-08-26 15:30:55

标签: android performance user-interface grid-layout

我想在具有数千个(> 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>

屏幕截图应如下所示:

非常感谢!

1 个答案:

答案 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()
    }
}
相关问题