Java 无法在RemoteViewsFactory中加载多个图像
我正在创建一个简单的Android小部件,从网站上获取并显示一些电影封面。显示图像的是简单的Java 无法在RemoteViewsFactory中加载多个图像,java,android,android-gridview,android-appwidget,android-remoteview,Java,Android,Android Gridview,Android Appwidget,Android Remoteview,我正在创建一个简单的Android小部件,从网站上获取并显示一些电影封面。显示图像的是简单的GridView。该小部件工作正常,但当我开始滚动时,我得到并OutOfMemoryError,Android终止了我的进程 这是我的RemoteViewsFactory的代码。我似乎不明白如何解决这个问题。我使用的图像大小合适,所以我不会在Android中浪费内存。它们的尺寸非常合适。正如您所见,我使用的是一个非常小的LRU缓存,在清单中,我甚至启用了android:largeHeap=“true”。我
GridView
。该小部件工作正常,但当我开始滚动时,我得到并OutOfMemoryError
,Android终止了我的进程
这是我的RemoteViewsFactory
的代码。我似乎不明白如何解决这个问题。我使用的图像大小合适,所以我不会在Android中浪费内存。它们的尺寸非常合适。正如您所见,我使用的是一个非常小的LRU缓存,在清单中,我甚至启用了android:largeHeap=“true”
。我在这个问题上绞尽脑汁已经整整两天了,我想知道我想做的事情是否可能
public class SlideFactory implements RemoteViewsFactory {
private JSONArray jsoMovies = new JSONArray();
private Context ctxContext;
private Integer intInstance;
private RemoteViews remView;
private LruCache<String, Bitmap> lruCache;
private static String strCouch = "http://192.168.1.110:5984/movies/";
public SlideFactory(Context ctxContext, Intent ittIntent) {
this.ctxContext = ctxContext;
this.intInstance = ittIntent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
this.lruCache = new LruCache<String, Bitmap>(4 * 1024 * 1024);
final Integer intMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
final Integer intBuffer = intMemory / 8;
lruCache = new LruCache<String, Bitmap>(intBuffer) {
@Override
protected int sizeOf(String strDigest, Bitmap bmpCover) {
return bmpCover.getByteCount() / 1024;
}
};
}
public RemoteViews getViewAt(int intPosition) {
if (intPosition <= getCount()) {
try {
String strDocid = this.jsoMovies.getJSONObject(intPosition).getString("id");
String strDigest = this.jsoMovies.getJSONObject(intPosition).getJSONObject("value").getJSONObject("_attachments").getJSONObject("thumb.jpg").getString("digest");
String strTitle = this.jsoMovies.getJSONObject(intPosition).getJSONObject("value").getString("title");
Bitmap bmpThumb = this.lruCache.get(strDigest);
if (bmpThumb == null) {
String strUrl = strCouch + strDocid + "/thumb.jpg";
System.out.println("Fetching" + intPosition);
bmpThumb = new ImageFetcher().execute(strUrl).get();
this.lruCache.put(strDigest, bmpThumb);
}
remView.setImageViewBitmap(R.id.movie_cover, bmpThumb);
remView.setTextViewText(R.id.movie_title, strTitle);
} catch (Exception e) {
e.printStackTrace();
}
return remView;
}
return null;
}
public void onCreate() {
return;
}
public void onDestroy() {
jsoMovies = null;
}
public int getCount() {
return 20;
}
public RemoteViews getLoadingView() {
return null;//new RemoteViews(this.ctxContext.getPackageName(), R.layout.loading);
}
public int getViewTypeCount() {
return 1;
}
public long getItemId(int intPosition) {
return intPosition;
}
public boolean hasStableIds() {
return true;
}
public void onDataSetChanged() {
this.remView = new RemoteViews(this.ctxContext.getPackageName(), R.layout.slide);
try {
DefaultHttpClient dhcNetwork = new DefaultHttpClient();
String strUrl = strCouch + "_design/application/_view/language?" + URLEncoder.encode("descending=true&startkey=[\"hi\", {}]&attachments=true");
HttpGet getMovies = new HttpGet(strUrl);
HttpResponse resMovies = dhcNetwork.execute(getMovies);
Integer intMovies = resMovies.getStatusLine().getStatusCode();
if (intMovies != HttpStatus.SC_OK) {
throw new HttpResponseException(intMovies, "Server responded with an error");
}
String strMovies = EntityUtils.toString(resMovies.getEntity(), "UTF-8");
this.jsoMovies = new JSONObject(strMovies).getJSONArray("rows");
} catch (Exception e) {
Log.e("SlideFactory", "Unknown error encountered", e);
}
}
}
我也有过类似的痛苦经历,经过大量挖掘,我发现
setImageViewBitmap
将所有位图复制到新实例中,因此占用了双内存。
考虑将下面的行更改为静态资源或其他内容!
remView.setImageViewBitmap(R.id.movie_cover, bmpThumb);
这需要大量内存和ping垃圾收集器来清理内存,但速度太慢,应用程序无法及时使用释放的内存。我的解决方法是使用LRUCache存储小部件的位图: 首先,像往常一样初始化:
protected void initializeCache()
{
final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
// Use 1/10th of the available memory for this memory cache.
final int cacheSize = maxMemory / 10;
bitmapLruCache = new LruCache<String, Bitmap>(cacheSize)
{
@Override
protected int sizeOf(String key, Bitmap bitmap) {
// The cache size will be measured in kilobytes rather than
// number of items.
return bitmap.getByteCount() / 1024;
}
};
}
使用此代码,小部件现在不会使我的应用程序崩溃
更多信息@commonware,你能解释一下吗?你总是有答案的。:)谢谢。你能发布一些logcat输出吗?@MridangAgarwalla你能发布
ImageFetcher
的代码吗?你还可以提到你正在加载的图像的大小(或者可能是其中最大的图像的大小)…@AmulyaKhare,我已经发布了ImageFetcher
的源代码。我可以使用样本大小,但它大大降低了质量。我的图像都是250x375像素。我将println
放入方法getViewAt
中,注意到Android试图一次加载所有图像,即使在GridView
中只有少数图像可见。我认为这些用于列表视图
、网格视图
和堆栈视图
的适配器的工作方式是,它们只预加载一些项目,而当用户滚动并失去焦点时,安卓就会丢弃旧的布局。我不明白为什么它会尝试加载所有项目。这个this.lruCache=新的lruCache(4*1024*1024)代码>行是无用的。因为我从远程服务器下载图像,我如何创建静态引用。静态引用是指可提取文件夹中的资产吗?如果您可以链接到Android源代码,在那里您发现了使用setImageViewBitmap
方法的问题,那就太好了。谢谢@avebrahimi谢谢!这真的拯救了这一天@Idangagarwalla先生,你能发布你的解决方案吗?我认为问题还没有解决。如果您找到了解决方案,请发布!
protected void initializeCache()
{
final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
// Use 1/10th of the available memory for this memory cache.
final int cacheSize = maxMemory / 10;
bitmapLruCache = new LruCache<String, Bitmap>(cacheSize)
{
@Override
protected int sizeOf(String key, Bitmap bitmap) {
// The cache size will be measured in kilobytes rather than
// number of items.
return bitmap.getByteCount() / 1024;
}
};
}
void updateImageView(RemoteViews views, int resourceId, final String imageUrl)
{
Bitmap bitmap = bitmapLruCache.get(imageUrl);
if (bitmap == null)
{
bitmap = // get bitmap from web with your loader
bitmapLruCache.put(imageUrl, bitmap);
}
views.setImageViewBitmap(resourceId, bitmap);
}