gpt4 book ai didi

android - 内存全是图片,可能是Bitmap.compress(format, int, stream)引起的

转载 作者:太空宇宙 更新时间:2023-11-03 10:53:36 25 4
gpt4 key购买 nike

我的应用程序是一个 Wifi 聊天应用程序,您可以使用它在两个 Android 设备之间进行通信,发送文本消息和快照相机图片。图片存储到 SD 卡中。

我曾经有一个 OutOfMemoryError 在发送了几个图像后抛出,但我通过发送

解决了这个问题
options.inPurgeable = true;

options.inInputShareable = true;

到 BitmapFactory.decodeByteArray 方法。这使得像素“可解除分配”,因此新图像可以使用内存。因此,错误不再存在。

但是,内部存储器仍然充满图像,并出现“空间不足:手机存储空间不足”警告。该应用程序不再崩溃,但在应用程序完成后手机上没有更多内存。我必须在“设置”>“应用程序”>“管理应用程序”中手动清除应用程序的数据。

我尝试回收位图,甚至尝试显式清空应用程序的缓存,但它似乎没有达到我的预期。

此函数通过 TCP 套接字接收图片,将其写入 SD 卡并启动我的自定义 Activity PictureView:

public void receivePicture(String fileName) {
try {
int fileSize = inStream.readInt();
Log.d("","fileSize:"+fileSize);
byte[] tempArray = new byte[200];
byte[] pictureByteArray = new byte[fileSize];

path = Prefs.getPath(this) + "/" + fileName;
File pictureFile = new File(path);
try {
if( !pictureFile.exists() ) {
pictureFile.getParentFile().mkdirs();
pictureFile.createNewFile();
}
} catch (IOException e) { Log.d("", "Recievepic - Kunde inte skapa fil.", e); }

int lastRead = 0, totalRead = 0;
while(lastRead != -1) {
if(totalRead >= fileSize - 200) {
lastRead = inStream.read(tempArray, 0, fileSize - totalRead);
System.arraycopy(tempArray, 0, pictureByteArray, totalRead, lastRead);
totalRead += lastRead;
break;
}
lastRead = inStream.read(tempArray);
System.arraycopy(tempArray, 0, pictureByteArray, totalRead, lastRead);
totalRead += lastRead;
}

BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(pictureFile));
bos.write(pictureByteArray, 0, totalRead);
bos.flush();
bos.close();

bos = null;
tempArray = null;
pictureByteArray = null;

setSentence("<"+fileName+">", READER);
Log.d("","path:"+path);
try {
startActivity(new Intent(this, PictureView.class).putExtra("path", path));
} catch(Exception e) { e.printStackTrace(); }
}
catch(IOException e) { Log.d("","IOException:"+e); }
catch(Exception e) { Log.d("","Exception:"+e); }
}

这是 PictureView。它从 SD 卡上的文件创建一个字节 [],将数组解码为位图,压缩位图并将其写回 SD 卡。最后,在Progress.onDismiss中,将图片设置为全屏imageView的图片:

public class PictureView extends Activity {

private String fileName;
private ProgressDialog progress;

public ImageView view;

@Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
Log.d("","onCreate() PictureView");

requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);

view = new ImageView(this);
setContentView(view);

progress = ProgressDialog.show(this, "", "Laddar bild...");
progress.setOnDismissListener(new OnDismissListener() {
public void onDismiss(DialogInterface dialog) {
File file_ = getFileStreamPath(fileName);
Log.d("","SETIMAGE");
Uri uri = Uri.parse(file_.toString());
view.setImageURI(uri);
}
});

new Thread() { public void run() {
String path = getIntent().getStringExtra("path");
Log.d("","path:"+path);
File pictureFile = new File(path);

if(!pictureFile.exists())
finish();

fileName = path.substring(path.lastIndexOf('/') + 1);
Log.d("","fileName:"+fileName);

byte[] pictureArray = new byte[(int)pictureFile.length()];

try {
DataInputStream dis = new DataInputStream( new BufferedInputStream(
new FileInputStream(pictureFile)) );
for(int i=0; i < pictureArray.length; i++)
pictureArray[i] = dis.readByte();
} catch(Exception e) { Log.d("",""+e); e.printStackTrace(); }

/**
* Passing these options to decodeByteArray makes the pixels deallocatable
* if the memory runs out.
*/
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPurgeable = true;
options.inInputShareable = true;

Bitmap pictureBM =
BitmapFactory.decodeByteArray(pictureArray, 0, pictureArray.length, options);

OutputStream out = null;
try {
out = openFileOutput(fileName, MODE_PRIVATE);

/**
* COMPRESS !!!!!
**/
pictureBM.compress(CompressFormat.PNG, 100, out);

pictureBM = null;
progress.dismiss(); }
catch (IOException e) { Log.e("test", "Failed to write bitmap", e); }
finally {
if (out != null)
try { out.close(); out = null; }
catch (IOException e) { }
} }
}.start();
}

@Override
protected void onStop() {
super.onStop();
Log.d("","ONSTOP()");
Drawable oldDrawable = view.getDrawable();
if( oldDrawable != null) {
((BitmapDrawable)oldDrawable).getBitmap().recycle();
oldDrawable = null;
Log.d("","recycle");
}

Editor editor =
this.getSharedPreferences("clear_cache", Context.MODE_PRIVATE).edit();
editor.clear();
editor.commit();
}
}

当用户按下后退键时,应用内的图片应该不再可用。只是存储在 SD 卡上。

onStop() 中,我回收了旧的位图,甚至尝试清空应用程序的数据。仍然出现“空间不足”警告。我如何确定图像在不需要时不再分配内存?

编辑:看来问题出在压缩方法上。如果 compress 之后的所有内容都被注释,问题仍然存在。如果我删除压缩,问题就消失了。 Compress 似乎分配了从未释放的内存,每个图像 2-3 MB。

最佳答案

好的,我解决了。问题是,我将一个 OutputStream 传递给 compress,它是应用程序内部内存中私有(private)文件的流。这就是我后来设置的图像。这个文件永远不会被分配。

我不知道我有两个文件:一个在 SD 卡上,一个在内部存储器上,两个文件同名。

现在,我只是将 SD 卡文件设置为 ImageView 的图像。我从不将文件作为 byte[] 读入内部存储器,因此从不将数组解码为位图,因此从不将位图压缩到内部存储器中。

这是新的 PictureView:

public class PictureView extends Activity {

public ImageView view;
private String path;

@Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
Log.d("","onCreate() PictureView");

path = getIntent().getStringExtra("path");

requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);

view = new ImageView(this);
setContentView(view);

Uri uri = Uri.parse( new File(path).toString() );
view.setImageURI(uri);
}

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
Log.d("","Back key pressed");

Drawable oldDrawable = view.getDrawable();
if( oldDrawable != null) {
((BitmapDrawable)oldDrawable).getBitmap().recycle();
oldDrawable = null;
Log.d("","recycle");
}
view = null;
}
return super.onKeyDown(keyCode, event);
}
}

将外部文件作为 ImageView 的图像是不好的做法吗?我应该先将它加载到内存中吗?

关于android - 内存全是图片,可能是Bitmap.compress(format, int, stream)引起的,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9285760/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com