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

如何对存储加密数据的ArrayList进行排序并在RecyclerView中展示

解决加密数据列表排序与RecyclerView点击位置问题

我来帮你梳理一下问题,你现在的核心痛点是直接对加密字段排序导致顺序不对,以及随之而来的点击位置匹配问题,我们一步步来修复:

1. 修正排序逻辑:基于解密后的明文排序

你之前的sortBy { it.PassItemApp.toString() }是对加密后的字符串排序,这当然得不到按字母顺序排列的结果——加密后的字符串和明文的字符顺序完全无关。我们需要先解密每个PassItem的App名称,再以此为依据排序。

方案一:直接在排序时解密(快速实现)

修改viewDocuments方法中的排序代码,把解密逻辑嵌入到排序条件中:

private fun viewDocuments(){
    documentslist = dbHandler.getDocuments(this)
    
    // 按解密后的App名称字母排序
    documentslist.sortBy { passItem ->
        // 复用你Adapter中的解密逻辑,获取明文
        val initialisationVector = passItem.PassItemIvApp
        val bytesIV = Base64.decode(initialisationVector, Base64.NO_WRAP)
        val oisIV = ObjectInputStream(ByteArrayInputStream(bytesIV))
        val initializationVectorIV = oisIV.readObject() as ByteArray

        val encryptedText = passItem.PassItemApp
        val bytesText = Base64.decode(encryptedText, Base64.NO_WRAP)
        val oisText = ObjectInputStream(ByteArrayInputStream(bytesText))
        val textByteArray = oisText.readObject() as ByteArray

        val key = passItem.PassItemKeyApp
        val keyText = Base64.decode(key, Base64.NO_WRAP)
        val oisKey = ObjectInputStream(ByteArrayInputStream(keyText))
        val keyToDecrypt = oisKey.readObject() as SecretKey

        val aesDecrypt = Decrypted(keyToDecrypt,initializationVectorIV)
        val decryptedByteArray = aesDecrypt.decrypt(textByteArray)
        decryptedByteArray.toString(charset("UTF_8"))
    }

    adapter = DocumentAdapter(this,documentslist,this)
    rv = findViewById(R.id.recyclerView)
    rv.layoutManager = LinearLayoutManager(this, LinearLayout.VERTICAL,false)
    rv.adapter = adapter
}

方案二:缓存明文(性能优化)

上面的方法每次排序都要重复解密所有项,性能不太友好。如果可以修改PassItem类,建议添加一个明文缓存字段,避免重复解密:

// 修改PassItem类,添加缓存字段
data class PassItem(
    // 你的原有字段...
    val PassItemApp: String,
    val PassItemIvApp: String,
    val PassItemKeyApp: String,
    // 新增明文缓存字段
    var decryptedAppName: String? = null
)

然后在排序前批量解密并缓存:

private fun viewDocuments(){
    documentslist = dbHandler.getDocuments(this)
    
    // 先批量解密所有项并缓存明文
    documentslist.forEach { passItem ->
        if (passItem.decryptedAppName == null) {
            // 解密逻辑和之前一致
            val initialisationVector = passItem.PassItemIvApp
            val bytesIV = Base64.decode(initialisationVector, Base64.NO_WRAP)
            val oisIV = ObjectInputStream(ByteArrayInputStream(bytesIV))
            val initializationVectorIV = oisIV.readObject() as ByteArray

            val encryptedText = passItem.PassItemApp
            val bytesText = Base64.decode(encryptedText, Base64.NO_WRAP)
            val oisText = ObjectInputStream(ByteArrayInputStream(bytesText))
            val textByteArray = oisText.readObject() as ByteArray

            val key = passItem.PassItemKeyApp
            val keyText = Base64.decode(key, Base64.NO_WRAP)
            val oisKey = ObjectInputStream(ByteArrayInputStream(keyText))
            val keyToDecrypt = oisKey.readObject() as SecretKey

            val aesDecrypt = Decrypted(keyToDecrypt,initializationVectorIV)
            val decryptedByteArray = aesDecrypt.decrypt(textByteArray)
            passItem.decryptedAppName = decryptedByteArray.toString(charset("UTF_8"))
        }
    }
    
    // 用缓存的明文排序
    documentslist.sortBy { it.decryptedAppName }

    adapter = DocumentAdapter(this,documentslist,this)
    rv = findViewById(R.id.recyclerView)
    rv.layoutManager = LinearLayoutManager(this, LinearLayout.VERTICAL,false)
    rv.adapter = adapter
}

