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

Android中AsyncTask结合Firebase上传SMS时进度显示异常问题

问题根源分析

你遇到的核心问题是:Firebase的setValue()是异步操作——你的doInBackground方法只是快速把所有上传请求发送给了Firebase服务器,但并没有等待请求真正完成,就立刻执行了i++和publishProgress(i)。这就导致进度条瞬间走完,但Firebase后台还在逐个处理这些异步请求,所以控制台里的消息会慢慢出现。

解决方案:等待每个上传任务完成后再更新进度

要获取真实的上传进度,我们需要确保只有当Firebase确认某个消息上传成功后,才更新进度计数。下面是基于你的代码修改后的实现:

步骤1:先把所有消息数据读取到本地列表

先在主线程把游标里的所有消息数据读取到一个列表中,避免在后台线程操作游标引发线程安全问题:

// 定义一个数据类保存消息字段
private static class MessageData {
    long id;
    String type;
    String message;
    String formattedTime;
    long timestamp;

    public MessageData(long id, String type, String message, String formattedTime, long timestamp) {
        this.id = id;
        this.type = type;
        this.message = message;
        this.formattedTime = formattedTime;
        this.timestamp = timestamp;
    }
}

// 读取所有消息到列表
List<MessageData> messageList = new ArrayList<>();
while (cur.moveToNext()) {
    long _id = cur.getLong(cur.getColumnIndex("_id"));
    String type = cur.getString(cur.getColumnIndex("type"));
    String body = cur.getString(cur.getColumnIndex("body"));
    long timestamp = cur.getLong(cur.getColumnIndex("date"));
    String formattedTime = dateFormat.format(timestamp);
    messageList.add(new MessageData(_id, type, body, formattedTime, timestamp));
}
cur.close();
totalMsgs = messageList.size();

步骤2:修改AsyncTask,等待每个上传任务完成

使用CountDownLatch让后台线程等待当前消息的上传请求完成后,再处理下一个消息,确保进度更新的时机是真实的上传完成时刻:

private class UploadConversations extends AsyncTask<Void, Integer, Integer> {
    private List<MessageData> mMessageList;
    private DatabaseReference mRootRef;

    public UploadConversations(List<MessageData> messageList) {
        mMessageList = messageList;
        mRootRef = FirebaseDatabase.getInstance().getReference();
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        mBuilder.setProgress(totalMsgs, 0, false);
        mNotifyManager.notify(id, mBuilder.build());
    }

    @Override
    protected Integer doInBackground(Void... params) {
        int uploadedCount = 0;
        for (MessageData msg : mMessageList) {
            // 处理任务取消情况
            if (isCancelled()) break;

            CountDownLatch uploadLatch = new CountDownLatch(1);
            String msgID = String.valueOf(msg.id);
            DatabaseReference msgRef = mRootRef.child("Chats").child(userID).child(thread_id).child(msgID);

            // 用Map批量设置字段,减少网络请求次数
            Map<String, Object> msgMap = new HashMap<>();
            msgMap.put("_id", msg.id);
            msgMap.put("type", msg.type);
            msgMap.put("message", msg.message);
            msgMap.put("time", msg.formattedTime);
            msgMap.put("time_stamp", msg.timestamp);

            // 上传并监听完成状态
            msgRef.setValue(msgMap)
                .addOnCompleteListener(task -> {
                    if (task.isSuccessful()) {
                        uploadedCount++;
                        publishProgress(uploadedCount);
                    } else {
                        Log.e(LOGTAG, "上传消息失败:" + msg.id, task.getException());
                    }
                    // 不管成功失败,都释放锁,继续下一个消息
                    uploadLatch.countDown();
                });

            try {
                // 等待当前上传任务完成
                uploadLatch.await();
            } catch (InterruptedException e) {
                Log.e(LOGTAG, "上传被中断", e);
                Thread.currentThread().interrupt();
                break;
            }
        }
        return uploadedCount;
    }

    @Override
    protected void onProgressUpdate(Integer... values) {
        super.onProgressUpdate(values);
        mBuilder.setProgress(totalMsgs, values[0], false);
        mNotifyManager.notify(id, mBuilder.build());
    }

    @Override
    protected void onPostExecute(Integer result) {
        super.onPostExecute(result);
        mBuilder.setContentTitle("上传完成");
        mBuilder.setContentText("已备份 " + result + "/" + totalMsgs + " 条消息");
        mBuilder.setProgress(0, 0, false);
        mNotifyManager.notify(id, mBuilder.build());
        mNotifyManager.cancel(id);
        Toast.makeText(getApplicationContext(), "备份完成:共上传" + result + "条消息", Toast.LENGTH_LONG).show();
    }

    @Override
    protected void onCancelled() {
        super.onCancelled();
        mBuilder.setContentTitle("上传取消");
        mBuilder.setContentText("备份已停止");
        mBuilder.setProgress(0, 0, false);
        mNotifyManager.notify(id, mBuilder.build());
        mNotifyManager.cancel(id);
        Toast.makeText(getApplicationContext(), "备份已取消", Toast.LENGTH_LONG).show();
    }
}

步骤3:启动AsyncTask

new UploadConversations(messageList).execute();
额外优化建议
  1. 分批次并行上传:如果消息数量很大,串行上传会比较慢,可以考虑每次同时上传3-5条消息,等这一批全部完成后再更新进度,既保证进度准确,又提升上传速度。
  2. 替换AsyncTask:AsyncTask已经在Android 11被废弃,建议改用Coroutines(协程)或WorkManager来处理这类后台任务,它们的生命周期管理和线程调度更可靠。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 08:14:44