最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

android - How can I save the contents of a table and then reload it - Stack Overflow

programmeradmin3浏览0评论

I am trying to write a program in Kotlin for the first time, and I'm banging my head against my own inexperience. The problem I'm running up against would be the work of a moment in Objective C (because I have experience of that language) but Kotlin is proving trickier.

I need to be able to save the contents of a table (of varying length - the user can both add and delete rows), and then load it again when the program is relaunched. I'm able to save the table contents as follows…

    fun saveTableData(context: Context, tableLayout: TableLayout) {
        val sharedPreferences = context.getSharedPreferences("TableData", Context.MODE_PRIVATE)
        val editor = sharedPreferences.edit()
        val rowCount = tableLayout.childCount
        editor.clear()

        println("Saving $rowCount rows")

        for (i in 1 until rowCount) { // 1 because we omit the header row
            val tableRow = tableLayout.getChildAt(i) as TableRow
            val colCount = tableRow.childCount

            for (j in 0 until colCount - 1) {
                val textView = tableRow.getChildAt(j) as TextView
                val key = "row_${i}_col_${j}"
                val value = textView.text.toString()

                println("$key, $value")
                editor.putString(key, value)
            }
        }

        editor.apply()
    }

The resultant saved XML looks correct…

<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
    <string name="row_1_col_2"></string>
    <string name="row_2_col_0">Clark</string>
    <string name="row_2_col_3"></string>
    <string name="row_2_col_1">Kent</string>
    <string name="row_2_col_2"></string>
    <string name="row_1_col_1">Wade</string>
    <string name="row_1_col_0">Wilson</string>
</map>

When I try to reload the file, it a) loads too many rows (three, instead of two) and the rows all say "Clark Kent"

    fun loadTableData(context: Context, tableLayout: TableLayout) {
        val tableDataXml: String = xmlHelper.getSharedPreferencesRawXml(context, "TableData")
        if (tableDataXml.isNullOrEmpty()) { return }

        val xmlArray = xmlHelper.parseXML(tableDataXml)

        val arraycount = xmlArray.count()
        println("Loading $arraycount rows")

        tableLayout.removeAllViews()

        for (row in xmlArray) {
            val tableRow = TableRow(context)
            for (cell in row) {
                val textView = TextView(context)
                textView.text = cell ?: ""
                textView.setPadding(16, 16, 16, 16)
                tableRow.addView(textView)
            }
            tableLayout.addView(tableRow)
        }
    }

with the helper class defined as follows…

class XmlHelperFunctions {
    fun <T> addToArray(originalArray: Array<Array<T>>, newElement: Array<T>): Array<Array<T>> {
        @Suppress("UNCHECKED_CAST")
        val newArray = java.lang.reflect.Array.newInstance(
            originalArray::class.javaponentType!!,
            originalArray.size + 1
        ) as Array<Array<T>>

        for (i in originalArray.indices) {
            newArray[i] = originalArray[i]
        }
        newArray[originalArray.size] = newElement

        return newArray
    }

    fun parseXML(xmlData: String?): Array<Array<String?>> {
        val parser = Xml.newPullParser()
        parser.setInput(xmlData?.reader() ?: "".reader())
        var eventType = parser.eventType
        val emptyRow = arrayOfNulls<String>(4) // this will need to be updated if the number of data fields to be stored increases
        var table: Array<Array<String?>> = arrayOf(emptyRow)
        val seenRows = mutableSetOf<Int>() //XML is not necessarily in the right order

        while (eventType != XmlPullParser.END_DOCUMENT) {
            if (eventType == XmlPullParser.START_TAG && parser.name == "string") {
                val name = parser.getAttributeValue(null, "name")
                val value = parser.nextText()
                val row = name.substringAfter("row_").substringBefore("_col_").toInt()
                val col = name.substringAfter("col_").toInt()

                if (!seenRows.contains(row)) {
                    println("row: $row")
                    table = addToArray(table, emptyRow) // the row number changed - so add a row
                    seenRows.add(row)
                }

                table[row][col] = value
            }
            try {
                eventType = parser.next()
                println("Parsing next")

            } catch (e: Exception) {
                println("ParseXML: Failed trying to parse.next")
                return table
            }
        }
        return table
    }

    fun getSharedPreferencesRawXml(context: Context, sharedPreferencesName: String): String {
        // Locate the SharedPreferences XML file
        val prefsFile = File(context.filesDir.parent, "shared_prefs/$sharedPreferencesName.xml")

        // Read the file contents as text
        return if (prefsFile.exists()) {
            prefsFile.readText()
        } else {
            "" // need to return an empty string, bail early.
        }
    }
}

If anyone knows ObjC then all I'm trying to do is the equivalent of

//Save, where array is the array populating the NSTable

[[NSUserDefaults standardUserDefaults] setObject:array forKey:@"SavedArray"];
[[NSUserDefaults standardUserDefaults] synchronize];

//Restore

NSArray *reloadedArray = [[NSUserDefaults standardUserDefaults] objectForKey:@"SavedArray"];
NSMutableArray *mutableReloadedArray = [NSMutableArray arrayWithArray:reloadedArray];
发布评论

评论列表(0)

  1. 暂无评论