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

Android启动页需完成Firebase同步后再启动主页面求助

问题分析

你遇到的核心问题是Firebase的异步操作和AsyncTask的执行逻辑冲突:

  • 你在AsyncTask的doInBackground里添加了addValueEventListener,但Firebase的数据库回调(onDataChange)和存储下载(getFile的OnSuccessListener)都是异步执行的。
  • doInBackground会在添加监听器后立刻返回null,直接触发onPostExecute跳转到MainActivity,这时候数据库同步和音频下载其实还在后台跑,所以MainActivity启动时本地数据库没有数据。

另外,addValueEventListener会持续监听数据变化,而你只需要启动时同步一次,改用addListenerForSingleValueEvent更合适,避免不必要的实时监听。

解决方案

我们需要跟踪所有同步和下载任务的完成状态,等所有操作都结束后再启动MainActivity。具体步骤如下:

1. 移除AsyncTask,直接在SplashScreen中处理Firebase操作

Firebase本身就是异步设计,不需要额外用AsyncTask包裹,反而会导致逻辑混乱。

2. 使用addListenerForSingleValueEvent替代addValueEventListener

只在启动时同步一次数据,避免持续监听浪费资源。

3. 跟踪所有音频下载任务的完成情况

用一个计数器记录需要下载的音频数量,每完成一个下载就递减计数器,当计数器归0时,再启动MainActivity。

修改后的完整代码

public class SplashScreen extends Activity {
    private DatabaseHandler db;
    private int pendingDownloads = 0; // 跟踪待完成的下载任务数

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_splash);

        // 创建存储文件夹
        File folder = new File(Environment.getExternalStorageDirectory() + "/" + getString(R.string.folder_name));
        if (!folder.exists()) {
            folder.mkdirs();
        }

        db = new DatabaseHandler(this);
        startFirebaseSync();
    }

    private void startFirebaseSync() {
        FirebaseDatabase database = FirebaseDatabase.getInstance();
        DatabaseReference dbRef = database.getReference("categorie");

        // 单次监听数据变化,同步完成后自动取消监听
        dbRef.addListenerForSingleValueEvent(new ValueEventListener() {
            @Override
            public void onDataChange(DataSnapshot dataSnapshot) {
                try {
                    List<String> listCat = db.getAllCategoriesId();
                    List<String> listSounds = db.getAllSoundsId();
                    Gson gson = new Gson();
                    JSONArray jsonArray = new JSONArray(gson.toJson(dataSnapshot.getValue()));

                    // 先同步分类数据
                    for (int i = 0; i < jsonArray.length(); i++) {
                        JSONObject cat = jsonArray.getJSONObject(i);
                        String nom = cat.getString("nom");
                        String id = cat.getString("id");
                        if (!listCat.contains(id)) {
                            db.addCategorie(nom, id);
                        }

                        // 处理音频数据,统计需要下载的数量
                        JSONArray sounds = cat.getJSONArray("son");
                        for (int j = 0; j < sounds.length(); j++) {
                            JSONObject sound = sounds.getJSONObject(j);
                            String soundId = sound.getString("id");
                            if (!listSounds.contains(soundId)) {
                                pendingDownloads++; // 需要下载,计数器+1
                                downloadAudioAndUpdateDb(sound, id);
                            }
                        }
                    }

                    // 如果没有需要下载的音频,直接跳转
                    if (pendingDownloads == 0) {
                        navigateToMainActivity();
                    }

                } catch (JSONException e) {
                    e.printStackTrace();
                    // 同步过程出错,也跳转(可以根据需求添加错误提示)
                    navigateToMainActivity();
                }
            }

            @Override
            public void onCancelled(DatabaseError databaseError) {
                databaseError.toException().printStackTrace();
                // 数据库访问失败,跳转
                navigateToMainActivity();
            }
        });
    }

    private void downloadAudioAndUpdateDb(JSONObject sound, String categoryId) {
        try {
            String soundId = sound.getString("id");
            String soundName = sound.getString("nom");
            String soundLien = sound.getString("lien");

            FirebaseStorage storage = FirebaseStorage.getInstance();
            StorageReference storageRef = storage.getReferenceFromUrl("gs://soundbox-a6dd8.appspot.com");
            StorageReference audioRef = storageRef.child(soundLien + ".mp3");

            File rootPath = new File(Environment.getExternalStorageDirectory(), getString(R.string.folder_name));
            if (!rootPath.exists()) {
                rootPath.mkdirs();
            }
            final File localFile = new File(rootPath, soundLien + ".mp3");

            audioRef.getFile(localFile)
                    .addOnSuccessListener(taskSnapshot -> {
                        Log.e("firebase", ";local temp file created: " + localFile.toString());
                        // 下载成功,更新本地数据库
                        db.addSound(soundId, soundName, soundLien, categoryId);
                        // 计数器递减,检查是否所有任务完成
                        pendingDownloads--;
                        checkIfAllTasksDone();
                    })
                    .addOnFailureListener(exception -> {
                        Log.e("firebase", ";local temp file not created: " + exception.toString());
                        // 下载失败,计数器也要递减(避免卡住跳转)
                        pendingDownloads--;
                        checkIfAllTasksDone();
                    });
        } catch (JSONException e) {
            e.printStackTrace();
            pendingDownloads--;
            checkIfAllTasksDone();
        }
    }

    private void checkIfAllTasksDone() {
        if (pendingDownloads == 0) {
            // 所有同步和下载任务完成,跳转MainActivity
            navigateToMainActivity();
        }
    }

    private void navigateToMainActivity() {
        Intent i = new Intent(SplashScreen.this, MainActivity.class);
        startActivity(i);
        finish();
    }
}

关键改进点说明

  • 移除AsyncTask:直接利用Firebase的异步回调处理逻辑,避免线程嵌套导致的时序问题。
  • 单次数据监听:addListenerForSingleValueEvent只触发一次数据同步,完成后自动解绑监听器,减少资源消耗。
  • 下载任务计数:用pendingDownloads跟踪所有需要下载的音频,确保所有下载(无论成功失败)都完成后才跳转,避免MainActivity启动时数据不完整。
  • 错误处理:在同步或下载出错时,依然保证能跳转到MainActivity,避免应用卡在启动页。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 06:56:46