Android GridView Scrolling Problem

It should be very simple, I miss, but I have the following problem (the message is quite long, but I want to provide as much information as possible :)).

I have a gridview in my android application where each cell contains a custom view:

<?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> 

and each cell

 <?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> 

My adapter looks like this:

 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; } } 

So, initially it works correctly, i.e. displays the first 18 images and a few pixels from the next line. But when I start scrolling the grid, the images begin to appear randomly, that is, after the last image, I see some from the very beginning and so on. Out of curiosity, I tried several examples like this: http://androidsamples.blogspot.com/2009/06/how-to-display-thumbnails-of-images.html ... and see the same result.

So am I doing something wrong? why on earth does a gridview display more items than it is supposed to? and why are the elements displayed in the wrong positions?

BR, Alex

+7
source share
5 answers

Actually the problem is that you set the contents of "convertView" to if or else. Or you should always do this after creating an instance of the view, if it is null, and set the content only before returning the view.

Therefore, you are sure that the content of the view is always correct, updated using the position, and not a false secondary view.

So you should do the following:
(based on guidance from Android Guide 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; } 
+20
source

The answer is species recycling.

In general, your getView should always be something like:

 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 } ... } 

Where your ViewHolder class will look something like

 public class ViewHolder { ImageView thumbImage; TextView text; } 

Then you should not run into any problems. Also I'm not sure why you need to sleep in your getView? This will slow down the scrolling of your gridview.

+10
source

Use the standard Lazy Loader to capture images, but never refresh onpostexecute, which causes the images to refresh too quickly and get randomness that you don't want.

I even used the code:

 if (result != null && !mFlinging && myPosition < 12) { imageView.setImageBitmap(result); } 

int onpostexecute, which then correctly updates the images for the first screen, but if you go to the image screen, return too quickly for the first screen to get random again, so now I use:

 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(); } } }); 

to update the view.

+3
source

I have the same problem. I am moving towards rendering views in the background;

I study these codes if I should help:

http://blog.tomgibara.com/post/7665158012/android-adapter-view-rendering

https://github.com/desertjim/LazyLoadingGridView

0
source

guys, to avoid this problem, always return the newly created object in getView ()

 public View getView(int position, View convertView, ViewGroup parent) { ImageView imageView; TextView textView; LinearLayout linearlayout = new LinearLayout(mContext); //if (convertView == null) { imageView = new ImageView(mContext); textView = new TextView(mContext); //imageView.setLayoutParams(new GridView.LayoutParams(85, 85)); imageView.setAdjustViewBounds(false); imageView.setScaleType(ImageView.ScaleType.CENTER_CROP); imageView.setPadding(4, 8, 8, 8); imageView.setBackgroundResource(mThumbIds[position]); textView.setText(mThumbText[position]); textView.setGravity(0x01); textView.setMaxLines(2); //textView.setPadding(20, 0, 0, 0); linearlayout.addView(imageView,0); linearlayout.addView(textView,1); linearlayout.setPadding(4, 4, 4, 4); linearlayout.setOrientation(LinearLayout.VERTICAL); linearlayout.setGravity(0x01); // } else { //linearlayout = (LinearLayout) convertView; //} return linearlayout; } 
-8
source

All Articles