我正在关注developer.android网站here,我正在尝试从网址加载大图片(即1024 x 900)我的代码在我的Google Nexus中工作正常但在Nexus上无效。
这是我的代码
public static Bitmap getBitmapFromURL(String src) {
Bitmap bmImg;
URL myFileUrl = null;
try {
myFileUrl = new URL(src);
HttpURLConnection conn= (HttpURLConnection)myFileUrl.openConnection();
conn.setDoInput(true);
conn.connect();
InputStream is = conn.getInputStream();
final BitmapFactory.Options options = new BitmapFactory.Options();
BufferedInputStream bis = new BufferedInputStream(is, 4*1024);
ByteArrayBuffer baf = new ByteArrayBuffer(50);
int current = 0;
while ((current = bis.read()) != -1) {
baf.append((byte)current);
}
byte[] imageData = baf.toByteArray();
BitmapFactory.decodeByteArray(imageData, 0, imageData.length, options);
options.inJustDecodeBounds = true;
options.inSampleSize = calculateInSampleSize(options, 1024, 128);
options.inJustDecodeBounds = false;
Bitmap bitmap = BitmapFactory.decodeByteArray(imageData, 0, imageData.length,options);
return bitmap;
} catch (Exception e) {
// TODO Auto-generated catch block
return null;
}
}
和
public static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) > reqHeight
&& (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
AsyncTask类
class BitmapWorkerTask extends AsyncTask<String, Void, Bitmap> {
private final WeakReference<ImageView> imageViewReference;
private String data = null;
public BitmapWorkerTask(ImageView imageView) {
// Use a WeakReference to ensure the ImageView can be garbage collected
imageViewReference = new WeakReference<ImageView>(imageView);
}
// Decode image in background.
@Override
protected Bitmap doInBackground(String... params) {
data = params[0];
return Util.getBitmapFromURL(data);
}
// Once complete, see if ImageView is still around and set bitmap.
@Override
protected void onPostExecute(Bitmap bitmap) {
if (imageViewReference != null && bitmap != null) {
final ImageView imageView = imageViewReference.get();
if (imageView != null) {
imageView.setImageBitmap(Bitmap.createBitmap(bitmap, 0, bitmap.getHeight()/2, bitmap.getWidth(), bitmap.getHeight()/2));
}
}
}
}
当我在Nexus上运行时,我的内存不足异常。如下面的Android开发者网站,我不明白我在这里做错了什么以及为什么我的应用程序粉碎旧设备。 请帮忙。
注意:我的图片宽度应始终为match_parent。这就是我把calculateInSampleSize(选项, 1024 ,128)
的原因答案 0 :(得分:1)
你浪费记忆,因为你在解码整个图像一次后设置了JustDecodeBounds。 (我猜你之后会因为这个而得到OOM)。考虑关闭输入流。
BitmapFactory.decodeByteArray(imageData, 0, imageData.length, options);
options.inJustDecodeBounds = true;
options.inSampleSize = calculateInSampleSize(options, 1024, 128);
options.inJustDecodeBounds = false;
Bitmap bitmap = BitmapFactory.decodeByteArray(imageData, 0, imageData.length,options);
return bitmap;
我认为你真的应该这样做:
options.inJustDecodeBounds = true;
BitmapFactory.decodeByteArray(imageData, 0, imageData.length, options);
options.inSampleSize = calculateInSampleSize(options, 1024, 128);
options.inJustDecodeBounds = false;
Bitmap bitmap = BitmapFactory.decodeByteArray(imageData, 0, imageData.length,options);
return bitmap;
这将获得图像的宽度和高度而不存储位图(只需获取选项),然后在此之后将图像子采样到正确的大小并返回位图。
我不明白你为什么要在asynctask的 onPostExexute
中重新调整位图的大小, imageView.setImageBitmap(Bitmap.createBitmap(bitmap, 0, bitmap.getHeight()/2, bitmap.getWidth(), bitmap.getHeight()/2));
当您刚刚完成加载位图时,为什么不加载正确的尺寸开始?(执行上述更改后,我建议您记录尺寸,看看是否真的需要在 onPostExexute
)
您是否看过图片加载库?
有很多可用的,一个似乎符合您需求的是Picasso
在哪里可以执行以下操作: Picasso.with(context).load("url_to_image").fit().into(imageView);
这会下载并缓存位图(在后台线程中)并且适合并绘制到一个imageView中,所有这些都在一行中,整齐!
答案 1 :(得分:0)
您必须在Bitmap
Thread
内进行Main thread
提取,而不是AsyncTask
,在getBitmapFromURL()
内执行此操作,否则您的应用将会内存不足。
doInBackground
Asynctask
{{1}} {{1}}方法中的工作是否正常工作
答案 2 :(得分:-1)
在您的清单中:将android:largeHeap=true
添加到您的应用程序标签中。