这似乎是一个常见的问题,但我无法实现我找到的任何解决方案。我有一个Listview
带有自定义适配器,可以在一行中显示缩略图和文本字段。缩略图来自我之前创建的文件夹,并将我拍摄的照片放在我的应用程序中。
这是我的列表活动:
private LayoutInflater mInflater;
private Vector<RowData> data;
private CustomAdapter adapter;
private RowData rd;
static File path = Environment.getExternalStorageDirectory();
static File fnames = new File(path, "MyImages");
static String[] title = fnames.list();
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_blog);
mInflater = (LayoutInflater) getSystemService(
Activity.LAYOUT_INFLATER_SERVICE);
setListName();
data = new Vector<RowData>();
for(int i=0;i<title.length;i++){
try {
rd = new RowData(i,title[i]);
} catch (ParseException e) {
e.printStackTrace();
}
data.add(rd);
}
getListView().setTextFilterEnabled(true);
getListView().setScrollingCacheEnabled(false);
}
public void onRestart()
{
super.onRestart();
setListName();
}
private Vector<RowData> setListName()
{
data = new Vector<RowData>();
String[] title = fnames.list();
//get the databases textblog
DatabaseHandler db = new DatabaseHandler(this);
List<TextBlog> textBlogs = db.getAllText();
int positionRaw = textBlogs.size();
for (int i=0;i<textBlogs.size(); i++) {
rd = new RowData(i, textBlogs.get(i).getText());
data.add(rd);
}
for(int i=0;i<title.length;i++) {
try {
rd = new RowData(positionRaw,title[i]);
positionRaw++;
} catch (ParseException e) {
e.printStackTrace();
}
data.add(rd);
}
adapter = new CustomAdapter(this, R.layout.list,R.id.title, data);
setListAdapter(adapter);
getListView().setTextFilterEnabled(true);
adapter.notifyDataSetChanged();
return data;
}
//Create thumbnail from file picture
private Bitmap decodeFile(File f) {
try {
//Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(new FileInputStream(f),null,o);
//The new size we want to scale to
final int REQUIRED_SIZE=70;
//Find the correct scale value. It should be the power of 2.
int scale=1;
while (o.outWidth/scale/2>=REQUIRED_SIZE && o.outHeight/scale/2>=REQUIRED_SIZE)
scale*=2;
//Decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize=scale;
return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
} catch (FileNotFoundException e) {
}
return null;
}
//Set row object
private class RowData
{
protected int mId;
protected String mTitle;
RowData(int id,String title){
mId=id;
mTitle = title;
}
@Override
public String toString() {
return mId+" "+mTitle+" ";
}
这是我的自定义适配器:
public class CustomAdapter extends ArrayAdapter<RowData>
{
public CustomAdapter(Context context, int resource, int textViewResourceId,
List<RowData> objects)
{
super(context, resource, textViewResourceId, objects);
}
@Override
public View getView(int position, View convertView, ViewGroup parent)
{
ViewHolder holder = null;
TextView title = null;
ImageView thumb=null;
RowData rowData= getItem(position);
if(null == convertView) {
convertView = mInflater.inflate(R.layout.list, null);
holder = new ViewHolder(convertView);
convertView.setTag(holder);
}
holder = (ViewHolder) convertView.getTag();
title = holder.gettitle();
title.setText(rowData.mTitle);
thumb=holder.getImage();
File file = new File(path + "/MyImages/" + rowData.mTitle);
//Check what kind of file is it to add thumbnail
//Way too slow use asynchronous task
if (rowData.mTitle.substring(rowData.mTitle.lastIndexOf('.') + 1).equalsIgnoreCase("mp4") == true)
{
Bitmap thumbVideo = ThumbnailUtils.createVideoThumbnail(file.getAbsolutePath(), MediaStore.Video.Thumbnails.MICRO_KIND);
thumb.setImageBitmap(thumbVideo);
}
else if (rowData.mTitle.substring(rowData.mTitle.lastIndexOf('.') + 1).equalsIgnoreCase("3gpp") == true)
{
thumb.setImageDrawable(getResources().getDrawable(R.drawable.voice));
}
else
{
thumb.setImageBitmap(decodeFile(file));
}
return convertView;
}
private class ViewHolder {
private View mRow;
private TextView title = null;
private ImageView thumb=null;
public ViewHolder(View row) {
mRow = row;
}
public TextView gettitle() {
if(null == title) {
title = (TextView) mRow.findViewById(R.id.title);
}
return title;
}
public ImageView getImage() {
if (null == thumb) {
thumb = (ImageView) mRow.findViewById(R.id.img);
}
return thumb;
}
}
}
}
我很确定这是因为缩略图创建,我必须在AsynchTask
中实现它,但我尝试了任何成功。
任何人都可以建议我出错的地方,或者在列表上给我一些提示吗?
答案 0 :(得分:1)
您正在尝试在此处实现ViewHolder模式,但您的实现看起来不对。
这种模式的想法是减少对findViewById()
的调用,这会对您的表现产生影响。仅当行为null(convertView)时,您应该调用findViewById()
,否则重复使用setTag()
让我们来看看您的代码:
if(null == convertView){
convertView = mInflater.inflate(R.layout.list, null);
holder = new ViewHolder();
convertView.setTag(holder);
}
// .......
title = holder.gettitle();
// .........
thumb=holder.getImage();
请注意,在holder.getTitle()
语句后调用holder.getImage()
和if
。这意味着无论convertView
是否为空,都会每次调用它们
现在,看看这些getter,我们看到它们包含调用findViewById();
实施例。对于getTitle()
public TextView gettitle() {
if(null == title){
title = (TextView) mRow.findViewById(R.id.title);
}
return title;
}
所以,基本上,你不要在这里使用ViewHolder模式,只使用一些混合代码,最后每次调用findViewById()
都会降低ListView.
的性能
要正确执行此操作,只有在findViewById()
为空时才应调用convertView
。
例如:
if(null==convertView){
convertView = mInflater.inflate(R.layout.list, null);
holder = new ViewHolder();
// Getting a refernce to the views with findViewById()
title = holder.gettitle();
thumb=holder.getImage();
convertView.setTag(holder);
}else{
holder = (ViewHolder) convertView.getTag();
}
// Then you set the appropriate values to your views through the holder:
holder.title.setText("");
holder.thumb.setImageBitmap(...);
这是实现ViewHolder
模式
(PS:您需要将标题,拇指,...的访问修饰符更改为公开。)