Android 重新启动会损坏使用FileChannel.map()写入Galaxy S4外部存储器的文件

Android 重新启动会损坏使用FileChannel.map()写入Galaxy S4外部存储器的文件,android,storage,mmap,galaxy,leveldb,Android,Storage,Mmap,Galaxy,Leveldb,我有以下问题: 我们的Android应用程序使用LevelDB将文件写入设备的外部存储器。LevelDB内部使用mmap进行写入。到目前为止,我们的问题只发生在三星Galaxy S4上。文件在存储器中的写入和读取没有任何问题。但在重新启动设备后,文件已损坏 有没有人经历过类似的事情 我编写了一个小的演示应用程序来检查mmap是否是问题所在,事实上似乎是。演示应用程序显示应用程序附带的图像以及图像下方的按钮。 如果按下按钮 使用FileChannel.map()将映像写入外部存储器(相当于mma

我有以下问题:

我们的Android应用程序使用LevelDB将文件写入设备的外部存储器。LevelDB内部使用
mmap
进行写入。到目前为止,我们的问题只发生在三星Galaxy S4上。文件在存储器中的写入和读取没有任何问题。但在重新启动设备后,文件已损坏

有没有人经历过类似的事情

我编写了一个小的演示应用程序来检查
mmap
是否是问题所在,事实上似乎是。演示应用程序显示应用程序附带的图像以及图像下方的按钮。
如果按下按钮

  • 使用
    FileChannel.map()
    将映像写入外部存储器(相当于
    mmap
  • 图像从外部存储器读取并显示在按钮下方
按下按钮一次并将图像写入外部存储器后,应用程序将显示图像的两个副本。即使在重新启动应用程序后,此功能仍能正常工作。但是,在Galaxy S4重新启动后,外部存储器上的文件已损坏,仅显示第一张图像

注意:当使用
FileOutputStream
写入文件时,此问题不会发生,并且仅在Galaxy S4上发生

如果有人知道如何使用LevelDB规避这个问题,那就太好了。
为了让您更容易重现问题,以下是演示应用程序的一些代码:

main.xml


StartActivity.java

package net.skoobe.StorageWrite;
导入android.app.Activity;
导入android.graphics.Bitmap;
导入android.graphics.drawable.BitmapDrawable;
导入android.graphics.drawable.drawable;
导入android.os.Bundle;
导入android.os.Environment;
导入android.util.Log;
导入android.view.view;
导入android.widget.ImageView;
导入java.io.*;
导入java.nio.ByteBuffer;
导入java.nio.channels.FileChannel;
公共类StartActivity扩展活动{
@凌驾
创建时的公共void(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
检索图像();
}
公共无效写入文件(视图v){
String state=Environment.getExternalStorageState();
if(环境、介质、安装等于(状态)){
//我们可以读写媒体
试一试{
//将资源转换为位图
BitmapDrawable bm=((BitmapDrawable)getResources().getDrawable(R.drawable.test_image));
位图b=bm.getBitmap();
//在字节数组中存储位图数据
ByteArrayOutputStream bos=新建ByteArrayOutputStream();
b、 压缩(Bitmap.CompressFormat.PNG,0/*对于PNG*/,bos被忽略);
字节[]位图数据=bos.toByteArray();
bos.close();
File dir=getApplicationContext().getExternalCacheDir();
//将字节写入外部存储器
FileChannel readWriteChannel=新的随机访问文件(dir.getPath()+“/test_image_s.png”,“rw”).getChannel();
ByteBuffer readWriteBuf=readWriteChannel.map(FileChannel.MapMode.READ_-WRITE,0,bitmapdata.length);
readWriteBuf.put(位图数据);
readWriteChannel.close();
}捕获(例外e){
Log.e(“StorageWrite”,e.toString());
}
检索图像();
}else if(Environment.MEDIA\u MOUNTED\u READ\u ONLY.equals(state)){
Log.e(“StorageWrite”、“存储不可写”);
}否则{
Log.e(“StorageWrite”,“既不可写也不可读的存储”);
}
}
私有void retrieveImage(){
String state=Environment.getExternalStorageState();
if(环境、介质、安装等于(状态)){
//我们可以读写媒体
试一试{
//在外部存储器上从PNG文件创建可绘制文件
File dir=getApplicationContext().getExternalCacheDir();
字符串pathName=dir.getPath()+“/test\u image\u s.png”;
Drawable d=Drawable.createFromPath(路径名);
//显示图像
((ImageView)findViewById(R.id.storageImage)).setImageDrawable(d);
}捕获(例外e){
Log.e(“StorageWrite”,e.toString());
}
}else if(Environment.MEDIA\u MOUNTED\u READ\u ONLY.equals(state)){
Log.e(“StorageWrite”、“存储不可写”);
}否则{
Log.e(“StorageWrite”,“既不可写也不可读的存储”);
}
}
}

我的一位同事找到了解决S4问题的方法。他意识到这个设备上的外部存储实际上是模拟的。在内部,它使用内部存储器。所以我们也可以直接使用内部存储器

幸运的是,从API级别11开始,有一个SDK调用来确定是否模拟了存储:

我认为这是一个干净的解决方案,因为它不仅仅针对单个设备。只要模拟外部存储,就使用内部存储

然而,我们仍然认为,若数据是通过mmap写入的,那个么模拟的外部存储仍然存在Galaxy S4特有的问题(2)