最近写了个手机相册的应用,闲的无聊想增加些功能,本来以为删除应该很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执行具体文件或文件夹进行扫描。我尝试了。并没有解决,包括虚拟机上都不行。各位看到这篇文章的朋友如果解决了这个问题麻烦相告。
新手的进击之路!与君共勉。