android - 我的 Android 应用正在损坏 SD 卡

标签 android

我在 Android 市场上发布了一个应用程序,此后我不得不将其删除,因为大约一半的评论是人们提示 SD 卡损坏。我已经检查了几次代码,但找不到任何可能损坏 SD 卡的东西。所有涉及外部存储的事情都是将流保存为图像,然后将其读入 ImageView。

这就是在根 Activity 中创建文件夹所调用的内容。目录路径存储在公共(public)静态变量中。

//Get the SD Card directory
    String external = Environment.getExternalStorageDirectory().getAbsolutePath() + "/appfolder/";

    CACHE_DIRECTORY = external + ".cache/";
    SAVED_DIRECTORY = external + "saved/";

    File cache = new File(CACHE_DIRECTORY);
    File saved = new File(SAVED_DIRECTORY);
    cache.mkdirs();
    saved.mkdirs();

下面是下载图片并复制它们的代码(当它们被移动到保存的目录时)。

public static void saveImage(File file, URL url) throws IOException {
    BufferedInputStream bis = new BufferedInputStream(url.openStream());
    BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));
    int bytes;
    while ((bytes = bis.read()) != -1) {
        bos.write(bytes);
    }
    bos.close();
    bis.close();
}

public static void copy(File fileIn, File fileOut) throws IOException {
    BufferedInputStream bin = new BufferedInputStream(new FileInputStream(fileIn));
    BufferedOutputStream bout = new BufferedOutputStream(new FileOutputStream(fileOut));
    int bytes;
    while ((bytes = bin.read()) != -1) {
        bout.write(bytes);
    }
    bin.close();
    bout.close();
}

这是网络I/O的后台线程

public void run() {
    for (String url : thumbnails) {
        if (url != null) {
            String[] urlParts = url.split("/");
            String imageName = urlParts[urlParts.length - 1];
            File file = new File(Main.CACHE_DIRECTORY + imageName);
            if (!file.exists() || file.length() == 0) {
                try {
                    Image.saveImage(file, new URL(url));
                } catch (IOException e) {}
            }
        actx.runOnUiThread(reload);
        }
    }
}

其中 reload 是更新适配器的可运行对象,缩略图是字符串 url 数组,图像名称是具有图像扩展名(特别是 .jpeg、.png、.gif)的唯一 10-11 位数字。

这是在异步任务后台运行的类似代码。

String imageUrl = (String)params[0];
    String[] imageUrlParts = imageUrl.split("/");
    String imageName = imageUrlParts[imageUrlParts.length - 1];
    URL fullImageUrl;
    try {
        fullImageUrl = new URL(imageUrl);
    } catch (MalformedURLException me) {
        cancel(true);
        return null;
    }

    File file = new File(Main.CACHE_DIRECTORY + imageName);
    try {
        URLConnection ucon = fullImageUrl.openConnection();
        int requestedSize = ucon.getContentLength();
        long fileSize = file.length();
        //Either the file does not exist, or it exists but was cancelled early due to
        //User or IOException, so it needs to be redownloaded
        if (!file.exists() || ((file.exists()) && fileSize < (requestedSize * 0.8))) {
            mLoad.setMax(requestedSize);
            BufferedInputStream bis = new BufferedInputStream(ucon.getInputStream());
            BufferedOutputStream bout = new BufferedOutputStream(new FileOutputStream(file));
            int bytes;
            int count = 0;
            while ((bytes = bis.read()) != -1) {
                bout.write(bytes);
                count++;
                //Updates in increments of 2kb
                if (count % 2048 == 0) {
                    publishProgress(count);
                }
            }
            bis.close();
            bout.close();
        }

        if (save) {
            File saveFile = new File(Main.SAVED_DIRECTORY + imageName);
            copy(file, saveFile);
        }
    } catch (IOException e) {
        cancel(true);
        return null;
    } catch (OutOfMemoryError e) {
        cancel(true);
        return null;
    }

我能找到的唯一一个损坏的 SD 卡实例是 http://code.google.com/p/android/issues/detail?id=2500

该应用程序基于 Android 1.6 构建,无法通过模拟器或使用 HTC Desire 在 2.1update1 上进行个人测试来重现该错误。

编辑:我查看了其他一些问题,问题可能是由于我没有刷新缓冲输出流引起的吗?这有什么大不了的吗?

最佳答案

我看到两件事可能相关:

  • 您应该在 finally{ } block 中对流调用 .close(),以便在发生错误或写入时强制关闭时关闭它们。
  • 捕获 OutOfMemoryError 通常不是一个好主意。 VM 内存不足,很多事情将处于不可预测的糟糕状态,在这些情况下最好中止。

我打赌 finally block ,可能与 OutOfMemoryError 发生有关,并且由于 catch 而没有中止应用程序,导致一些进一步向下错误。

关于android - 我的 Android 应用正在损坏 SD 卡,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3289710/

相关文章:

带有PorterDuff.Mode.DST_IN的android drawBitmap,应该透明的区域变成黑色

android - 安全共享首选项android

android - 如何为我们的服务器生成信号开源 android 应用程序的自签名证书

android - Activity fragment

java - 设置布局背景时应用程序崩溃

android - Android EditText 的 getSelectionEnd() getSelectionStart() 不返回正确的值

Android 在新 Activity 中显示相机图像

android - 如何在Flutter中将.dart文件的变量获取到另一个.dart文件

android - 在 android 应用程序中单击按钮调用条码扫描器

android - 当方向改变时,Actionbar scherlock 不会刷新