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

AsyncTask执行loadVideos报initLoader需在主线程调用错误如何解决

问题根因

你遇到的报错核心原因是:调用的FileFilter.getFiles()方法内部依赖了LoaderManager.initLoader(),Android系统要求LoaderManager的初始化和相关操作必须在主线程执行,而你现在把loadVideos()放在AsyncTask的doInBackground()回调中执行,这个回调运行在后台工作线程,不符合API要求所以抛出异常。

解决方案

推荐采用逻辑拆分的方案,将Loader相关的调用移到主线程,耗时的文件遍历、数据组装、数据库操作保留在后台执行,既满足API调用要求,也不会阻塞主线程:

// 先在主线程调用FileFilter.getFiles,拿到文件目录结果
FileFilter.getFiles(this, directories -> {
    // 拿到结果后再启动AsyncTask执行耗时操作
    new LoadVideos(directories).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}, new String[]{".mp4",".ts",".mkv",".mov",
        ".3gp",".mv2",".m4v",".webm",".mpeg1",".mpeg2",".mts",".ogm",
        ".bup", ".dv",".flv",".m1v",".m2ts",".mpeg4",".vlc",".3g2",
        ".avi",".mpeg",".mpg",".wmv",".asf"});

// 改造LoadVideos类,构造函数传入获取到的目录列表
@SuppressLint("StaticFieldLeak")
private class LoadVideos extends AsyncTask<Void, Integer, Void> {
    private List<Directory<NormalFile>> directoryList;

    public LoadVideos(List<Directory<NormalFile>> directoryList) {
        this.directoryList = directoryList;
    }

    @Override
    protected void onPostExecute(Void aVoid) {
        super.onPostExecute(aVoid);
        startActivity(new Intent(SplashScreen.this, MainActivity.class));
    }

    @Override
    protected Void doInBackground(Void... voids) {
        // 把原来回调中的耗时逻辑移到后台线程执行
        for (Directory<NormalFile> directory : directoryList) {
            for (int i = 0; i < directory.getFiles().size(); i++) {
                File file = new File(directory.getFiles().get(i).getPath());
                Log.d(TAG, "onResult: " + file.getPath());
                FileStore fs = db.getFileByCustomPath(file.getAbsolutePath());
                AllVideoModel avm = new AllVideoModel();
                avm.setFileName(file.getName());
                avm.setVideoPath(file.getAbsolutePath());
                avm.setFolderName(Objects.requireNonNull(file.getParentFile()).getName());
                avm.setVideoSize(file.length());
                avm.setParentPath(file.getParent());
                StaticConstant.allMediaListWithModel.add(avm);
                StaticConstant.FABbeforeSort.add(avm);
                if (fs == null) {
                    // 数据库操作保留在后台执行
                    FileStore fsNew = new FileStore();
                    fsNew.setName(file.getName());
                    fsNew.setFilePath(file.getAbsolutePath());
                    fsNew.setParent(Objects.requireNonNull(file.getParentFile()).getName());
                    fsNew.setUpdatedAt(new Date());
                    fsNew.setParentPath(file.getParent());
                    db.insertOrUpdateFile(fsNew);
                }
            }
        }
        return null;
    }
}

如果你不想调整原有逻辑结构,也可以临时把FileFilter.getFiles()的调用切换到主线程执行,不过不推荐该方案,因为回调中的耗时操作如果在主线程执行会导致界面卡顿:

@Override
protected Void doInBackground(Void... voids) {
    // 切换到主线程执行依赖Loader的代码
    new Handler(Looper.getMainLooper()).post(() -> {
        loadVideos();
    });
    return null;
}
额外说明

AsyncTask已经在Android API 30中被正式废弃,后续维护时可以考虑使用ThreadPoolExecutor搭配Handler、WorkManager或者Kotlin协程实现异步任务,兼容性和可维护性更好。

内容的提问来源于stack exchange,提问作者sanoj lawrence

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 10:45:01