Java Android:高效管理位图arraylist而不会导致OutOfMemory异常
我正在用android实现一本速写本。在这里,我添加了一个画布。为了显示用户有多个页面,当用户单击下一页时,我将画布上当前的位图保存到位图阵列列表中,并清除画布以获得新位图。最后我将整个ArrayList一起保存到图像文件中(工作正常) 问题是,在我的应用程序中,用户可以使用“下一步”和“上一步”按钮移动到先前绘制的位图,在这里,我从位图重新绘制位图。这就是我使用位图数组列表的原因。问题是,在创建了几个页面(比如30个页面)后,我的应用程序崩溃,说OutOfMemory exception 有没有人能提出一种有效的方法来实现我想要实现的目标,这样用户就可以创建任意多的页面,并且仍然可以来回导航 下面是保存到位图arraylist的代码Java Android:高效管理位图arraylist而不会导致OutOfMemory异常,java,android,bitmap,android-canvas,android-bitmap,Java,Android,Bitmap,Android Canvas,Android Bitmap,我正在用android实现一本速写本。在这里,我添加了一个画布。为了显示用户有多个页面,当用户单击下一页时,我将画布上当前的位图保存到位图阵列列表中,并清除画布以获得新位图。最后我将整个ArrayList一起保存到图像文件中(工作正常) 问题是,在我的应用程序中,用户可以使用“下一步”和“上一步”按钮移动到先前绘制的位图,在这里,我从位图重新绘制位图。这就是我使用位图数组列表的原因。问题是,在创建了几个页面(比如30个页面)后,我的应用程序崩溃,说OutOfMemory exception 有没
public void bitArrayStore(int k) {
if (drawView.canvasBitmap.sameAs(drawView.emptyBitmap)) {
flag = true;
} else {
try {
if (flag1 == false) {
drawView.buildDrawingCache();
drawView.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);
bitmaps.set(k, Bitmap.createBitmap(drawView.getDrawingCache()));
} else {
bitmaps.add(k, Bitmap.createBitmap(drawView.getDrawingCache()));
flag1 = false;
}
} catch (IndexOutOfBoundsException e) {
bitmaps.add(k, Bitmap.createBitmap(drawView.getDrawingCache()));
}
drawView.destroyDrawingCache();
}
这是当用户单击“上一步”或“下一步”按钮时,我用于将其重新绘制到画布中的代码
public void redraw(ArrayList<Bitmap> bits, int i) {
try {
drawCanvas.drawBitmap(bits.get(i), 0, 0, canvasPaint);
invalidate();
}catch (NullPointerException e){
Log.w("DrawingApp","Exception");
}
}
public void重画(数组列表位,int i){
试一试{
drawCanvas.drawBitmap(bit.get(i)、0、0、canvasPaint);
使无效();
}捕获(NullPointerException e){
Log.w(“绘图应用”、“例外”);
}
}
下面是onClickListeners中的next和previous按钮的代码
if (v.getId() == R.id.previousbtn) {
PageNoLayout.setVisibility(View.VISIBLE);
hideDrawer(colorNsize);
hideDrawer(eraserDrawer);
try {
bitArrayStore(j);
drawView.startNew();
j--;
if (bitmaps.size() > j) {
drawView.redraw(bitmaps, j);
}
} catch (IndexOutOfBoundsException e) {
j = 0;
try {
drawView.redraw(bitmaps, j);
} catch (IndexOutOfBoundsException e1) {
drawView.startNew();
}
}
pageNo.setText(String.valueOf(j+1));
flag = false;
} else if (v.getId() == R.id.nextbtn) {
PageNoLayout.setVisibility(View.VISIBLE);
hideDrawer(colorNsize);
hideDrawer(eraserDrawer);
if (j < 50) {
bitArrayStore(j);
if (flag == false) {
j++;
}
if (bitmaps.size() > j) {
drawView.startNew();
drawView.redraw(bitmaps, j);
} else {
drawView.startNew();
}
flag = false;
} else {
Snackbar.make(v, "Reached page limit. Please save and start new note", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
pageNo.setText(String.valueOf(j+1));
}
if(v.getId()==R.id.previousbtn){
设置可见性(View.VISIBLE);
hideDrawer(彩色);
hideDrawer(橡皮擦绘图器);
试一试{
bitArrayStore(j);
drawView.startNew();
j--;
if(位图.size()>j){
重绘(位图,j);
}
}catch(IndexOutOfBoundsException e){
j=0;
试一试{
重绘(位图,j);
}捕获(IndexOutOfBoundsException e1){
drawView.startNew();
}
}
pageNo.setText(String.valueOf(j+1));
flag=false;
}else if(v.getId()==R.id.nextbtn){
设置可见性(View.VISIBLE);
hideDrawer(彩色);
hideDrawer(橡皮擦绘图器);
如果(j<50){
bitArrayStore(j);
如果(标志==false){
j++;
}
if(位图.size()>j){
drawView.startNew();
重绘(位图,j);
}否则{
drawView.startNew();
}
flag=false;
}否则{
Snackbar.make(v,“已达到页数限制。请保存并开始新注释”,Snackbar.LENGTH\u LONG)
.setAction(“Action”,null).show();
}
pageNo.setText(String.valueOf(j+1));
}
您应该使用ViewPager之类的组件,根据需要管理加载/卸载页面的过程,这样您的内存中就只有将要显示的页面
否则,您可以自己实现相同的逻辑
希望这有帮助。不要将您的
位图
保存在阵列列表
中。将它们保存在沙盒内部内存或缓存中(通过getCacheDir()
)。按“下一步”或“上一步”时,需要从文件中解码位图并通过解码方法之一加载它:BitmapFactory.decode()
您可以将文件路径保存在ArrayList
中,以便跟踪Next
和Previous
另外,
BitmapFactory.decode()
可能会占用一些时间,如果您希望用户交互良好,可以提前解码一对(仅一对)位图,可能是异步的。确保使用完位图后调用Bitmap.recycle()
,然后转到下一个位图。唯一的方法是将位图保存在磁盘(PNG或JPG)中,然后重新加载。位图占用大量内存,如果你试图在内存中存储太多的位图,就会耗尽内存,这是一个简单的数学问题。但是我想不出别的办法。这就是我问的原因。谢谢你的回复。就像你说的,如果我保存到磁盘,我怎么知道上一个文件是什么,下一个文件是什么?你能帮我解决这个困惑吗@但是,你只需要记住寻呼机号码
和文件路径
之间的相关性。您可以有一个标准的命名约定,page_X.png
,或者放入一个SQLite数据库,有一个ArrayList
,写入共享首选项。@Budius。。。谢谢你的解决方案。。。。我试过了。。就像我想要的那样。请将您的解决方案写为答案,以便我将其标记为已接受答案:)