防止重复图像保存到SD卡

4
我有一个包含多行的ListActivity应用程序。每一行都会打开一个活动,其中包含视图,其中之一是一个按钮,当点击时会打开无限画廊类(图像存储在应用程序内的RES => drawable文件夹中),每个图像下面都有一个按钮,当按下它时,它将图像保存到名为(saved_images)的文件夹中的SD卡目录中。
我在画廊类中使用SharedPreferences按顺序存储所有图像,这很好用,但我正试图:
1. 防止重复保存在SD卡文件夹(saved_images)中的图像: 假设您成功保存了图像-1,然后再次按下图像-1下面的相同按钮,它将再次保存在SD卡文件夹中,因此最终您将拥有相同的图像(图像-1)两次, 所以我想要的是:当我按下已经保存的图像下面的按钮时,会弹出“图像已保存”的Toast,因此所有应用程序图像都将保存一次在Sd卡文件夹中。
2. 在重新安装后按顺序继续保存图像: 在设备中安装应用程序并将一些图像保存在已在SD卡中创建的文件夹(saved_images)中后,假设您从设备中卸载应用程序并保留SD卡中的(saved_images)文件夹,则再次安装应用程序并想要保存一些新图像,会发生的是新图像将替换先前保存的图像, 但我希望它能够:继续按顺序保存新图像和以前保存的图像。
用于将图像保存到SD卡的代码:
public void onClick(View arg0) {
    String root = Environment.getExternalStorageDirectory().toString();
    File myDir = new File(root + "/saved_images");
    if (!myDir.exists()) {
        myDir.mkdirs();
        SharedPreferences saveNumber = mContext.getApplicationContext()
                .getSharedPreferences(PREFS_NAME, 0);
        SharedPreferences.Editor editorset = saveNumber.edit();
        editorset.putInt("lastsavednumber", 0);
        editorset.commit();
    }
    bm = BitmapFactory.decodeResource(mContext.getResources(),
            images[itemPos]);
    holder.image.setImageBitmap(bm);

    SharedPreferences savedNumber = mContext.getSharedPreferences(
            PREFS_NAME, 0);
    int lastSavedNumber = savedNumber.getInt("lastsavednumber", 0);
    lastSavedNumber++;
    String fname = "Image-" + lastSavedNumber + ".png";
    File file = new File(myDir, fname);
    if (file.exists()) {
        file.delete();
    }
    try {
        FileOutputStream out = new FileOutputStream(file);
        bm.compress(Bitmap.CompressFormat.PNG, 100, out);
        out.flush();
        out.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
    SharedPreferences saveNumber = mContext.getApplicationContext()
            .getSharedPreferences(PREFS_NAME, 0);
    SharedPreferences.Editor editorset = saveNumber.edit();
    editorset.putInt("lastsavednumber", lastSavedNumber);
    editorset.commit();
    Toast.makeText(mContext, "Saved", Toast.LENGTH_SHORT).show();
    vi.setTag(holder);
}

在处理点击的函数中 - 将按钮设置为禁用,然后 Thread.sleep 1000,最后在函数结束时重新启用按钮。对于双重保存的图像 - 尝试在文件夹中搜索最新保存的图像,然后从该编号继续序列。 - g00dy
你想让用户不要保存两次图片 - 如果用户关闭应用程序然后重新打开它 - 那么他是否应该能够保存两次图片呢? - Mr_and_Mrs_D
@Mr_and_Mrs_D 如果用户关闭了我的应用程序然后重新打开它,他也不能再次保存图像,因为文件夹仍然存在于SD卡中,但如果他手动删除文件夹(saved_images),那么该文件夹会在再次打开或重新安装应用程序时创建,所以现在他可以保存任何图像。 - androidqq6
我能想到的唯一方法是保留照片的CRC和目录的修改日期,每当保存文件时检查其CRC - 但这样会不会太耗费资源? - Mr_and_Mrs_D
@Mr_and_Mrs_D,请问您所说的CRC是什么意思?我认为使用(onSaveInstanceState)会有帮助,但不确定。我想我需要为所有图像创建保存/未保存状态的数据库,这样做对吗?谢谢。 - androidqq6
2个回答

1
你可以在保存图像时检查图像是否已存在。如果使用不同名称保存图像,则将图像矩阵与已保存图像的矩阵进行比较,如果它匹配任何图像矩阵,则显示 Toast 消息。
其次,如果文件夹已经存在,则不要删除它。当你重新安装应用程序时,文件夹的内容仍然存在。
尝试此代码以检查图像是否相同,我从 SO 回答中获得了此代码。
bool imagesAreEqual(Image i1, Image i2)
{

    if (i1.getHeight() != i2.getHeight) return false;
    if (i1.getWidth() != i2.getWidth) return false;

    for (int y = 0; y < i1.getHeight(); ++y)
       for (int x = 0; x < i1.getWidth(); ++x)
            if (i1.getPixel(x, y) != i2.getPixel(x, y)) return false;

    return true;
}

关于文件夹问题 在您的代码中,如果文件夹存在,则未删除文件夹。


1
要从文件夹中获取最后一个文件名,可以执行以下操作:
String directory = "/parent/of/saved_images/";
File savedImagesDir = new File(directory, "saved_images");
if (savedImagesDir.mkdirs() && savedImagesDir.isDirectory()) {
    // you just created the dir
} else {
    File[] files = savedImagesDir.listFiles();
    if (files == null) {
        // oops savedImagesDir is not a directory
    } else {
        int max = -1;
        Pattern p = Pattern.compile("-[\\d]+");
        for (File file : files) {
            Log.w("file", file.getName());
            Matcher matcher = p.matcher(file.getName());
            if (matcher.find()) {
                final String group = matcher.group();
                final String[] split = group.split("-");
                Log.w("group", file.getName());
                Log.w("split", split[1]);
                int curent = Integer.parseInt(split[1]);
                Log.w("curent", curent + "");
                if (curent > max) max = curent;
            }
        }
        Log.w("max", max + "");
        SharedPreferences saveNumber = mContext.getApplicationContext()
                    .getSharedPreferences(PREFS_NAME, 0);
        SharedPreferences.Editor editorset = saveNumber.edit();
        editorset.putInt("lastsavednumber", 0);
        editorset.commit();
    }
}

你需要在卸载后第一次运行活动时执行此操作。当然,我使用的正则表达式可能会失败,如果用户在那里放置了东西或者您更改了命名方案等。你必须小心谨慎。
至于“不再保存”,你应该(在共享首选项中)存储已保存图像的 saved_images 的校验和(哈希)。每当你尝试将文件放入其中时,计算其哈希值,如果已经存储了哈希,则显示 toast(“图像已保存”),否则将其放入其中。
要开始使用java哈希,请查看herehere

谢谢您的回答,但我是Android开发新手,无法理解第二点。如果您能将其翻译成代码,我将不胜感激。具体来说,“不再保存”的问题应该在“saved_images”中存储照片的校验和(哈希)。每当您尝试将文件放入其中时,请计算其哈希值,如果已经存储了哈希值,则显示您的提示信息(“图像已保存”),否则将其放入其中。 - androidqq6
@androidqq6 谷歌搜索“java md5”-这不是Android开发,而是通用编程-哈希(如md5)是一个小的字符串,可以唯一地标识文件-请检查我提供的链接-我会在找到时间时尝试编写一些东西-我发布的代码是否解决了其他问题? - Mr_and_Mrs_D
卸载并重新安装应用程序后,只需保存第一张图像,然后替换文件夹中的旧第一张图像,但是其他图像将继续保存在文件夹中(第一张图像的保存仍然存在问题)。 - androidqq6
卸载并重新安装应用程序后,仅保存第一张图像以替换文件夹中的旧第一张图像,但其余图像仍将继续保存在文件夹中(第一张图像保存仍然是问题),这是在运行Gingerbread的设备上,但在Ice Cream中,假设您第一次保存了3张图像,然后卸载应用程序,再次安装应用程序,然后想要保存第一张图像直到第三张图像,烤面包机会提示已保存,但进入文件夹后,您将看到先前图像的缩略图,但打开图像时它会打开新保存的图像,然后第四张图像正常保存。 - androidqq6
同时,运行冰淇淋的设备发生的情况也会发生在运行果冻豆的设备上。 - androidqq6

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接