Android GridView loading the 0 indexed item in a later index's slot when data set changes -


using gridview extended baseadapter loading collection of relativelayouts contain image , caption. when user clicks on 1 of these items in gridview, should removed grid , replaced items behind it.

this works fine item other first 1 (index 0 in arraylist of items adapter manages).

on device i'm testing on, screen able display 12 items when screen scrolled top of grid (3 columns , 4 rows) last row cut off. 5th row isn't showing @ all. in situation, if click on first item (to remove it), of items fill in correctly, however, first item of 5th row (index 12) returns view of first item (index 0) instead of item @ index 12.

some screens explain issue:

step 1

clicking on brian mcknight remove him, , beck , rest fill in.

step 2

beck has filled in along rest, scroll down next row.

step 3

uh oh. beck there too. left partially scrolled can see both items have beck picture.

step 4

scrolling item 12 (row 5) out of view, down corrects problem.

this process other item in grid working correctly, item 0. did logging , found couple of things:

  • the getview(...) method object 0 called lot. when grid loads first time, called 3 times, whereas of other items called once.
  • when item other item 0 deleted, getview(...) position 0 called 19 times. 3 @ first, 16 more times after of other object's getview(...) method has been called.
  • when item 0 deleted, getview(...) method 0 called twice after scroll down 5th row (item 12). i'm thinking here issue occurring, because if can see correct item begin load in before being overwritten item @ position 0.

so i'm pretty sure 2 calls of getview(...) position 0, called when item @ index 12 appears, causing problem. don't know why getview(...) position 0 called @ time, , why decide overwrite item @ position 12.

i'll include code adapter below, think sufficient figure out problem.

public class popularartistsgridadapter extends baseadapter {      private arraylist<artistslistitem> martists = new arraylist<artistslistitem>();     private layoutinflater minflater;     private context mcontext;      private int mremovedindex = -1;     private int mrefresher = -1;     private int mlastvisible = -1;      public popularartistsgridadapter(context context) {         mcontext = context;         minflater = (layoutinflater) context.getsystemservice(context.layout_inflater_service);     }      public void setitems(arraylist<artistslistitem> artists) {         if(artists == null)             throw new nullpointerexception();          martists = artists;         notifydatasetchanged();     }      @override     public int getcount() {         return martists.size();     }      public void removeitem(int position, int lastvisible) {         mlastvisible = lastvisible;          mremovedindex = position;         mrefresher = mremovedindex;          martists.remove(position);         notifydatasetchanged();     }      public void additem(int position) {         artistslistitem item = getitem(position);          martists.add(0, item);         notifydatasetchanged();     }      @override     public artistslistitem getitem(int position) {         return martists.get(position);     }      @override     public long getitemid(int position) {         return position;     }      private void iteraterefresher() {         mrefresher++;          if(mrefresher > mlastvisible) {             mremovedindex = -1;             mrefresher = -1;             mlastvisible = -1;         }     }      @override     public view getview(final int position, view convertview, viewgroup parent) {          final artistslistitem item = getitem(position);          if(convertview == null)             convertview = minflater.inflate(r.layout.popular_artist_item, null);          final textview tv = (textview) convertview.findviewbyid(r.id.pai_stupid_bubble_button);         final imageview iv = (imageview) convertview.findviewbyid(r.id.pai_image);          final bitmapdrawable drawable = drawablemanager.fetchbitmapdrawable(mcontext, item.getimageurl(), true, false);          iv.invalidate();         tv.invalidate();          if(mrefresher >= 0 && position >= mrefresher) {             animation anim = animationutils.loadanimation(mcontext, r.anim.grid_item_fadein);             anim.setanimationlistener(new animationlistener() {                  @override                 public void onanimationstart(animation animation) {                     iv.setimagedrawable(drawable);                     tv.settext(item.getname());                 }                  @override                 public void onanimationrepeat(animation animation) {                     // todo auto-generated method stub                  }                  @override                 public void onanimationend(animation animation) {                     // todo auto-generated method stub                  }             });              anim.setstartoffset(300 + (50 * (position - mremovedindex)));              convertview.startanimation(anim);             iteraterefresher();         }         else {             iv.setimagedrawable(drawable);             tv.settext(item.getname());         }          return convertview;     }  } 

the refresher made allow visible items on screen fade in when replacing removed item. if sees here suspect, or has other ideas why happening, i'd appreciate help. thanks!

the issue due animation using fade view. start animation offset of @ least 350msec. means animation won't run until amount of time has elapsed. problem arises in onanimationstart method of animationlistener. referencing local variables , manipulating them. things go wrong.

this bit tricky explain, try follow along. time onanimationstart has been called first time getview have been called many times. since item views recycled (that's convertview is), time onanimationstart invoked view referencing @ different position.

crude illustration:

// views being held adapter after first pass. view0 --> onscreenitemtematposition0 view1 --> onscreenitemtematposition1 view2 --> onscreenitemtematposition2  // schedule animation, listener uses view0 reference  // scrolling occurs, item0 goes offscreen view0 --> onscreenitemtematposition3 // view0 being used in new position onscreen view1 --> onscreenitemtematposition1 view2 --> onscreenitemtematposition2  // onanimationstart triggers , mutates view0 // !!!! boom !!! view0 being used onscreen item @ position 3 // isn't want because drawable in case item 0 

as can see tricky situation. 1 solution let animationlistener know position of view intending mutate can reconcile view mutate.

roughly:

class myanimationlistener extends animationlistener {     private int positiontomutate;      public myanimationlistener(int positiontomutate) {         this.positiontomutate = positiontomutate;     }      @override     public void onanimationstart(animation animation) {         integer viewposition = (integer)localconvertview.gettag(); // add getview final view localconvertview         if (positiontomutate == viewposition) {             iv.setimagedrawable(drawable);             tv.settext(item.getname());         }     }     // rest of methods } 

and in getview method update convertview's tag position info:

final view localconvertview = convertview; localconvertview.settag(new integer(position)); 

this ensure animation listener knows whether should mutate view or not.


Comments

Popular posts from this blog

ios - iPhone/iPad different view orientations in different views , and apple approval process -

java Extracting Zip file -

C# WinForm - loading screen -