我收到一条错误,指出位图正在使用很多内存。
我知道我应该使用bitmap.recyle()但是我不知道在哪里放它,无论我把它放在哪里我都会收到错误,说我正在尝试使用循环位图。
如果有人能提供帮助那就太棒了。
以下是我的相关代码:
public class PictureViewer extends SherlockActivity implements
android.view.GestureDetector.OnGestureListener {
private ViewFlipper viewFlipper = null;
private GestureDetector gestureDetector = null;
ArrayList<Integer> number = new ArrayList<Integer>();
DownloadBitmap bit = new DownloadBitmap();
int j = 1;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Remove title bar
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.pictureviewer);
viewFlipper = (ViewFlipper) findViewById(R.id.viewflipper);
gestureDetector = new GestureDetector(this);
for (int i = 1; i <= 65; ++i)
number.add(i);
Collections.shuffle(number);
loadImage();
loadImage();
}
public void loadImage() {
if (j == 65) { // Change this number to exact ammount of pictures
j = 1;
}
int next = number.get(j);
j++;
ImageView image = new ImageView(this);
Bitmap bitmap = bit.createBitmapFromUrl("http://comedyzone.mobi/img" + next + ".jpg");
WeakReference<Bitmap> mBitmapReference = new WeakReference<Bitmap>(bitmap);
image.setImageBitmap(mBitmapReference.get());
image.setScaleType(ImageView.ScaleType.FIT_XY);
viewFlipper.addView(image, new LayoutParams(LayoutParams.FILL_PARENT,
LayoutParams.FILL_PARENT));
}
@Override
public boolean onDown(MotionEvent arg0) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean onFling(MotionEvent arg0, MotionEvent arg1, float arg2,
float arg3) {
// TODO Auto-generated method stub
if (arg0.getX() - arg1.getX() > 120) {
this.viewFlipper.setInAnimation(AnimationUtils.loadAnimation(this,
R.anim.push_left_in));
this.viewFlipper.setOutAnimation(AnimationUtils.loadAnimation(this,
R.anim.push_left_out));
this.viewFlipper.showNext();
loadImage();
return true;
} else if (arg0.getX() - arg1.getX() < -120) {
this.viewFlipper.setInAnimation(AnimationUtils.loadAnimation(this,
R.anim.push_right_in));
this.viewFlipper.setOutAnimation(AnimationUtils.loadAnimation(this,
R.anim.push_right_out));
this.viewFlipper.showPrevious();
loadImage();
return true;
}
return true;
}
@Override
public void onLongPress(MotionEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public boolean onScroll(MotionEvent arg0, MotionEvent arg1, float arg2,
float arg3) {
// TODO Auto-generated method stub
return false;
}
@Override
public void onShowPress(MotionEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public boolean onSingleTapUp(MotionEvent arg0) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
return this.gestureDetector.onTouchEvent(event);
}
private InputStream OpenHttpConnection(String urlString) throws IOException {
InputStream in = null;
int response = -1;
URL url = new URL(urlString);
URLConnection conn = url.openConnection();
if (!(conn instanceof HttpURLConnection))
throw new IOException("Not an HTTP connection");
try {
HttpURLConnection httpConn = (HttpURLConnection) conn;
httpConn.setAllowUserInteraction(false);
httpConn.setInstanceFollowRedirects(true);
httpConn.setRequestMethod("GET");
httpConn.connect();
response = httpConn.getResponseCode();
if (response == HttpURLConnection.HTTP_OK) {
in = httpConn.getInputStream();
}
} catch (Exception ex) {
throw new IOException("Error connecting");
}
return in;
}
答案 0 :(得分:6)
我知道我应该使用bitmap.recyle()
无需拨打recycle
。
去年在谷歌IO上,有一个关于这个主题的演讲。
Google I/O 2011: Memory management for Android Apps - 你一定要注意这一切,值得花时间。
为WeakReference
对象制作Bitmap
是改善Bitmap
管理的良好开端。例如:
Bitmap bitmap = DownloadImage("http://comedyzone.mobi/img" + next + ".jpg");
WeakReference<Bitmap> mBitmapReference = new WeakReference<Bitmap>(bitmap);
image.setImageBitmap(mBitmapReference.get());
有效显示位图
These are Android training classes you should read through too.
此外,这是我写的一个从URL下载图像的类。您应该考虑使用它来代替DownloadImage
方法,它会更有效率。
<强> DownloadBitmap 强>
public class DownloadBitmap {
private static String LOG_TAG = DownloadBitmap.class.getName();
/**
* @param url
* @return Bitmap image from the interwebs
*/
static Bitmap createBitmapFromUrl(String url) {
final Bitmap mBitmap = readBitmapFromNetwork(url);
final WeakReference<Bitmap> mBitmapReference = new WeakReference<Bitmap>(mBitmap);
if (mBitmapReference.get() != null)
return mBitmapReference.get();
return null;
}
/**
* @param urlString The URL to read the bitmap from.
* @return A Bitmap image or null if an error occurs.
*/
private static Bitmap readBitmapFromNetwork(String urlString) {
InputStream mInputStream = null;
FlushedInputStream mFlushedInputStream = null;
Bitmap mBitmap = null;
WeakReference<Bitmap> mBitmapReference = null;
try {
final BitmapFactory.Options mOptions = new BitmapFactory.Options();
mOptions.inPurgeable = true;
mOptions.inDither = false;
final URL mUrl = new URL(urlString);
final URLConnection mConnection = mUrl.openConnection();
mConnection.connect();
mInputStream = mConnection.getInputStream();
mFlushedInputStream = new FlushedInputStream(mInputStream);
mBitmap = BitmapFactory.decodeStream(mFlushedInputStream, null, mOptions);
mBitmapReference = new WeakReference<Bitmap>(mBitmap);
} catch (MalformedURLException e) {
if (BuildConfig.DEBUG)
Log.e(LOG_TAG, "Bad image URL", e);
return null;
} catch (IOException e) {
if (BuildConfig.DEBUG)
Log.e(LOG_TAG, "Could not get remote image", e);
return null;
} finally {
try {
if (mInputStream != null)
mInputStream.close();
if (mFlushedInputStream != null)
mFlushedInputStream.close();
} catch (IOException e) {
if (BuildConfig.DEBUG)
Log.e(LOG_TAG, "Error closing stream.");
return null;
}
}
if (mBitmapReference.get() != null)
return mBitmapReference.get();
return null;
}
/**
* An InputStream that skips the exact number of bytes provided, unless it
* reaches EOF.
*/
static class FlushedInputStream extends FilterInputStream {
public FlushedInputStream(InputStream inputStream) {
super(inputStream);
}
@Override
public long skip(long n) throws IOException {
long totalBytesSkipped = 0L;
while (totalBytesSkipped < n) {
long bytesSkipped = in.skip(n - totalBytesSkipped);
if (bytesSkipped == 0L) {
int bytes = read();
if (bytes < 0) {
break;
} else {
bytesSkipped = 1;
}
}
totalBytesSkipped += bytesSkipped;
}
return totalBytesSkipped;
}
}
}
答案 1 :(得分:1)
在使用之前,您需要减小位图的样本大小。这可以用来做到这一点。
private Bitmap decodeFile(File file)
{
try
{
//********************* decode image size ********************
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(new FileInputStream(file), null, options);
// ********************** Find the correct scale value. It should be the power of 2. ********************
options.inSampleSize = BitmapConverter.calculateInSampleSize(options, 145, 105);
options.inJustDecodeBounds = false;
return BitmapFactory.decodeStream(new FileInputStream(file), null, options);
}
catch(FileNotFoundException eFileNotFoundException)
{
return null;
}
}
然后你可以根据需要调用Bitmap.recycle(),虽然我觉得没必要。
答案 2 :(得分:0)
ImageLoader
您可以使用Imageloader类在后台加载图像
Imageloader
答案 3 :(得分:0)
您可以在bitmap.recycle()
函数之后的image.setImageBitmap(bitmap);
语句之后写loadImage()
,因为在此语句之后不再需要位图。
发生此错误是因为您使用的是非常大的位图,或者您的代码中存在内存泄漏。
无论何时使用位图,都要尽量使用所有可能的Options作为最小内存。
有关详细信息,请参阅我的answer同一问题。
答案 4 :(得分:0)
一般来说,在不再需要时,应标记要清理的对象。在你的情况下,我唯一一次看到你不再需要这些位图就是当活动不再在前面时。
我看到的是ViewFlipper可能会使用不必要的大位图。您应该在将位图设置在ImageView内部之前调整位图的大小,而不是在添加它们之后调整ImageView的大小。尝试使用inSampleSize作为BitmapFactory的选项,并在将位图加载到ImageView之前使用Bitmap.createScaledBitmap()调整位图大小。