Gist:自定义适配器通过数据库中的文件路径间接获取文件资源。低效/记忆问题。您的意见要求。
对所有搜索,相关链接以及有用的主题的引用都在帖子底部。
以下代码,但有几个因素值得关注。需要一些更有经验的眼睛,请建议改善或潜在的错误,以避免。应用不需要是内容提供商(仅限应用于本地的数据)。有问题的ListView将非常轻量级,只有大约5到10个条目。 (我遗漏了数据库的东西,因为它有效。)
概述:
文件不在数据库中使得它与普通的SimpleCursorAdapter不同 - 必须拉动图像文件。添加了在填充listview之前将其制作成缩略图的开销。
如上所述,它很轻,但即使只有一两个条目,虚拟机也会出现问题。我怀疑这是与Bitmaps相关的所有内存抖动:
08-27 19:53:14.273: I/dalvikvm-heap(11900): Grow heap (frag case) to 4.075MB for 1228816-byte allocation
08-27 19:53:14.393: D/dalvikvm(11900): GC_CONCURRENT freed <1K, 5% free 4032K/4244K, paused 13ms+3ms, total 116ms
/* myTextAndImageCursorAdapter.java */
import android.widget.SimpleCursorAdapter;
//import android.support.v4.widget.SimpleCursorAdapter;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.database.Cursor;
import java.io.File;
import android.widget.ImageView;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import static android.media.ThumbnailUtils.extractThumbnail;
public class TextAndImageCursorAdapter extends SimpleCursorAdapter {
private Context context;
private int layout;
public TextAndImageCursorAdapter (Context ctx, int layout, Cursor c, String[] from, int[] to) {
super(context, layout, c, from, to);
this.context = ctx;
this.layout = layout;
}
@Override
public View newView(Context ctx, Cursor cursor, ViewGroup parent) {
Cursor c = getCursor();
final LayoutInflater inflater = LayoutInflater.from(ctx);
View vView = inflater.inflate(layout, parent, false);
int iCol_Text = c.getColumnIndex(DBCOL_TEXT);
int iCol_Image = c.getColumnIndex(DBCOL_IMAGE);
String sText = c.getString(iCol_Text);
String sFileAndPath_Image = c.getString (iCol_Image); //// sImage path & file
TextView tvText = (TextView) v.findViewById(R.id.gui_text);
if (tvText != null) {
tvText.setText(sSomeText);
}
ImageView ivImage (ImageView) v.findViewById(R.id.gui_image);
if (ivImage != null) {
ivImage.setImage (mySetImage (sFileAndPath_Image) );
}
return vView;
}
@Override
public void bindView(View v, Context ctx, Cursor c) {
//// ( like newView(), without an inflater, view, or return )
int iCol_Text = c.getColumnIndex(DBCOL_TEXT);
int iCol_Image = c.getColumnIndex(DBCOL_IMAGE);
String sText = c.getString(iCol_Text);
String sFileAndPath_Image = c.getString (iCol_Image); //// path & file
TextView tvText = (TextView) v.findViewById(R.id.gui_text);
if (tvText != null) {
tvText.setText(sSomeText);
}
ImageView ivImage (ImageView) v.findViewById(R.id.gui_image);
if (ivImage != null) {
ivImage.setImageBitmap ( mySetImage ( sFileAndPath_Image ) ) ;
}
}
/////
/////
protected Bitmap mySetImage ( String path ) {
int width = 60; int height = 40 ;
File imgFile = new File ( path ); //// usually like: \sdcard0\wherever\filename1234.bmp
Bitmap myBitmap = null;
if( imgFile.exists() )
{
myBitmap = BitmapFactory.decodeFile ( imgFile.getAbsolutePath () );
}
else
Log.d ("oops", "no image file ... using default.");
myBitmap = getTheDefaultImage (); //// not shown - this is arbitrary
}
imgFile.close();
return ( extractThumbnail ( myBitmap, width, height ) ) ;
}
}
[编辑 - 添加链接] 搜索条件: “ Android自定义simplecursoradapter与文件中的图像与数据库中的路径 “
最近的点击,但尝试从res中提取图像,而不是从外部/ sd存储(未应答): SimpleCursorAdapter how to show an image?
也是一个接近命中/错过 - 类似的算法(未答复)引用4): Customizing list shown from SimpleCursorAdapter using ViewBinder
差不多,但OP的代码不起作用,(没有正常工作的答案): Load Image in a custom list by SimpleCursorAdapter
为OP工作,但使用JSON进行远程检索,而不是本地(可能这可以调整,但我不清楚如何)。 How to show images in imageview in simple adapter?
不完全,但又一次关闭: ListView scroll slow while loading image from Internal Storage
Image Loader问题(参考文献2): Imageloader not loading image on real device
相关链接:
Android: Issue with newView and bindView in custom SimpleCursorAdapter
同样命名的匹配,但与我的具体问题无关 - 这些通常指的是应用内资源: show image from database where you saved the path of image
Custom SimpleCursorAdapter error
Custom SimpleCursorAdapter, database query and NullPointerException
nullPointerException with extended SimpleCursorAdapter
Android SimpleCursorAdapter - Adding conditional images
外部参考:
0)简单介绍自定义游标适配器 http://thinkandroid.wordpress.com/2010/01/11/custom-cursoradapters/
1)Romain Guy - 基本布局... 2 txts,1张图片 http://www.curious-creature.org/2009/02/22/android-layout-tricks-1/
2)AQuery(Android查询) http://code.google.com/p/android-query/wiki/ImageLoading
3)Android缩略图 http://developer.android.com/reference/android/media/ThumbnailUtils.html
4)客户。列表视图带有“开/关”星形图像: http://enjoyandroid.wordpress.com/2012/03/12/customizing-simple-cursor-adapter/
答案 0 :(得分:5)
你可以做两件事:
1)使用ViewHolder模式,缓存LayoutInfalter,最重要的是:不要绑定数据两次:
/* ... imports */
import static android.media.ThumbnailUtils.extractThumbnail;
public class TextAndImageCursorAdapter extends SimpleCursorAdapter {
private LayoutInflater mLayoutInflater;
private Context context;
private int layout;
private class ViewHolder {
TextView textView;
ImageView imageView;
ViewHolder(View v) {
textView = (TextView) v.findViewById(R.id.gui_text);
imageView = (ImageView) v.findViewById(R.id.gui_image);
}
}
public TextAndImageCursorAdapter (Context ctx, int layout, Cursor c, String[] from, int[] to) {
super(ctx, layout, c, from, to);
this.context = ctx;
this.layout = layout;
mLayoutInflater = LayoutInflater.from(ctx);
}
@Override
public View newView(Context ctx, Cursor cursor, ViewGroup parent) {
View vView = mLayoutInflater.inflate(layout, parent, false);
vView.setTag( new ViewHolder(vView) );
// no need to bind data here. you do in later
return vView;// **EDITED:**need to return the view
}
@Override
public void bindView(View v, Context ctx, Cursor c) {
// you might want to cache these too
int iCol_Text = c.getColumnIndex(DBCOL_TEXT);
int iCol_Image = c.getColumnIndex(DBCOL_IMAGE);
String sText = c.getString(iCol_Text);
String sFileAndPath_Image = c.getString (iCol_Image); //// path & file
ViewHolder vh = (ViewHolder) v.getTag();
vh.textView.setText(sSomeText);
vh.imageView.setImageBitmap ( mySetImage ( sFileAndPath_Image ) );
}
}
2)这非常重要:不要在每个绑定上创建缩略图。你需要缓存结果:
private void setThumbnail(String path, Bitmap b) {
// save thumbnail to some kind of cache
// see comment below
}
private Bitmap getThumbnail(String path) {
Bitmap thumbnail = null;
// try to fetch the thumbnail from some kind of cache
// see comment below
return thumbnail;
}
protected Bitmap mySetImage ( String path ) {
int width = 60; int height = 40 ;
Bitmap thumbnail = getThumbnail(path); // try to fetch thumbnail
if (thumbnail != null) return thumbnail;
File imgFile = new File ( path ); //// usually like: /sdcard/wherever/filename1234.bmp
Bitmap myBitmap = null;
if( imgFile.exists() ) {
myBitmap = BitmapFactory.decodeFile ( imgFile.getAbsolutePath () );
} else {
Log.d ("oops", "no image file ... using default.");
myBitmap = getTheDefaultImage (); //// not shown - this is arbitrary
}
imgFile.close();
thumbnail = extractThumbnail ( myBitmap, width, height );
myBitmap.recycle();
setThumbnail(path, thumbnail); // save thumbnail for later reuse
return thumbnail;
}
根据您的使用情况,您希望使用某种LruCache填充getThumbnail()
和setThumbnail()
:
编辑:
@Override
public View newView(Context ctx, Cursor cursor, ViewGroup parent) {
View vView = mLayoutInflater.inflate(layout, parent, false);
vView.setTag( new ViewHolder(vView) );
// no need to bind data here. you do in later
return vView;// **EDITED:**need to return the view
}