异步任务状态机:PENDING、DOWNLOADING、INSTALLING、INSTALLED、FAILED、CANCELED

SplitInstall 模块下载与安装的过程是一个典型的有限状态机(FSM)。每个异步任务从创建到消亡,都会依次或跳转地经历一组互斥状态。客户端只有准确理解这六种状态的触发条件与切换路径,才能在回调中做出正确的 UI 更新与错误处理。

状态定义与切换规则

状态 含义 触发时机 可流转至
PENDING 任务已排队,等待系统调度 startInstall() 调用成功返回 DOWNLOADING, FAILED, CANCELED
DOWNLOADING 正在从 Google Play 下载安装包 系统开始传输数据 INSTALLING, FAILED, CANCELED
INSTALLING 下载完成,正在安装到应用沙箱 下载进度达到 100% INSTALLED, FAILED
INSTALLED 模块已就绪,可立即调用 安装流程完成 (终止态)
FAILED 因网络、存储、权限等原因终止 任何阶段发生不可恢复错误 (终止态)
CANCELED 用户或客户端主动取消 调用 cancelInstall() 或系统清理 (终止态)
注意:CANCELED 只在 PENDING 或 DOWNLOADING 阶段生效;进入 INSTALLING 后无法取消,只能等待 FAILED 或成功。

状态机流程图

SplitInstall 异步任务状态机 PENDING DOWNLOADING INSTALLING INSTALLED FAILED CANCELED 虚线箭头表示异常路径(失败或取消),实线箭头表示正常流转。

状态监听 API

客户端通过 SplitInstallStateUpdatedListener 接收状态变更。核心实现在 onStateUpdate() 回调中根据 sessionId 和 status 字段分发逻辑:

SplitInstallStateUpdatedListener listener = new SplitInstallStateUpdatedListener() {
    @Override
    public void onStateUpdate(SplitInstallSessionState state) {
        switch (state.status()) {
            case PENDING:
                // 显示排队提示
                break;
            case DOWNLOADING:
                long bytesDownloaded = state.bytesDownloaded();
                long totalBytes = state.totalBytesToDownload();
                updateProgressBar(bytesDownloaded, totalBytes);
                break;
            case INSTALLING:
                // 显示“安装中”状态,避免用户操作
                setInstallingUI(true);
                break;
            case INSTALLED:
                // 模块已就绪,可加载代码或资源
                loadSplit(state.moduleName());
                break;
            case FAILED:
                int errorCode = state.errorCode();
                handleError(errorCode);
                break;
            case CANCELED:
                // 用户取消或系统清理,重置 UI
                resetUI(state.moduleName());
                break;
        }
    }
};
关键校验: 状态回调可能在 任何线程 上触发。建议使用 Handler 或 LiveData 将 UI 更新切回主线程。

调试与日志

开发时可通过 Android Studio 的 Logcat 观察 SplitInstall 内部日志。启用详细日志:

adb shell setprop log.tag.SplitInstall VERBOSE
adb logcat -s SplitInstall D

日志常见模式:

  • Processing state: PENDING → DOWNLOADING —— 正常调度
  • Session [ID] canceled by user —— 收到 CANCELED
  • Error code -2 (NETWORK_ERROR) —— 导致 FAILED 的可能原因

常见错误与优化

陷阱: 在 INSTALLING 状态下调用 cancelInstall() 会被忽略。若用户想取消,应仅在 PENDING 或 DOWNLOADING 时取消,并立即清理对应 UI。
  • 状态丢失: 应用进程被杀后,未完成的 session 状态会丢失。建议在 onResume() 调用 getSessionStates() 恢复。
  • 重复注册监听器: registerListener() 应在 Application.onCreate() 或 BaseActivity 中一次注册,避免多次创建导致泄漏。
  • 性能建议: 不要在 onStateUpdate() 中执行耗时操作;若需要持久化状态,使用 WorkManager 异步写数据库。