【问题标题】:Why am I getting "Agent error" when trying to perform a backup?为什么我在尝试执行备份时收到“代理错误”?
【发布时间】:2021-07-29 21:13:00
【问题描述】:

我正在为我的 Android 应用实施备份系统。我正在使用自定义 BackupAgentHelper 来备份共享首选项和数据库文件:

class CustomAgent : BackupAgentHelper() {

    val DB_NAME = "notesDB"

    val DB_BACKUP_KEY = "dbBackup"
    val SHARED_PREFS_KEY = "prefsBackup"

    override fun onCreate() {
        super.onCreate()
        //Backup note's database file
        val dbHelper = FileBackupHelper(this, DB_NAME)
        addHelper(DB_BACKUP_KEY, dbHelper)

        //Backup SharedPreferences
        val prefHelper = SharedPreferencesBackupHelper(this)
        addHelper(SHARED_PREFS_KEY, prefHelper)
    }

    override fun onBackup(
        oldState: ParcelFileDescriptor?,
        data: BackupDataOutput?,
        newState: ParcelFileDescriptor?
    ) {
        super.onBackup(oldState, data, newState)
        Toast.makeText(this, "Performing backup...", Toast.LENGTH_SHORT).show()
    }

    override fun onRestore(
        data: BackupDataInput?,
        appVersionCode: Int,
        newState: ParcelFileDescriptor?
    ) {
        Toast.makeText(this, "Restoring...", Toast.LENGTH_SHORT).show()
        super.onRestore(data, appVersionCode, newState)
    }

    override fun onQuotaExceeded(backupDataBytes: Long, quotaBytes: Long) {
        Toast.makeText(this, "Failed backup: The size is too big.", Toast.LENGTH_SHORT).show()
        super.onQuotaExceeded(backupDataBytes, quotaBytes)
    }

    override fun getFilesDir(): File {
        val path = getDatabasePath(DB_NAME)
        return path.parentFile
    }
}

我想显示一条 Toast 消息,让用户知道备份正在运行,并在有任何问题时通知他们。但是,如果我使用 Toast 消息运行应用程序,并执行以下 adb 命令来请求备份...

adb -s emulator-5554 shell bmgr backupnow com.byteseb.grafobook

我得到这个输出:

为 1 个请求的包运行增量备份。

打包@pm@,结果:成功

使用结果打包 com.byteseb.grafobook:代理错误

备份完成,结果:成功

并且没有显示 Toast 消息。

但是如果我删除 Toast 消息行或用 println() 函数替换它们并执行相同的命令,我会得到以下输出:

为 1 个请求的包运行增量备份。

打包@pm@,结果:成功

使用结果打包 com.byteseb.grafobook:成功

备份完成,结果:成功

为什么会发生这个错误?如果不允许我显示 Toast,我还能做些什么来通知用户有关备份的信息?

【问题讨论】:

  • "为什么会出现这个错误?" – 您不能从非 UI 线程中显示 Toasts,因此这可能会引发异常。 “...我还能做些什么来通知用户有关备份的信息?” – 您可能不想直接从您的BackupAgentHelper 触发任何 UI 通知,因为您永远不知道系统何时会自行运行它。就个人而言,我只会在SharedPreferences 中跟踪上次备份时间,例如,将当前时间保存在onBackup() 的末尾。如果您想实时更新备份请求,可以设置OnSharedPreferenceChangeListener
  • @MikeM 你认为使用 BroadcastReceiver 是个好主意吗?
  • 实时更新的东西?这可以工作,但很少需要在同一个应用程序中进行广播,通常也不再推荐它。曾经有一个专门的支持库类——LocalBroadcastManager——但这早已被弃用,取而代之的是ViewModels 和观察者等。如果你想做一个ViewModel-type 设置,你基本上可以告诉 UI 任何你想要从你的备份代理那里得到的东西,但是这需要更多的设置。
  • 如果您打算直接从帮助程序中显示一些 UI 通知,您可以考虑使用Notifications。只是一个建议。
  • @MikeM。是的,谢谢。我确实最终使用了通知,但我在答案中使用了 Toasts,因为问题使用了它们:)

标签: android kotlin


【解决方案1】:

正如@MikeM 所说,发生这种情况是因为我正在从非 UI 线程执行代码。

我通过使用处理程序解决了这个问题,这个处理程序负责从 UI 线程运行代码:

override fun onBackup(
    oldState: ParcelFileDescriptor?,
    data: BackupDataOutput?,
    newState: ParcelFileDescriptor?
) {
    super.onBackup(oldState, data, newState)
    val handler = Handler(Looper.getMainLooper())
    val runnable = Runnable {
        Toast.makeText(this, "Performing backup...", Toast.LENGTH_SHORT).show()
    }
    handler.post(runnable)
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-25
    • 2012-05-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多