这一定非常简单,我忽略了,但我有以下问题(帖子相当冗长,但我想提供尽可能多的信息:))。
我的Android应用程序中有一个gridview,每个单元格都有自定义视图:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<GridView
android:id = "@+id/photosGridView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:clickable="true"
android:drawSelectorOnTop="true"
android:focusable="true"
android:focusableInTouchMode="true"
android:numColumns="6"
android:columnWidth="90dp"
android:verticalSpacing="5dp"
android:horizontalSpacing="5dp"
android:stretchMode="columnWidth"
>
</GridView>
</RelativeLayout>
并且每个单元格都是
<?xml version="1.0" encoding="utf-8"?>
<com.myapp.widgets.ImageThumbView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background = "@android:color/transparent"
android:paddingLeft = "1dip"
android:paddingRight = "1dip"
android:paddingTop = "2dip"
android:paddingBottom = "2dip"
>
<ImageView
android:id="@+id/thumbImage"
android:layout_width="fill_parent"
android:layout_height = "fill_parent"
android:src="@drawable/icon_small"
/>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height = "fill_parent"
android:background = "@android:color/transparent"
>
<ImageView
android:id="@+id/iconRight"
android:layout_width="40px"
android:layout_height = "40px"
android:src="@drawable/album_check"
android:visibility="gone"
android:layout_alignParentTop = "true"
android:layout_alignParentRight = "true"
/>
<ImageView
android:id="@+id/iconLeft"
android:src="@drawable/album_check"
android:visibility="gone"
android:layout_width = "40px"
android:layout_height="40px"
android:layout_alignParentTop = "true"
android:layout_alignParentLeft = "true"
/>
</RelativeLayout>
</com.myapp.widgets.ImageThumbView>
我的适配器看起来像这样:
public class ImageAdapter extends BaseAdapter {
private List<String> mPictures = null;
public ImageAdapter(List<String> pictures) {
mPictures = pictures;
}
public int getCount() {
return mPictures != null ? mPictures.size() : 0;
}
public Object getItem(int position) {
return mPictures != null ? mPictures.get(position) : null;
}
public long getItemId(int position) {
return mPictures != null ? position : -1;
}
@Override
public View getView(int position,View convertView,ViewGroup parent)
{
ImageThumbView i = null;
try
{
Thread.sleep(100);
if (convertView == null)
{
String path = mPictures.get(position);
Log.d(((Integer)position).toString(), path);
i = addSingleView(_li, path);
TextView idx = (TextView) i.findViewById(R.id.caption);
if (idx != null)
idx.setText(((Integer)position).toString());
}
else
{
Log.d(((Integer)position).toString(), "ALREADY NOT NULL");
i = (ImageThumbView) convertView;
// These 2 lines were added only in desperate attempt to get it working, but it makes no difference
String path = mPictures.get(position);
i.updateView(path);
}
}
catch(InterruptedException ie)
{
ie.printStackTrace();
}
return i;
}
}
所以最初它正常工作,即它显示前18个图像和下一行的几个像素。但是当我开始滚动网格时,图像开始随机出现,即在最后一个图像之后,我从头开始看到很少,依此类推。出于好奇,我尝试了几个这样的样本:http://androidsamples.blogspot.com/2009/06/how-to-display-thumbnails-of-images.html ......并看到相同的结果。
那么,我做错了吗?为什么GridView会显示比预期更多的项目?为什么物品出现在错误的位置?
BR, 亚历
答案 0 :(得分:20)
实际上这里的问题是你在if或else中设置了“convertView”的内容。或者,在实例化视图后,如果它为null,则应始终执行此操作,并仅在返回视图之前设置内容。
因此,您确定视图的内容始终是正确的,使用位置更新,而不是使用错误的回收视图。
因此,您通常应该做以下事项:
(基于Android指南here中的教程)
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView;
if (convertView == null) {
imageView = new ImageView(mContext);
//just creating the view if not already present
} else {
imageView = (ImageView) convertView;
//re-using if already here
}
//here is the tricky part : set the content of the view out of the if, else
//just before returning the view
imageView.setImageResource(mThumbIds[position]);
return imageView;
}
答案 1 :(得分:10)
答案是回收视图。
一般来说,你的getView应该总是这样:
public class ImageAdapter extends BaseAdapter {
private List<String> mUrls; // put your urls here
private Map<String, Drawable> mImages; // cache your images here
public ImageAdapter() {
...
mUrls = new ArrayList<String>();
mImages = new HashMap<String, Drawable>();
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder; // Use the ViewHolder pattern for efficiency
if (convertView == null) {
// first time this view has been created so inflate our layout
convertView = View.inflate(this, R.layout.my_grid_item, null);
holder = new ViewHolder();
holder.image = convertView.findViewById(R.id.image);
holder.text = convertView.findViewById(R.id.text);
convertView.setTag(holder); // set the View holder
} else {
holder = (ViewHolder) convertView.getTag();
}
// update the current view - this must be done EVERY
// time getView is called due to view recycling
holder.text.setText(Integer.toString(position));
// check our cache for the downloaded image
final String url = mUrls.get(position);
if (mImages.get(url) != null)
holder.image.setImageDrawable(mImages.get(url));
else
loadImage(url, holder.image);
// return our view
return convertView;
}
public loadImage(final String url, final ImageView image) {
// load an image (maybe do this using an AsyncTask
// if you're loading from network
}
...
}
您的ViewHolder
课程类似于
public class ViewHolder {
ImageView thumbImage;
TextView text;
}
然后你不应该遇到任何问题。另外我不确定为什么你需要在你的getView中睡觉?这将减慢GridView的滚动速度。
答案 2 :(得分:3)
使用标准的Lazy Loader来获取图像,但永远不会更新onpostexecute,这会导致图像更新速度过快并获得您不想要的随机性。
我甚至使用了代码:
if (result != null && !mFlinging && myPosition < 12)
{
imageView.setImageBitmap(result);
}
int onpostexecute然后会为第一个屏幕正确更新图像,但是如果你扔掉图像屏幕然后再回到第一个屏幕再次获得随机性,那么我现在使用:
mPhotoView.setOnScrollListener(new OnScrollListener() {
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
// TODO Auto-generated method stub
}
public void onScrollStateChanged(AbsListView view, int scrollState) {
// TODO Auto-generated method stub
if(scrollState != SCROLL_STATE_IDLE) {
mAdapter.setFlinging(true);
} else {
mAdapter.setFlinging(false);
}
int first = view.getFirstVisiblePosition();
int count = view.getChildCount();
if (scrollState == SCROLL_STATE_IDLE || (first + count > mAdapter.getCount()) ) {
mPhotoView.invalidateViews();
}
}
});
更新视图。
答案 3 :(得分:0)
我遇到了同样的问题。 我正朝着在后台渲染视图的方向前进;
我正在研究这些代码,如果有帮助的话:
http://blog.tomgibara.com/post/7665158012/android-adapter-view-rendering