同时Adapter也可以直接用缓存的明文,避免重复解密:

override fun onBindViewHolder(holder: ViewHolder, position: Int) {
    val document : PassItem = documents[position]
    // 优先使用缓存的明文,兜底才重新解密
    holder.txtDocApp.text = document.decryptedAppName ?: run {
        // 这里的解密逻辑和之前一致,解密后更新缓存
        val initialisationVector = document.PassItemIvApp
        val bytesIV = Base64.decode(initialisationVector, Base64.NO_WRAP)
        val oisIV = ObjectInputStream(ByteArrayInputStream(bytesIV))
        val initializationVectorIV = oisIV.readObject() as ByteArray

        val encryptedText = document.PassItemApp
        val bytesText = Base64.decode(encryptedText, Base64.NO_WRAP)
        val oisText = ObjectInputStream(ByteArrayInputStream(bytesText))
        val textByteArray = oisText.readObject() as ByteArray

        val key = document.PassItemKeyApp
        val keyText = Base64.decode(key, Base64.NO_WRAP)
        val oisKey = ObjectInputStream(ByteArrayInputStream(keyText))
        val keyToDecrypt = oisKey.readObject() as SecretKey

        val aesDecrypt = Decrypted(keyToDecrypt,initializationVectorIV)
        val decryptedByteArray = aesDecrypt.decrypt(textByteArray)
        val textAfterDecryption = decryptedByteArray.toString(charset("UTF_8"))
        document.decryptedAppName = textAfterDecryption
        textAfterDecryption
    }
}

2. 修复点击位置问题

你当前传递position到下一个页面的方式有隐患——如果列表后续发生变化(比如新增/删除项),position对应的对象可能会出错。更可靠的方式是直接传递PassItem对象:

首先让PassItem实现Serializable接口:

data class PassItem(...) : Serializable

然后修改onItemClick方法:

override fun onItemClick(position: Int) {
    val clickedItem = documentslist[position]
    val intent = Intent(this@HomeActivity,DocActivity::class.java)
    intent.putExtra("clickedItem", clickedItem)
    startActivity(intent)
}

在DocActivity中接收对象:

val clickedItem = intent.getSerializableExtra("clickedItem") as PassItem

这样不管列表怎么排序,你传递的都是正确的对象,不会因为position变化而匹配错误。

额外优化建议

  • 封装解密逻辑:把解密代码抽成一个工具类(比如EncryptionUtils),提供fun decryptAppName(passItem: PassItem): String方法,避免在Activity和Adapter中重复写相同的代码,提升可维护性。
  • 后台线程执行解密:解密是耗时操作,建议用Coroutine在IO线程执行,避免主线程卡顿:
    private fun viewDocuments(){
        lifecycleScope.launch(Dispatchers.IO) {
            documentslist = dbHandler.getDocuments(this@HomeActivity)
            // 解密+排序逻辑放在IO线程
            documentslist.forEach { /* 解密缓存 */ }
            documentslist.sortBy { it.decryptedAppName }
            
            // 切换回主线程更新UI
            withContext(Dispatchers.Main) {
                adapter = DocumentAdapter(this@HomeActivity,documentslist,this@HomeActivity)
                rv = findViewById(R.id.recyclerView)
                rv.layoutManager = LinearLayoutManager(this@HomeActivity, LinearLayout.VERTICAL,false)
                rv.adapter = adapter
            }
        }
    }
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.01 03:07:34