You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android Studio示例:从Assets读取XML生成动态TreeView

从Assets文件夹XML动态生成TreeView节点实现方案

没问题,我来帮你把硬编码的树节点改成从Assets里的XML动态读取生成。咱们一步步来,先理清楚核心步骤:定义XML结构、创建节点数据模型、解析XML构建树结构、最后替换Fragment里的硬编码逻辑。

1. 先定义Assets中的层级XML结构

首先你需要在assets文件夹下创建一个XML文件(比如命名为folder_structure.xml),按照你的层级结构来编写,示例结构如下:

<root>
    <folder name="Root Folder">
        <item name="File 1.txt"/>
        <folder name="Sub Folder 1">
            <item name="Sub File 1.1.txt"/>
            <item name="Sub File 1.2.txt"/>
        </folder>
        <folder name="Sub Folder 2">
            <item name="Sub File 2.1.txt"/>
        </folder>
    </folder>
</root>

你可以根据实际的层级需求调整标签和属性,比如如果是纯文件夹结构,也可以统一用<node>标签,只要解析时对应上就行。

2. 创建TreeNode数据模型

我们需要一个数据类来存储树节点的信息,包含节点名称和子节点列表:

// 如果用Java的话可以改成JavaBean,这里用Kotlin示例
data class TreeNode(
    val name: String,
    val children: MutableList<TreeNode> = mutableListOf()
)

3. 编写XML解析工具类

接下来写一个工具类,负责从Assets中读取XML并解析成TreeNode树结构:

import android.content.Context
import org.xmlpull.v1.XmlPullParser
import org.xmlpull.v1.XmlPullParserFactory

class XmlTreeParser(private val context: Context) {

    fun parseXmlFromAssets(xmlFileName: String): TreeNode? {
        return try {
            val factory = XmlPullParserFactory.newInstance()
            factory.isNamespaceAware = true
            val parser = factory.newPullParser()
            
            // 从Assets打开XML文件流
            context.assets.open(xmlFileName).use { inputStream ->
                parser.setInput(inputStream, null)
                parseNode(parser)
            }
        } catch (e: Exception) {
            e.printStackTrace()
            null
        }
    }

    private fun parseNode(parser: XmlPullParser): TreeNode? {
        var eventType = parser.eventType
        var currentNode: TreeNode? = null

        while (eventType != XmlPullParser.END_DOCUMENT) {
            when (eventType) {
                XmlPullParser.START_TAG -> {
                    val tagName = parser.name
                    val nodeName = parser.getAttributeValue(null, "name")
                    if (!nodeName.isNullOrEmpty()) {
                        currentNode = TreeNode(nodeName)
                        // 递归解析子节点
                        val childNode = parseNode(parser)
                        childNode?.let { currentNode.children.add(it) }
                    }
                }
                XmlPullParser.END_TAG -> {
                    return currentNode
                }
            }
            eventType = parser.next()
        }
        return currentNode
    }
}

这里用了XmlPullParser来逐节点解析,遇到<folder>或<item>标签时创建TreeNode,递归处理子节点,最后返回根节点。如果你的XML标签不同,记得修改parser.name的判断逻辑。

4. 修改FolderStructureFragment替换硬编码逻辑

现在回到你的FolderStructureFragment,把原来硬编码生成节点的代码替换成调用解析工具的逻辑。假设你之前用的是ExpandableListView来展示TreeView,示例修改如下:

class FolderStructureFragment : Fragment() {

    private lateinit var expandableListView: ExpandableListView
    private lateinit var treeAdapter: TreeExpandableAdapter
    private var rootNode: TreeNode? = null

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        val view = inflater.inflate(R.layout.fragment_folder_structure, container, false)
        expandableListView = view.findViewById(R.id.expandable_list_view)
        return view
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        
        // 解析Assets中的XML生成树节点
        val parser = XmlTreeParser(requireContext())
        rootNode = parser.parseXmlFromAssets("folder_structure.xml")
        
        // 初始化适配器(这里假设你有一个自定义的ExpandableListView适配器)
        rootNode?.let {
            treeAdapter = TreeExpandableAdapter(it)
            expandableListView.setAdapter(treeAdapter)
        }
    }

    // 自定义ExpandableListView适配器示例
    inner class TreeExpandableAdapter(private val rootNode: TreeNode) : BaseExpandableListAdapter() {

        override fun getGroupCount(): Int = rootNode.children.size

        override fun getChildrenCount(groupPosition: Int): Int = 
            rootNode.children[groupPosition].children.size

        override fun getGroup(groupPosition: Int): Any = rootNode.children[groupPosition]

        override fun getChild(groupPosition: Int, childPosition: Int): Any = 
            rootNode.children[groupPosition].children[childPosition]

        override fun getGroupId(groupPosition: Int): Long = groupPosition.toLong()

        override fun getChildId(groupPosition: Int, childPosition: Int): Long = 
            (groupPosition * 100 + childPosition).toLong()

        override fun hasStableIds(): Boolean = true

        override fun getGroupView(
            groupPosition: Int,
            isExpanded: Boolean,
            convertView: View?,
            parent: ViewGroup?
        ): View {
            val view = convertView ?: LayoutInflater.from(context)
                .inflate(android.R.layout.simple_expandable_list_item_1, parent, false)
            val textView = view.findViewById<TextView>(android.R.id.text1)
            textView.text = (getGroup(groupPosition) as TreeNode).name
            return view
        }

        override fun getChildView(
            groupPosition: Int,
            childPosition: Int,
            isLastChild: Boolean,
            convertView: View?,
            parent: ViewGroup?
        ): View {
            val view = convertView ?: LayoutInflater.from(context)
                .inflate(android.R.layout.simple_list_item_1, parent, false)
            val textView = view.findViewById<TextView>(android.R.id.text1)
            textView.text = (getChild(groupPosition, childPosition) as TreeNode).name
            return view
        }

        override fun isChildSelectable(groupPosition: Int, childPosition: Int): Boolean = true
    }
}

如果你的TreeView用的是第三方库(比如AndroidTreeView),那只需要把解析出来的TreeNode转换成对应库的节点格式即可,核心逻辑都是先解析XML得到层级结构,再绑定到视图。

注意事项

  • 确保Assets文件夹下的XML文件名和路径正确,解析时不要写错文件名
  • 处理XML解析的异常,避免崩溃
  • 如果你的XML结构更复杂(比如包含图标、文件类型等属性),可以扩展TreeNode类添加对应的字段,解析时一起读取

内容的提问来源于stack exchange,提问作者Quanta Salman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:38:57