如何在Android中高效地组合位图
我目前正在尝试创建一个小助手类,它可以从多个图像中生成一个图像。它应该取屏幕的大小,取所有图像的相等部分,然后将它们组合成一个单独的图像,其中有一小块并排的所有图像 到目前为止,我的班级成功地创造了这样一个形象。我唯一的问题是在我创建了这个图像之后,使用了大量的内存。在我创建了那个映像之后,你有什么建议可以提高RAM的使用率吗?(我不想耗尽内存)也许我在用创建图像的方式浪费内存(我愿意寻求更好的建议)。 需要知道的重要一点是,我无法将这些图像缓存在磁盘上,因为它们永远不会是相同的 我注意到,一旦我运行一个手动GC RAM,它的使用就会从大约70MiB恢复到15MiB如何在Android中高效地组合位图,android,image,performance,memory,bitmap,Android,Image,Performance,Memory,Bitmap,我目前正在尝试创建一个小助手类,它可以从多个图像中生成一个图像。它应该取屏幕的大小,取所有图像的相等部分,然后将它们组合成一个单独的图像,其中有一小块并排的所有图像 到目前为止,我的班级成功地创造了这样一个形象。我唯一的问题是在我创建了这个图像之后,使用了大量的内存。在我创建了那个映像之后,你有什么建议可以提高RAM的使用率吗?(我不想耗尽内存)也许我在用创建图像的方式浪费内存(我愿意寻求更好的建议)。 需要知道的重要一点是,我无法将这些图像缓存在磁盘上,因为它们永远不会是相同的 我注意到,一旦
private LruCache<Integer, Bitmap> mMemoryCache;
private List<Integer> IDs = new ArrayList<>();
private CombinerTask task;
private void combineImages(boolean useScreenSize){
if(task != null)
task.cancel(true);
task = new CombinerTask(useScreenSize);
if( Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ) {
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
} else {
task.execute();
}
}
class CombinerTask extends AsyncTask<Void,Void,Bitmap>{
private boolean useScreenSize;
public CombinerTask(boolean useScreenSize){
this.useScreenSize = useScreenSize;
}
@Override
protected Bitmap doInBackground(Void...voids) {
Bitmap bmOverlay;
if(useScreenSize){
WindowManager wm = (WindowManager) ImageCombiner.getInstance().getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
Point size = new Point();
display.getSize(size);
for(int x = 0; x < IDs.size(); x++){
float scaleFactor = (float)size.y / (float)mMemoryCache.get(IDs.get(x)).getHeight();
Bitmap temp = Bitmap.createScaledBitmap(mMemoryCache.get(IDs.get(x)),(int)(mMemoryCache.get(IDs.get(x)).getWidth() * scaleFactor), (int)(mMemoryCache.get(IDs.get(x)).getHeight() * scaleFactor),false);
mMemoryCache.put(IDs.get(x),temp);
}
bmOverlay = Bitmap.createBitmap(size.x,size.y,mMemoryCache.get(IDs.get(0)).getConfig());
}else {
bmOverlay = Bitmap.createBitmap(mMemoryCache.get(IDs.get(0)).getWidth(),mMemoryCache.get(IDs.get(0)).getHeight(),mMemoryCache.get(IDs.get(0)).getConfig());
}
Canvas canvas = new Canvas(bmOverlay);
for(int i = 0; i < IDs.size(); i++){
Bitmap bm = Bitmap.createBitmap(mMemoryCache.get(IDs.get(i)),mMemoryCache.get(IDs.get(i)).getWidth()/3,0,bmOverlay.getWidth()/mMemoryCache.size(),mMemoryCache.get(IDs.get(i)).getHeight());
canvas.drawBitmap(bm,bm.getWidth()*i,0,null);
bm.recycle();
}
canvas = null;
return bmOverlay;
}
@Override
protected void onPostExecute(Bitmap bitmap) {
if(listener != null)
listener.combineFinished(bitmap);
for (int i = 0; i < IDs.size(); i++){
mMemoryCache.get(IDs.get(i)).recycle();
}
mMemoryCache = null;
IDs = null;
}
}
私有LruCache-mMemoryCache;
私有列表ID=new ArrayList();
私密任务;
专用void组合图像(布尔值useScreenSize){
如果(任务!=null)
任务。取消(true);
任务=新组合任务(使用屏幕大小);
if(Build.VERSION.SDK\u INT>=Build.VERSION\u code.hyboone){
task.executeOnExecutor(异步task.THREAD\u POOL\u EXECUTOR);
}否则{
task.execute();
}
}
类CombinerTask扩展了AsyncTask{
屏幕大小的私有布尔值;
公共组合任务(布尔值useScreenSize){
this.useScreenSize=useScreenSize;
}
@凌驾
受保护位图doInBackground(无效…无效){
位图覆盖;
如果(使用屏幕大小){
WindowManager wm=(WindowManager)ImageCombiner.getInstance().getSystemService(Context.WINDOW\u服务);
Display Display=wm.getDefaultDisplay();
点大小=新点();
display.getSize(size);
对于(int x=0;x
欢迎提出任何建议。祝你度过愉快的一天。我将自己回答这个问题,因为我能够将所需的内存量从70Mib减少到2Mib。我做的很简单。我没有在我的代码中放大我的图像,我只采用它与屏幕的纵横比。缩放将由ImageView本身完成。这节省了近60%的内存 此外,我现在在使用后直接回收大部分位图,一旦所有作业完成,LruCache将被逐出 下面是我更新的代码(这不是最终的,但比以前好得多):
private void组合图像(布尔值useScreenSize){
如果(任务!=null)
任务。取消(true);
任务=新组合任务(使用屏幕大小);
if(Build.VERSION.SDK\u INT>=Build.VERSION\u code.hyboone){
task.executeOnExecutor(异步task.THREAD\u POOL\u EXECUTOR);
}否则{
task.execute();
}
}
类CombinerTask扩展了AsyncTask{
屏幕大小的私有布尔值;
公共组合任务(布尔值useScreenSize){
this.useScreenSize=useScreenSize;
}
@凌驾
受保护位图doInBackground(无效…无效){
如果(!mMemoryCache.get(IDs.get(0)).isRecycled()){
位图覆盖;
如果(使用屏幕大小){
WindowManager wm=(WindowManager)ImageCombiner.getInstance().getSystemService(Context.WINDOW\u服务);
Display Display=wm.getDefaultDisplay();
点大小=新点();
display.getSize(size);
对于(int x=0;x缩放因子宽度){
temp=Bitmap.createScaledBitmap(mMemoryCache.get(id.get(x)),(int)(宽度*scaleFactorHeight),(int)(高度*scaleFactorHeight),false);
位图裁剪=Bitmap.createBitmap(temp,0,0,size.x,size.y);
温度循环();
temp=Bitmap.createScaledBitmap(裁剪,(int)((float)裁剪.getWidth()/scaleFactorHeight),(int)((float)裁剪.getHeight()/scaleFactorHeight),false);
crapped.recycle();
}否则
private void combineImages(boolean useScreenSize){
if(task != null)
task.cancel(true);
task = new CombinerTask(useScreenSize);
if( Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ) {
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
} else {
task.execute();
}
}
class CombinerTask extends AsyncTask<Void,Void,Bitmap>{
private boolean useScreenSize;
public CombinerTask(boolean useScreenSize){
this.useScreenSize = useScreenSize;
}
@Override
protected Bitmap doInBackground(Void...voids) {
if(!mMemoryCache.get(IDs.get(0)).isRecycled()) {
Bitmap bmOverlay;
if (useScreenSize) {
WindowManager wm = (WindowManager) ImageCombiner.getInstance().getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
Point size = new Point();
display.getSize(size);
for (int x = 0; x < IDs.size(); x++) {
int width = mMemoryCache.get(IDs.get(x)).getWidth();
int height = mMemoryCache.get(IDs.get(x)).getHeight();
float scaleFactorWidth = 1f;
float scaleFactorHeight = 1f;
scaleFactorWidth = (float) size.x / (float) width;
scaleFactorHeight = (float) size.y / (float) height;
Bitmap temp = null;
if (scaleFactorHeight > scaleFactorWidth) {
temp = Bitmap.createScaledBitmap(mMemoryCache.get(IDs.get(x)), (int) (width * scaleFactorHeight), (int) (height * scaleFactorHeight), false);
Bitmap cropped = Bitmap.createBitmap(temp, 0, 0, size.x, size.y);
temp.recycle();
temp = Bitmap.createScaledBitmap(cropped, (int) ((float) cropped.getWidth() / scaleFactorHeight), (int) ((float) cropped.getHeight() / scaleFactorHeight), false);
cropped.recycle();
} else if (scaleFactorHeight < scaleFactorWidth) {
temp = Bitmap.createScaledBitmap(mMemoryCache.get(IDs.get(x)), (int) (width * scaleFactorWidth), (int) (height * scaleFactorWidth), false);
Bitmap cropped = Bitmap.createBitmap(temp, 0, 0, size.x, size.y);
temp.recycle();
temp = Bitmap.createScaledBitmap(cropped, (int) ((float) cropped.getWidth() / scaleFactorWidth), (int) ((float) cropped.getHeight() / scaleFactorWidth), false);
cropped.recycle();
}
if(mMemoryCache.get(IDs.get(x)) != null)
mMemoryCache.get(IDs.get(x)).recycle();
mMemoryCache.put(IDs.get(x), temp);
}
bmOverlay = Bitmap.createBitmap(mMemoryCache.get(IDs.get(0)).getWidth(), mMemoryCache.get(IDs.get(0)).getHeight(), mMemoryCache.get(IDs.get(0)).getConfig());
} else {
bmOverlay = Bitmap.createBitmap(mMemoryCache.get(IDs.get(0)).getWidth(), mMemoryCache.get(IDs.get(0)).getHeight(), mMemoryCache.get(IDs.get(0)).getConfig());
}
Canvas canvas = new Canvas(bmOverlay);
for (int i = 0; i < IDs.size(); i++) {
Bitmap bm = Bitmap.createBitmap(mMemoryCache.get(IDs.get(i)), 0, 0, bmOverlay.getWidth() / mMemoryCache.size(), mMemoryCache.get(IDs.get(i)).getHeight());
canvas.drawBitmap(bm, bm.getWidth() * i, 0, null);
bm.recycle();
}
canvas = null;
return bmOverlay;
}
return null;
}
@Override
protected void onPostExecute(Bitmap bitmap) {
if(listener != null && bitmap != null)
listener.combineFinished(bitmap);
for (int i = 0; i < IDs.size(); i++){
if(mMemoryCache.get(IDs.get(i))!= null)
mMemoryCache.get(IDs.get(i)).recycle();
}
mMemoryCache.evictAll();
IDs.clear();
}
}