我正在开发一个从Server API下载图像的应用程序...
我们创建了一个API,它提供了图像URL的JSON响应......
我创建GridView
用于显示图片,但它正在成功运作....
但问题是,当图像数量增加时,由于堆内存增加,它会抛出OutOfMemoryException
...
我试图通过System.gc();
手动清除堆内存..但没有效果.......
所以,我的问题是:如何在没有此问题的情况下从服务器成功加载所有图像.. 我应该做些什么改变来解决这个问题
有我的JSON和代码..
JSON:
{
is_error: "false",
is_error_msg: "Video/Image List",
images: [
"http://equestsolutions.net/clients/elad/MovieApp/public/uploads/Screenshot_2014-07-21-17-22-43.png",
"http://equestsolutions.net/clients/elad/MovieApp/public/uploads/IMG_20140521_155703.jpg",
"http://equestsolutions.net/clients/elad/MovieApp/public/uploads/IMG_20140522_152254.jpg",
"http://equestsolutions.net/clients/elad/MovieApp/public/uploads/1386231199182.jpg",
"http://equestsolutions.net/clients/elad/MovieApp/public/uploads/DSC01809.JPG"
],
videos: [ ],
others: [ ]
}
ImageAdapter.java
private class ImageAdapter extends BaseAdapter {
private final Context mContext;
ArrayList<String> urls_list;
ProgressBar pbrLoadImage;
public ImageAdapter(Context context,ArrayList<String> urls_list) {
super();
mContext = context;
this.urls_list= urls_list;
}
@Override
public int getCount() {
return urls_list.size();
}
@Override
public Object getItem(int position) {
return urls_list.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup container) {
ImageView imageView;
if (convertView == null) { // if it's not recycled, initialize some attributes
LayoutInflater mInflater = (LayoutInflater)
getActivity().getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
convertView = mInflater.inflate(R.layout.image_grid_fragment_raw, null);
}
FrameLayout frm = (FrameLayout)convertView.findViewById(R.id.imageframe);
pbrLoadImage =(ProgressBar)convertView.findViewById(R.id.pbrLoadImage);
imageView = (ImageView)convertView.findViewById(R.id.imageFromUrl); ImageView(mContext);
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.getLayoutParams().height = 160;
imageView.getLayoutParams().width = 160;
Log.i("values", "value :"+url_list.get(position));
new BitmapWorkerTask(imageView).execute(url_list.get(position)); // calling class for download Images...
return convertView;
}
//download Images from path
class BitmapWorkerTask extends AsyncTask<String, Void, Bitmap> {
private final WeakReference<ImageView> imageViewReference;
//private int data = 0;
String path=null;
Bitmap mIcon=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];
path = params[0];
InputStream in=null;
ByteArrayOutputStream out=null;
try {
in = new java.net.URL(path).openStream();
mIcon = BitmapFactory.decodeStream(in);
out= new ByteArrayOutputStream();
mIcon.compress(Bitmap.CompressFormat.PNG, 100, out);
in.close();
out.close();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
//return decodeSampledBitmapFromResource(getResources(), data, 100, 100));
//return BitmapFactory.decodeStream(new ByteArrayInputStream(out.toByteArray()));
return mIcon;
}
// 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);
}
}
}
}
}
请告诉我应该采取哪些措施来解决我的问题..
提前感谢您的帮助......
答案 0 :(得分:3)
这在android中是一个非常常见的问题。将位图加载到内存中可能会导致OutOfMemoryException
。
我建议您使用像picasso这样的lib,这个lib会在后台为您加载图像,并调整它们以使您的ImageView适合一行代码。
Picasso.with(context).load(URL).fit().centerCrop().into(imageView);
答案 1 :(得分:0)
在inPurgeable中添加BitmapFactory.Options也计算可能的最大inSampleSize 对于参考Check this和this link。
答案 2 :(得分:0)
我检查了您从服务器获取的浏览器上的图像,发现图像的分辨率非常高,大约为960 * 1280,而您正在使用135 * 160像素的GridView中的图像这样下载的位图与你需要的大小相比非常大,所以如果可能的话,既然你正在按照你的说法管理API,你可以将图像上传到最大尺寸的服务器上,因为那只是浪费网络带宽,因为必须获取更多数据,获取更多时间,并将更多内存保存在内存中。
使用最低API级别为11,因为位图存储在本机内存之前的API级别11,垃圾收集器无法进行垃圾收集,相反从API级别开始11位图存储在dalvik中(类似于Android虚拟机) Java虚拟机)堆内存,可以在垃圾收集器运行时进行垃圾回收。
调用bitmap.recycle();使用创建的位图后,使用这两行代码片段。 的System.gc(); 调用Runtime.getRuntime()GC();
在使用任何流或数据库相关操作时要格外小心,因为如果流或数据库未正确关闭,则会导致难以捉摸的内存泄漏。
此外,我不知道为什么要使用输出流将PNG压缩图像保存到内部存储器: out = new ByteArrayOutputStream(); mIcon.compress(Bitmap.CompressFormat.PNG,100,out);
使用android:largeHeap =&#34; true&#34;它不是解决内存问题的正确方法,只是延迟崩溃永远不会完全防止内存崩溃。