Picasso 内存不足错误 - Android 使用自定义适配器在 ListView 中加载图像
Picasso out of memory error - Android Image Loading in ListView with custom adapter
所以现在我包含了 picasso
和 sonce
然后每次我想做任何事情时我都会经常内存不足 errors
。这可能是因为 picasso
缓存了图像?我完全不知道为什么会这样,也不知道如何解决……有什么经验吗?
编辑:解决方案非常简单。必须按照 picasso
的建议更改我的自定义 adapters
以接收图像 url 并将其直接加载到 imageview
而不是使用另存为 bitmap
的弯路.忽略了提示,不知道为什么。
这是适配器:
public class ImageTextListViewAdapter extends ArrayAdapter<RowItem> {
Context context;
public ImageTextListViewAdapter(Context context, int resourceId,
List<RowItem> items) {
super(context, resourceId, items);
this.context = context;
}
/*private view holder class*/
private class ViewHolder {
ImageView imageView;
TextView txt;
TextView id;
}
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
RowItem rowItem = getItem(position);
LayoutInflater mInflater = (LayoutInflater) context
.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
if (convertView == null) {
convertView = mInflater.inflate(R.layout.list_item_friends, null);
holder = new ViewHolder();
holder.id = (TextView) convertView.findViewById(R.id.text_view_id_friends);
holder.txt = (TextView) convertView.findViewById(R.id.list_item_friends_textview);
holder.imageView = (ImageView) convertView.findViewById(R.id.friends_image);
convertView.setTag(holder);
} else
holder = (ViewHolder) convertView.getTag();
holder.txt.setText(rowItem.getText());
String url = getItem(position).getUrl();
Picasso.with(context).load(url).into(holder.imageView);
holder.id.setText(rowItem.getId());
return convertView;
}
}
我有一个 listview
,我在 ListView
中从 json
(通过 asynctask
)加载每个用户的名字。
此外,用户图像也必须从服务器加载。这是通过第二个 ajax
请求发生的。当我得到 json
和 url 用于保存图像然后从服务器获取图像时,对于每个图像,通过 asynctask
触发一个请求。这使得 listview
的负载持续很长时间,因此其他活动会留在队列中,直到此任务完成。
我发现了如何将图像保存在内存缓存中。但这并不能解决问题,因为图像只有在我将应用程序置于后台时才会保存。
listview
包含一个名为 RowItem 的 custom adapter
,它包含一个 imageview
和两个 listviews
。
有什么建议吗?我现在为此工作了大约 1 天半...
谢谢!
这是我加载图像的异步任务。
public class ImageLoadTask extends AsyncTask<Void, Void, Bitmap> {
private final String LOG_TAG = ImageLoadTask.class.getSimpleName();
String url, userId;
String[] items;
BufferedReader reader = null;
public ImageLoadTask(String url, String userId, String[] items) {
this.url = url;
this.userId = userId;
this.items = items;
}
private String getImageUrlFromJson(String imageJson) throws JSONException {
JSONObject imageJsonOutput = new JSONObject(imageJson);
imageJsonUrl = imageJsonOutput.getString("imageUrl");
Log.v(LOG_TAG, imageJsonUrl);
return imageJsonUrl;
}
@Override
protected Bitmap doInBackground(Void... params) {
String imageJson = null;
try {
URL urlConnection = new URL(url + userId);
HttpURLConnection connection = (HttpURLConnection) urlConnection
.openConnection();
connection.setDoInput(true);
connection.connect();
InputStream input = connection.getInputStream();
StringBuffer buffer = new StringBuffer();
if (input == null) {
// Nothing to do.
//jsonStr = null;
return null;
}
reader = new BufferedReader(new InputStreamReader(input));
String line;
while ((line = reader.readLine()) != null) {
// Since it's JSON, adding a newline isn't necessary (it won't affect parsing)
// But it does make debugging a *lot* easier if you print out the completed
// buffer for debugging.
buffer.append(line + "\n");
}
if (buffer.length() == 0) {
return null;
}
imageJson = buffer.toString();
} catch (Exception e) {
e.printStackTrace();
}
try {
String imageUrl = getImageUrlFromJson(imageJson);
URL url = new URL(imageUrl);
bmp = BitmapFactory.decodeStream(url.openConnection().getInputStream());
addBitmapToMemoryCache(userId, bmp);
return bmp;
}
catch(Exception e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(Bitmap result) {
super.onPostExecute(result);
bmp = result;
item = new RowItem(bmp, item[0], item[1], item[2]);
mDiscoverAdapter.add(item);
}
}
您正在尝试通过不使用现有的图像加载库来重新发明轮子。查看一些顶级库:
如果你还执意要自己搭建。您需要根据需要创建一个从 memory/disk 到 save/load 的缓存系统。还要小心泄漏视图,因为这在图像加载(尤其是列表或网格)和方向更改时会变得非常棘手。
官方 android 文档有关于 Loading/Caching Images 的精彩教程。仔细阅读并查看他们提供的示例应用程序以帮助您入门。
所以现在我包含了 picasso
和 sonce
然后每次我想做任何事情时我都会经常内存不足 errors
。这可能是因为 picasso
缓存了图像?我完全不知道为什么会这样,也不知道如何解决……有什么经验吗?
编辑:解决方案非常简单。必须按照 picasso
的建议更改我的自定义 adapters
以接收图像 url 并将其直接加载到 imageview
而不是使用另存为 bitmap
的弯路.忽略了提示,不知道为什么。
这是适配器:
public class ImageTextListViewAdapter extends ArrayAdapter<RowItem> {
Context context;
public ImageTextListViewAdapter(Context context, int resourceId,
List<RowItem> items) {
super(context, resourceId, items);
this.context = context;
}
/*private view holder class*/
private class ViewHolder {
ImageView imageView;
TextView txt;
TextView id;
}
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
RowItem rowItem = getItem(position);
LayoutInflater mInflater = (LayoutInflater) context
.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
if (convertView == null) {
convertView = mInflater.inflate(R.layout.list_item_friends, null);
holder = new ViewHolder();
holder.id = (TextView) convertView.findViewById(R.id.text_view_id_friends);
holder.txt = (TextView) convertView.findViewById(R.id.list_item_friends_textview);
holder.imageView = (ImageView) convertView.findViewById(R.id.friends_image);
convertView.setTag(holder);
} else
holder = (ViewHolder) convertView.getTag();
holder.txt.setText(rowItem.getText());
String url = getItem(position).getUrl();
Picasso.with(context).load(url).into(holder.imageView);
holder.id.setText(rowItem.getId());
return convertView;
}
}
我有一个 listview
,我在 ListView
中从 json
(通过 asynctask
)加载每个用户的名字。
此外,用户图像也必须从服务器加载。这是通过第二个 ajax
请求发生的。当我得到 json
和 url 用于保存图像然后从服务器获取图像时,对于每个图像,通过 asynctask
触发一个请求。这使得 listview
的负载持续很长时间,因此其他活动会留在队列中,直到此任务完成。
我发现了如何将图像保存在内存缓存中。但这并不能解决问题,因为图像只有在我将应用程序置于后台时才会保存。
listview
包含一个名为 RowItem 的 custom adapter
,它包含一个 imageview
和两个 listviews
。
有什么建议吗?我现在为此工作了大约 1 天半...
谢谢!
这是我加载图像的异步任务。
public class ImageLoadTask extends AsyncTask<Void, Void, Bitmap> {
private final String LOG_TAG = ImageLoadTask.class.getSimpleName();
String url, userId;
String[] items;
BufferedReader reader = null;
public ImageLoadTask(String url, String userId, String[] items) {
this.url = url;
this.userId = userId;
this.items = items;
}
private String getImageUrlFromJson(String imageJson) throws JSONException {
JSONObject imageJsonOutput = new JSONObject(imageJson);
imageJsonUrl = imageJsonOutput.getString("imageUrl");
Log.v(LOG_TAG, imageJsonUrl);
return imageJsonUrl;
}
@Override
protected Bitmap doInBackground(Void... params) {
String imageJson = null;
try {
URL urlConnection = new URL(url + userId);
HttpURLConnection connection = (HttpURLConnection) urlConnection
.openConnection();
connection.setDoInput(true);
connection.connect();
InputStream input = connection.getInputStream();
StringBuffer buffer = new StringBuffer();
if (input == null) {
// Nothing to do.
//jsonStr = null;
return null;
}
reader = new BufferedReader(new InputStreamReader(input));
String line;
while ((line = reader.readLine()) != null) {
// Since it's JSON, adding a newline isn't necessary (it won't affect parsing)
// But it does make debugging a *lot* easier if you print out the completed
// buffer for debugging.
buffer.append(line + "\n");
}
if (buffer.length() == 0) {
return null;
}
imageJson = buffer.toString();
} catch (Exception e) {
e.printStackTrace();
}
try {
String imageUrl = getImageUrlFromJson(imageJson);
URL url = new URL(imageUrl);
bmp = BitmapFactory.decodeStream(url.openConnection().getInputStream());
addBitmapToMemoryCache(userId, bmp);
return bmp;
}
catch(Exception e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(Bitmap result) {
super.onPostExecute(result);
bmp = result;
item = new RowItem(bmp, item[0], item[1], item[2]);
mDiscoverAdapter.add(item);
}
}
您正在尝试通过不使用现有的图像加载库来重新发明轮子。查看一些顶级库:
如果你还执意要自己搭建。您需要根据需要创建一个从 memory/disk 到 save/load 的缓存系统。还要小心泄漏视图,因为这在图像加载(尤其是列表或网格)和方向更改时会变得非常棘手。
官方 android 文档有关于 Loading/Caching Images 的精彩教程。仔细阅读并查看他们提供的示例应用程序以帮助您入门。