2010-07-20 40 views
6

Tôi đã phát hành một ứng dụng trên thị trường Android mà tôi đã phải gỡ xuống vì khoảng một nửa số nhận xét là những người phàn nàn về thẻ SD bị hỏng. Tôi đã đi qua mã một vài lần và không thể tìm thấy bất cứ điều gì có thể làm hỏng một thẻ SD. Tất cả những gì xảy ra liên quan đến lưu trữ bên ngoài là việc lưu các luồng dưới dạng hình ảnh, sau đó được đọc vào trong ImageView.Ứng dụng Android của tôi đang làm hỏng Thẻ SD

Đây là những gì được gọi trong hoạt động gốc để tạo thư mục. Các đường dẫn thư mục được lưu trữ trong các biến tĩnh công cộng.

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

Và sau đây là mã để tải xuống hình ảnh và sao chép chúng (khi chúng được chuyển đến thư mục đã lưu).

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

Và đây là một sợi nền cho mạng 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); 
     } 
    } 
} 

đâu tải lại là một Runnable để cập nhật một bộ chuyển đổi, hình thu nhỏ là một mảng của các url chuỗi và tên hình ảnh là một độc đáo 10 Số có 11 chữ số có đuôi hình ảnh (.jpeg, .png, .gif cụ thể).

Và đây là mã chạy tương tự trong nền của một 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; 
    } 

Trường hợp duy nhất tôi có thể tìm thẻ SD bị hư hỏng là http://code.google.com/p/android/issues/detail?id=2500

Ứng dụng này được xây dựng trên Android 1.6 và các lỗi không recreatable qua giả lập hoặc thử nghiệm cá nhân trên 2.1update1 với HTC Desire.

EDIT: Tôi đã xem xét một số câu hỏi khác và các vấn đề có thể phát sinh từ tôi không xả các luồng đầu ra được lưu vào bộ đệm không? Đó có phải là một vấn đề lớn không?

+0

Ý anh là gì bởi SDcards hư hỏng? Chính xác thì điều gì xảy ra? – Macarse

+0

Trường hợp người dùng nhận được thông báo "Thẻ SD bị hỏng" khi nó đang được gắn kết và họ phải định dạng nó để làm cho nó hoạt động trở lại. – daniel

+0

ohhh! Mã nguy hiểm: | hehe! – Jorgesys

Trả lời

2

tôi thấy hai điều mà có thể liên quan:

  • Bạn nên gọi .close() trên suối trong một khối finally{ } vì vậy họ đều đóng cửa trong trường hợp có lỗi hoặc buộc chặt chẽ trong khi viết.
  • Bắt OutOfMemoryError thường không phải là một ý tưởng hay. VM đã hết bộ nhớ và rất nhiều thứ sẽ ở trạng thái không thể đoán trước được, tốt nhất là hủy bỏ trong những trường hợp đó.

đặt cược của tôi là trên finally khối, có thể liên quan đến một OutOfMemoryError xảy ra và không hủy ứng dụng do catch, gây ra một số lỗi tiếp tục xuống.

+0

Cảm ơn. Tôi sẽ thực hiện các thay đổi và tải lại nó lên một thị trường nhỏ hơn và xem liệu các vấn đề tương tự có nảy sinh hay không. – daniel

0

Tôi cho rằng bạn đang nói về tham nhũng hệ thống tập tin chứ không phải hỏng phần cứng của thẻ SD. Các ứng dụng Android chạy trong hộp cát nên tôi cho rằng ứng dụng sẽ không thể phá hủy hệ thống tệp (gần như).

Có lẽ đây là lỗi cụ thể của Android được kích hoạt bởi mã mà bạn đang thực hiện.

Tôi phải đồng ý rằng việc sao chép byte là thực hành không tốt. Bạn nên thử sao chép các khối 512 hoặc 1024 byte để thay thế.

Ngoài ra tôi sẽ sử dụng lưu trữ nội bộ cho các tập tin tmp: Android Storage Options

Các vấn đề liên quan