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

Android中MediaStore无法获取新增照片的问题排查咨询

问题排查与修复方案

问题背景

我们的应用读取手机MediaStore中的照片,对含有人脸的照片做情绪分析。为避免每次启动全量扫描,只获取新增照片:首次启动扫描全部照片,后续启动仅查询上次扫描时间到当前时间的新增照片。但现在遇到问题:退出应用后新增照片,重新进入时无法获取这些新增照片,代码从未进入if (cursor.moveToFirst()) {}语句块。

核心问题定位

1. 时间戳来源不匹配,查询逻辑完全错误

你存储到SharedPreferences的lastPhotoDate是文件的本地修改时间(file.lastModified()),但查询MediaStore时用的是DATE_TAKEN字段——这两个时间戳根本不是一回事:

  • DATE_TAKEN是照片拍摄时的原始时间戳(来自照片EXIF,毫秒级)
  • file.lastModified()是文件被复制/下载到本地后的最后修改时间
    首次扫描后存储的是文件修改时间,后续用这个值和DATE_TAKEN做比较,相当于拿两个完全无关的时间做筛选,自然查不到新增照片。

2. 查询条件的边界限制过严

当前查询用DATE_TAKEN > ? and DATE_TAKEN < ?,如果新增照片的DATE_TAKEN刚好等于当前生成的timeStamp,会被直接排除,应该把<改成<=,覆盖所有在扫描时间段内的照片。

3. 首次扫描时的时间存储逻辑错误

首次扫描时,cursor是按DATE_TAKEN DESC排序的,你却取了第一条记录的文件修改时间存储,而不是这条记录的DATE_TAKEN值,直接导致后续查询的起始点错误。

修复代码

步骤1:统一时间戳来源,直接用MediaStore的DATE_TAKEN

不再使用文件修改时间,直接从cursor读取DATE_TAKEN字段的值来存储,同时修正查询条件和资源管理:

public static void listOfImages(Context context) {
    Uri uri;
    String ablosutePathOfImage;
    emotionDatabase = EmotionDatabase.getEmotionDatabase(context);

    Long currentTime = System.currentTimeMillis();
    String timeStamp = currentTime.toString();
    SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
    String lastPhotoDate = sharedPreferences.getString("last_photo_date", null);

    uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
    // 确保投影包含DATE_TAKEN字段
    String [] projection = {MediaStore.MediaColumns.DATA, MediaStore.Images.Media.DATE_TAKEN};
    String orderBy = MediaStore.Images.Media.DATE_TAKEN + " DESC";

    Cursor cursor = null;
    if(lastPhotoDate == null){
        cursor = context.getContentResolver().query(uri, projection, null, null, orderBy);
    } else {
        // 修正查询条件的边界,把<改成<=
        cursor = context.getContentResolver().query(uri, projection,
                MediaStore.Images.Media.DATE_TAKEN + ">? and " +
                MediaStore.Images.Media.DATE_TAKEN + "<=?",
                new String[] {lastPhotoDate , timeStamp},
                orderBy);
    }

    if(cursor == null) {
        return;
    }

    int column_index_data = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA);
    int column_index_date_taken = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATE_TAKEN);

    // 先判断cursor是否有数据,再处理
    if(cursor.moveToFirst()){
        // 直接读取第一条记录的DATE_TAKEN作为上次扫描的最后时间
        Long photoDate = cursor.getLong(column_index_date_taken);
        lastPhotoDate = photoDate.toString();
        SharedPreferences.Editor editor = sharedPreferences.edit();
        editor.putString("last_photo_date", lastPhotoDate);
        editor.apply();

        // 初始化FaceDetector放到循环外,提升性能
        FaceDetector faceDetector = new FaceDetector.Builder(context.getApplicationContext())
                .setTrackingEnabled(false)
                .setLandmarkType(FaceDetector.ALL_LANDMARKS)
                .setMode(FaceDetector.FAST_MODE)
                .build();

        do {
            ablosutePathOfImage = cursor.getString(column_index_data);
            final Bitmap myBitmap = BitmapFactory.decodeFile(ablosutePathOfImage);
            Frame frame = new Frame.Builder().setBitmap(myBitmap).build();
            SparseArray<Face> sparseArray = faceDetector.detect(frame);

            for (int i = 0; i < sparseArray.size(); i++) {
                Face face = sparseArray.valueAt(i);
                float x1 = face.getPosition().x;
                float y1 = face.getPosition().y;

                Bitmap faceBitmap = Bitmap.createBitmap(
                        myBitmap,
                        (int) x1,
                        (int) y1,
                        (int) face.getWidth(),
                        (int) face.getHeight());
                classifyEmotions(faceBitmap, context, ablosutePathOfImage);
            }
        } while (cursor.moveToNext());
    }
    // 记得关闭cursor,避免内存泄漏
    cursor.close();
}

步骤2:额外优化点

  • 把FaceDetector的初始化放到循环外面,避免重复创建实例浪费资源
  • 新增cursor空值判断,避免空指针异常
  • 最后关闭cursor,防止内存泄漏

验证方法

  1. 卸载重装应用,首次启动确认全量扫描正常
  2. 退出应用,新增几张照片(可以拍照或下载)
  3. 重新启动应用,检查是否能获取到这些新增照片并进行情绪分析

内容的提问来源于stack exchange,提问作者Barış Balcıkoca

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 18:17:57