我在Android市场上发布了一个应用程序,因为大约一半的评论都是抱怨SD卡损坏的人。我已经查了几次代码,找不到任何可能损坏SD卡的东西。所有涉及外部存储的事情都是将流保存为图像,然后将其读入ImageView。
这是在根活动中调用以创建文件夹的内容。目录路径存储在公共静态变量中。
//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是可以更新适配器的runoable,则缩略图是一个字符串URL数组,图像名称是一个唯一的10-11位数字,带有图像扩展名(.jpeg,.png,.gif)。
这是在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 :(得分:2)
我看到两件可能相关的事情:
.close()
块内的流上调用finally{ }
,以便在写入时出现错误或强制关闭时关闭它们。OutOfMemoryError
通常不是一个好主意。虚拟机内存不足,很多东西都处于不可预测的状态,最好在这些情况下中止。我的赌注是finally
阻止,可能与OutOfMemoryError
发生有关,并且由于catch
而没有中止该应用,导致某些错误进一步缩小。
答案 1 :(得分:0)
我假设你在谈论文件系统损坏而不是SD卡的硬件损坏。 Android应用程序在沙箱中运行,所以我认为应用程序(几乎)不可能破坏文件系统。
这可能是一个特定于Android的错误,它是由您的代码正在执行的操作触发的。
我必须同意复制字节是不好的做法。您应该尝试复制512或1024字节的块。
另外我会为tmp文件使用内部存储: Android Storage Options