我使用ListView
的自定义适配器实施extends BaseAdapter
。在我的应用中,图片从网址下载,然后在Listview
中设置为位图图片。
问题是在完成2个图像的下载后java.Lang.OutOfMemoryError
发生并且应用程序崩溃。我知道这是内存问题,但我不知道应该采取哪些步骤来避免这种情况......我使用压缩图像并且工作正常。
以下是getView()
CustomAdapter
和doInBackground()
AsyncTask
的代码。
提前谢谢......
任何建议都将受到赞赏..
public View getView(final int position, View convertView, final ViewGroup parent) {
if (convertView == null){
convertView = inflater.inflate(R.layout.row, parent, false);
}
img_name = "test" + position;
image = (ImageView) convertView.findViewById(R.id.imageView1);
Log.d("URL", ""+values[position]);
AsyncTaskRunner runner = new AsyncTaskRunner();
final int x = (int) getItemId(position);
runner.execute(values[x] , image , img_name);
return convertView;
}
doInBackground(对象...参数)
protected ImageView doInBackground(Object... params) {
//publishProgress("Calculating..."); // Calls onProgressUpdate()
URL imageURL = null;
try {
url = (String) params[0];
img = (ImageView) params[1];
name = (String) params[2] + ".png";
imageURL = new URL(url);
Log.d("URL", ""+params[0]);
}
catch (MalformedURLException e) {
e.printStackTrace();
}
try {
HttpURLConnection connection= (HttpURLConnection)imageURL.openConnection();
connection.setDoInput(true);
connection.connect();
InputStream inputStream = connection.getInputStream();
bitmap = BitmapFactory.decodeStream(inputStream);
resized = Bitmap.createScaledBitmap(bitmap, 200, 200, true);
}
catch (IOException e) {
e.printStackTrace();
}
return img;
}
OnPostExecute(ImageView结果)
protected void onPostExecute(ImageView result) {
result.setImageBitmap(resized);
}
答案 0 :(得分:2)
java.Lang.OutOfMemoryError
<强>原因:强>
android中的每个进程都分配了一个不同的最大堆大小 设备到设备。(平均约16 MB。)在应用程序中使用的高分辨率图像占用此堆的大空间。因此,当创建新的位图实例并且总大小超过分配的堆大小时,是JVM抛出的错误。
<强>解决方案:强>
Android提供了一种处理此问题的方法。在解码位图之前,我们只需使用options.inJustDecodeBounds = true.
对其进行解码,其中options是BitmapFactory
的实例。它不会将位图加载到内存中,但它可以帮助我们找到位图的宽度和高度,以便我们可以根据设备减小高度和宽度。
然后缩小您的位图以创建一个较小尺寸的图像,这反过来会占用堆上较少的空间。 这是实现它的方法。
BitmapFactory.Options bmpBuffer = new BitmapFactory.Options();
bmpBuffer.inSampleSize = 3;
Bitmap bmp = BitmapFactory.decodeFile(path, bmpBuffer);
这将使您的位图成为原始大小的1/3 rd因此 也会占据1/3的空间。
<强>例如强>
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}
计算样本量的方法:
public static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
if (width > height) {
inSampleSize = Math.round((float)height / (float)reqHeight);
} else {
inSampleSize = Math.round((float)width / (float)reqWidth);
}
}
return inSampleSize;
}
注意:
如果没有其他选项,您可以使用以下内容。但是,我想提醒您,它会影响您设备上的其他应用程序。因此我不建议你使用它。
<application
android:largeHeap="true">
</application>
largeHeap="true"
将允许应用程序使用更多堆(如果可用)。但是,您的应用程序将在垃圾收集期间花费更多时间。设备上的其他应用程序可能会被踢出内存。
CommonsWare 解释了它here
答案 1 :(得分:0)
您可以使用Picasso Library有效地从网址下载图片,此外还有更多选项可以调整图片大小,缓存等。
答案 2 :(得分:0)
使用此bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);