Android 13下Block Store卸载重装后无法读取数据求助
Android 13 卸载重装后 Block Store 数据无法读取的解决方案
问题概述
已实现Block Store的数据存储与读取功能,存储后直接读取在所有设备上均正常。但卸载重装应用后,Android 9-12设备可正常读取数据,Android 13设备(Pixel 7、Samsung S21测试)返回空结果列表,已在AndroidManifest.xml中设置allowBackup="true"。
解决步骤
1. 添加跨版本恢复配置
Android 13默认仅允许恢复与当前应用版本相同或更高版本的备份数据,卸载重装后若应用版本未变更,会触发该限制导致数据无法恢复。需在AndroidManifest.xml的<application>标签中添加:
android:restoreAnyVersion="true"
该配置允许系统恢复任意版本的备份数据,适配卸载重装后的场景。
2. 等待备份完成再操作
存储数据后不要立即卸载应用,需等待系统完成备份同步(可通过系统设置-系统-备份查看进度),避免因备份未完成导致数据丢失。
3. 手动验证备份逻辑
可通过adb命令手动触发备份和恢复,确认数据是否正确备份:
- 备份命令:
adb backup -f backup.ab -noapk com.your.package.name - 恢复命令:
adb restore backup.ab
完整代码参考
Activity代码
class TestBlocksActivity : AppCompatActivity() { lateinit var binding: ActivityTestBlockBinding private val blockstoreClient by lazy { Blockstore.getClient(applicationContext) } private val tokenKey = "key.token.stage" private val tokenValue = "token.test" override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityTestBlockBinding.inflate(layoutInflater) setContentView(binding.root) binding.deleteTokenButton.setOnClickListener { deleteBlockstoreData() } binding.storeTokenButton.setOnClickListener { storeBlockstoreData() } binding.loadTokenButton.setOnClickListener { getBlockstoreData() } } private fun storeBlockstoreData() { val tokenRequest = StoreBytesData.Builder() .setShouldBackupToCloud(true) .setBytes(tokenValue.toByteArray()) .setKey(tokenKey) .build() blockstoreClient.storeBytes(tokenRequest) .addOnSuccessListener { binding.lastActionText.text = """Token stored: $tokenValue """ binding.storedDataText.text = "Unkown - Load to check" Timber.tag("BLOCKSTORE_TEST").d("""Stored token: {"$tokenKey", "$tokenValue"}""") } .addOnFailureListener { e -> binding.lastActionText.text = "Exception while storing key" Timber.tag("BLOCKSTORE_TEST").e(e) } } private fun getBlockstoreData() { val retrieveRequest = RetrieveBytesRequest.Builder() .setRetrieveAll(true) .build() blockstoreClient.retrieveBytes(retrieveRequest) .addOnSuccessListener { result -> if (result.blockstoreDataMap.isEmpty()) { binding.lastActionText.text = "retrieving token: no token found" Timber.tag("BLOCKSTORE_TEST").d("Retreiving token: no token found") } result.blockstoreDataMap.forEach { (key, value) -> val valueString = String(value.bytes) if (key == tokenKey) { binding.lastActionText.text = "Retrieved token: $valueString" binding.storedDataText.text = valueString } Timber.tag("BLOCKSTORE_TEST").d("""Retrieved token: {"$key", "$valueString"}""") } } .addOnFailureListener { binding.lastActionText.text = "Exception while retreiving key" Timber.tag("BLOCKSTORE_TEST").e(it) } } private fun deleteBlockstoreData() { val deleteBytesRequest = DeleteBytesRequest.Builder() .setDeleteAll(true) .build() blockstoreClient.deleteBytes(deleteBytesRequest) .addOnSuccessListener { success -> binding.lastActionText.text = if (success) "Deleted key: $tokenKey" else "Could not delete key" if (success) binding.storedDataText.text = "no value" Timber.tag("BLOCKSTORE_TEST").d("${binding.lastActionText.text}") } .addOnFailureListener { binding.lastActionText.text = "Exception while deleting key" Timber.tag("BLOCKSTORE_TEST").e(it) } } }
Layout代码
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent" android:padding="24dp"> <TextView android:id="@+id/stored_data_label" android:layout_width="0dp" android:layout_height="wrap_content" app:layout_constraintTop_toTopOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" android:textSize="20sp" android:textStyle="bold" android:text="Loaded token:"/> <TextView android:id="@+id/stored_data_text" android:layout_width="0dp" android:layout_height="wrap_content" android:gravity="start" android:textSize="20sp" android:text="no token value loaded yet" app:layout_constraintTop_toBottomOf="@+id/stored_data_label" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" /> <TextView android:layout_marginTop="20dp" android:id="@+id/last_action_label" android:layout_width="0dp" android:layout_height="wrap_content" app:layout_constraintTop_toBottomOf="@+id/stored_data_text" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" android:textSize="20sp" android:textStyle="bold" android:text="Last action:"/> <TextView android:id="@+id/last_action_text" android:layout_width="0dp" android:layout_height="wrap_content" android:gravity="start" android:textSize="20sp" android:text="no token value loaded yet" app:layout_constraintTop_toBottomOf="@+id/last_action_label" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" /> <com.google.android.material.button.MaterialButton android:id="@+id/load_token_button" android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toBottomOf="@+id/last_action_text" android:layout_marginTop="40dp" android:textAllCaps="false" android:textSize="20sp" android:text="Load token"/> <com.google.android.material.button.MaterialButton android:id="@+id/store_token_button" android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toBottomOf="@+id/load_token_button" android:layout_marginTop="20dp" android:textAllCaps="false" android:textSize="20sp" android:text="Store token"/> <com.google.android.material.button.MaterialButton android:id="@+id/delete_token_button" android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toBottomOf="@+id/store_token_button" android:textAllCaps="false" android:layout_marginTop="20dp" android:textSize="20sp" android:text="Delete token"/> </androidx.constraintlayout.widget.ConstraintLayout> </layout>
内容的提问来源于stack exchange,提问作者Djuro Gluvajic
相关产品推荐
相关产品推荐

