我正在尝试创建一个小帮助程序类,可以从多个图像中生成一个图像。它应该采用屏幕的大小,并采取所有图像的相同部分,然后将它们组合成一个单独的图像,并排放一小部分所有图像。
到目前为止,我的班级成功创建了这样的图像。我遇到的唯一问题是在创建此图像后,使用了大量已用RAM。在创建该图像后,您对如何提高RAM使用率有什么建议吗? (我不想耗尽内存)也许我正在以创建图像的方式浪费内存(我打开以获得更好的建议)。 重要的是要知道我无法将这些图像缓存在磁盘上,因为它们永远不会相同。
我注意到的是,一旦我运行手动GC RAM,使用率就会从大约70MiB回到15MiB。
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;
}
}
欢迎任何建议。祝你有美好的一天。
答案 0 :(得分:0)
我将自己回答这个问题,因为我能够将所需的内存量从70Mib减少到2Mib。我的表现非常简单。而不是在我的代码中升级我的图像,我只采用它的屏幕宽高比。缩放将由ImageView本身完成。这节省了近60%的内存。
此外,我现在在使用后直接回收大部分位图,一旦完成所有工作,LruCache将被驱逐。
这是我的更新代码(这不是最终的,但比以前更好的起点):
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();
}
}