Category: Android

Android Gallery convertView is always null

As the title says, a long standing bug has been hindering experience for the developers who use Android’s out of the box solution for a Gallery component.

The problem actually lies inside the getView method which is inherited from BaseAdapter->Adapter. One of the parameters the method is expecting is a “recycled” instance of their adapter view, but it never arrives. It allows the developer to re-use the old view that was just swiped off the stage, instead of instantiating a new view. Instantiating a new view here is an expensive process during the time of scrolling. You want this time to be seamless to the user, not choppy if they scroll too fast back and forth. During every swipe, you quickly have to instantiate multiple instances while every view that falls off the viewing area literally falls into an abyss of nothingness, never to be seen again.

I solved this problem by managing my own Array of views in the Adapter class and indexed them based on position. Looking back at it now, it was somewhat of a lazy solution for reasons I go into below….but it works. 😉

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
    public SmallGameVO[] featuredItems;
 
    private SmallGameVO tempGame;
 
    private View[] viewArray;
 
    public FeaturedAdapter(Context c, SmallGameVO[] featuredGames) {
 		featuredItems = featuredGames;
 		viewArray =  new View[featuredItems.length];
    }
 
    public int getCount() {
        return featuredItems.length;
    }
 
    public Object getItem(int position) {
        return position;
    }
 
    public long getItemId(int position) {
        return position;
    }
 
 
    public View getView(int position, View convertView, ViewGroup parent) {	   	
  		LayoutInflater linflater = (LayoutInflater) parent.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);			
  		LinearLayout tempView = null;
 
                if(convertView != null){
    		        NVDebug.log("re-using the convertView!");
    		        tempView = convertView;
    	        }else{
                        //no convertView, need to do the heavy lifting ourselves
                        //check our viewArray to see if we have a view at the position or we need to create a new one
 
				if(viewArray[position] != null){					
					tempView = (LinearLayout) viewArray[i];
					break;					
				} else {					
					tempView = (LinearLayout) linflater.inflate(R.layout.feature_gallery_capsule, null);
					viewArray[position] = tempView;
					break;					
				}
			}	
    	         }
 
    	        NVWebImageView img = (NVWebImageView) tempView.findViewById(R.id.galleryImage);
 
		if(position <= featuredItems.length - 1){			
			tempGame = featuredItems[position];
			if(img.imageUrl != tempGame.getFeaturedImage()){
				img.setImageUrl(tempGame.getFeaturedImage());
				img.loadImage();
			}		
		}else{
			tempView = new LinearLayout(parent.getContext());
		}    	
 
        return tempView;
    }

This wouldn’t be the best idea for situations where you have a larger number of items(20+) in your gallery. In that situation, I would recommend implementing you’re own “cache” of views at your disposal. Depending on the size of the view, you really only have 4-5 views in the viewing area at one time, so it’s pretty easy to see how you could manage them swiping to the n-th scale if needed with an array of just 10 views. Luckily, my gallery will never go higher than 10-15.

So that’s it, nothing too fancy. Just instead of relying on the view to be there, waste some space and make your own array of views. 🙂

Android 2.2 -> Android 2.3 Rating Bar changes

There isn’t anything mentioned in the API differences or anywhere that I can find so far, on changes made to the underlying skin of the RatingBar component.

If you have a rating bar in your 2.2 project using Widget.RatingBar.Small as a parent for your custom skin, you’ll most likely see a weird background skin now surrounding your rating bar. This could be the AbsSeekBar or ProgressBar, but to me it looks like a ToggleButton. Regardless, it’s not your desired look and here’s how to get rid of it. Just remove the .Small from Widget.RatingBar.Small and make sure you have set min/max heights for your stars so they shrink or grow to your desired size.

ps. I’ll get an example once I get a good enough plugin that doesn’t crash my wordpress when I drop some XML in it. 🙂

Android Gallery and bad performance gotcha

If you’re using the Gallery component from android and experiencing “snappy” animations when your item is selected, you’re most likely doing too much in the UI thread OnItemSelected.

Always try and create a separate thread to do expensive tasks so your UI thread can keep the user happy. Also, look for ways to optimize what you’re trying to do in that method. For instance, instead of swapping out resources to reflect a UI update, make a stateful skin.