删除手机图片后保持图库不会出现黑图的方法。

本文探讨了手机应用中删除图片文件后,图库仍显示该位置图片的问题,通过查看Gallery源代码发现其通过SQLite数据库操作图片存储。提出通过发送无序广播通知系统重新扫描内存的方法,并分享在不同设备上的实现经验。最终,文章提到在Android 4.4中发送ACTION_MEDIA_MOUNTED广播可能会延迟,分析原因并尝试使用MediaScannerConnection进行文件扫描解决延迟问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >



最近写了个手机相册的应用,闲的无聊想增加些功能,本来以为删除应该很easy的,结果显示会出现问题。即虽然删除了图片文件但是图库中还是会出现那张图的位置只是是以黑色取代。于是我就很苦恼的追寻原因。我觉得是不是要通知contentprovide之前的图片已被删除。(因为我的图片是根据contentprovide得到的。)甚至觉得要不要通过contentResolver来删除才行。。。

后来我通过查看Gallery的源代码发现它的删除操作是通过SQLite数据库进行操作的,而且图片存储应该是id,和byte【】数组存储。也就解释了为啥删除源文件后图片仍然会显示了。

public class PhotoAppWidgetProvider extends AppWidgetProvider {
    private static final String TAG = "PhotoAppWidgetProvider";
    private static final boolean LOGD = true;

    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
        // Update each requested appWidgetId with its unique photo
        PhotoDatabaseHelper helper = new PhotoDatabaseHelper(context);
        for (int appWidgetId : appWidgetIds) {
            int[] specificAppWidget = new int[] { appWidgetId };
            RemoteViews views = buildUpdate(context, appWidgetId, helper);
            if (LOGD) {
                Log.d(TAG, "sending out views=" + views + " for id=" + appWidgetId);
            }
            appWidgetManager.updateAppWidget(specificAppWidget, views);
        }
        helper.close();
    }

    @Override
    public void onDeleted(Context context, int[] appWidgetIds) {
        // Clean deleted photos out of our database
        PhotoDatabaseHelper helper = new PhotoDatabaseHelper(context);
        for (int appWidgetId : appWidgetIds) {
            helper.deletePhoto(appWidgetId);
        }
        helper.close();
    }

    /**
     * Load photo for given widget and build {@link RemoteViews} for it.
     */
    static RemoteViews buildUpdate(Context context, int appWidgetId, PhotoDatabaseHelper helper) {
        RemoteViews views = null;
        Bitmap bitmap = helper.getPhoto(appWidgetId);
        if (bitmap != null) {
            views = new RemoteViews(context.getPackageName(), Res.layout.photo_frame);
            views.setImageViewBitmap(Res.id.photo, bitmap);
        }
        return views;
    }

    static class PhotoDatabaseHelper extends SQLiteOpenHelper {
        private static final String DATABASE_NAME = "launcher.db";

        private static final int DATABASE_VERSION = 2;

        static final String TABLE_PHOTOS = "photos";
        static final String FIELD_APPWIDGET_ID = "appWidgetId";
        static final String FIELD_PHOTO_BLOB = "photoBlob";

        PhotoDatabaseHelper(Context context) {
            super(context, DATABASE_NAME, null, DATABASE_VERSION);
        }

        @Override
        public void onCreate(SQLiteDatabase db) {
            db.execSQL("CREATE TABLE " + TABLE_PHOTOS + " (" + FIELD_APPWIDGET_ID + " INTEGER PRIMARY KEY," + FIELD_PHOTO_BLOB
                    + " BLOB" + ");");
        }

        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            int version = oldVersion;

            if (version != DATABASE_VERSION) {
                Log.w(TAG, "Destroying all old data.");
                db.execSQL("DROP TABLE IF EXISTS " + TABLE_PHOTOS);
                onCreate(db);
            }
        }

        /**
         * Store the given bitmap in this database for the given appWidgetId.
         */
        public boolean setPhoto(int appWidgetId, Bitmap bitmap) {
            boolean success = false;
            try {
                // Try go guesstimate how much space the icon will take when
                // serialized to avoid unnecessary allocations/copies during
                // the write.
                int size = bitmap.getWidth() * bitmap.getHeight() * 4;
                ByteArrayOutputStream out = new ByteArrayOutputStream(size);
                bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
                out.flush();
                out.close();

                ContentValues values = new ContentValues();
                values.put(PhotoDatabaseHelper.FIELD_APPWIDGET_ID, appWidgetId);
                values.put(PhotoDatabaseHelper.FIELD_PHOTO_BLOB, out.toByteArray());

                SQLiteDatabase db = getWritableDatabase();
                db.insertOrThrow(PhotoDatabaseHelper.TABLE_PHOTOS, null, values);

                success = true;
            } catch (SQLiteException e) {
                Log.e(TAG, "Could not open database", e);
            } catch (IOException e) {
                Log.e(TAG, "Could not serialize photo", e);
            }
            if (LOGD) {
                Log.d(TAG, "setPhoto success=" + success);
            }
            return success;
        }

        static final String[] PHOTOS_PROJECTION = { FIELD_PHOTO_BLOB, };

        static final int INDEX_PHOTO_BLOB = 0;

        /**
         * Inflate and return a bitmap for the given appWidgetId.
         */
        public Bitmap getPhoto(int appWidgetId) {
            Cursor c = null;
            Bitmap bitmap = null;
            try {
                SQLiteDatabase db = getReadableDatabase();
                String[] selectionArgs = { String.valueOf(appWidgetId) };
                c = db.query(TABLE_PHOTOS, PHOTOS_PROJECTION, FIELD_APPWIDGET_ID + "=?",
                        selectionArgs, null, null, null, null);

                if (c != null && LOGD) {
                    Log.d(TAG, "getPhoto query count=" + c.getCount());
                }

                if (c != null && c.moveToFirst()) {
                    byte[] data = c.getBlob(INDEX_PHOTO_BLOB);
                    if (data != null) {
                        bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
                    }
                }
            } catch (SQLiteException e) {
                Log.e(TAG, "Could not load photo from database", e);
            } finally {
                if (c != null) {
                    c.close();
                }
            }
            return bitmap;
        }

        /**
         * Remove any bitmap associated with the given appWidgetId.
         */
        public void deletePhoto(int appWidgetId) {
            try {
                SQLiteDatabase db = getWritableDatabase();
                String[] selectionArgs = { String.valueOf(appWidgetId) };
                db.delete(TABLE_PHOTOS, FIELD_APPWIDGET_ID + "=?", selectionArgs);
            } catch (SQLiteException e) {
                Log.e(TAG, "Could not delete photo from database", e);
            }
        }
    }

}

再后来在网上查到可以通过发送无序广播通知系统重新扫描内存。

  //发送 一个无序广播
     getActivity().sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://"
+ Environment.getExternalStorageDirectory())));

但是这个在虚拟机上面可以实现,在其他几款手机也能实现。但在小米手机上不知怎么会延迟一分钟左右后才能实现。偶然看到了:Android4.4中拒绝发送Intent.ACTION_MEDIA_MOUNTED扫描SD卡的广播 

http://blog.youkuaiyun.com/sgz_china/article/details/24657709

这篇文章,但是他提出的方案:
使用MediaScannerConnection执行具体文件或文件夹进行扫描。我尝试了。并没有解决,包括虚拟机上都不行。各位看到这篇文章的朋友如果解决了这个问题麻烦相告。

新手的进击之路!与君共勉。










评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值