2010-07-20 68 views
6

我在Android市场发布了一个应用程序,之后我不得不取消,因为大约有一半的评论是人们抱怨损坏的SD卡。我已经翻了几遍代码,找不到可能会损坏SD卡的任何东西。所有涉及外部存储的事情都是将流保存为图像,然后将其读入ImageView。我的Android应用程序正在破坏SD卡

这是在根活动中称为创建文件夹的内容。目录路径存储在公共静态变量中。

//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); 
     } 
    } 
} 

凡重载是可运行的更新适配器,缩略图是字符串URL的数组和形象的名字是一个独特的10具有图像扩展名(.jpeg,.png,.gif)的11位数字。

这是在asynctask的背景下运行的类似代码。

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。

编辑:我已经看了一些其他问题,并可能产生的问题不是我冲洗缓冲输出流?这是一件大事吗?

+0

你是什么损坏SDcards是什么意思?究竟发生了什么? – Macarse 2010-07-20 12:23:15

+0

用户在安装时收到“损坏的SD卡”消息,并且必须对其进行格式化才能使其再次正常工作。 – daniel 2010-07-20 12:29:16

+0

哦!危险代码:|呵呵! – Jorgesys 2010-07-20 15:12:20

回答

2

我看到可能与两件事情:

  • 你应该在finally{ }块中呼吁流.close()所以他们在结案有错误或强制关闭,而写。
  • 捕捉OutOfMemoryError通常不是一个好主意。 VM已经耗尽内存,许多事情将处于不可预知的状态,最好在这些情况下放弃。

我的赌注是finally块,可能与一个OutOfMemoryError发生,而不是中止应用由于catch,导致一些错误进一步向下。

+0

谢谢。我将实施这些更改并将其重新上传到较小的市场,并查看是否出现相同的问题。 – daniel 2010-07-22 00:50:57

0

我假设你说的是文件系统损坏,而不是SD卡的硬件损坏。 Android应用程序在沙盒中运行,所以我认为应用程序会(几乎)不可能破坏文件系统。

也许这是一个安卓特定的错误,它是由你的代码正在做的事情触发的。我不得不同意复制字节是不好的做法。您应该尝试复制512或1024字节的块。

而且我会用内部存储。tmp文件: Android Storage Options