0

As my first Android project, I am creating an application that allows the user to display the cards from Magic The Gathering trading card game.

I am encountering an issue in my ArrayAdapter that displays an array of cards (according to an edition) in a listview.

I am reading a string which looks like this for example: {2}{B}{B} and creating ImageViews for each characters.. and I add those ImageViews to a LinearLayout display in the list.

The problem is that procedure is called everytime getView() is called so as long as I scroll down my list, the number of ImageViews endlessly increase. I would like that procedure to be called once and for all.

Any help would be very kind. Don't hesitate if you need further information.

Thanks! Rudz

package rudy.jaumain.mtgdb;

import java.util.ArrayList;

import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.content.Context;
import android.widget.TextView;
import android.graphics.Color;


public class MTGSetListAdapter extends ArrayAdapter<MTGCard> {

    private ArrayList<MTGCard> set;

    public MTGSetListAdapter(Context c, int resource, int textViewResourceId, ArrayList<MTGCard> set){
        super(c, resource, textViewResourceId, set);
        this.set = set;
    }

    static class ViewHolder{
        TextView name;
        ImageView rarity;
        LinearLayout manacost;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {



        ViewHolder holder;
        if(convertView == null){
            convertView = super.getView(position, convertView, parent);
            System.out.println("CONVERTVIEW IS NULL");
            holder = new ViewHolder();

            holder.name = (TextView)convertView.findViewById(R.id.editionlist_item_name);
            holder.rarity = (ImageView)convertView.findViewById(R.id.editionlist_item_rarity);
            holder.manacost = (LinearLayout)convertView.findViewById(R.id.editionlist_item_manacost); 

            convertView.setTag(holder);
        }
        else{
            System.out.println("CONVERTVIEW IS NOT NULL");
            holder = (ViewHolder)convertView.getTag();
        }

        MTGCard currentCard = this.set.get(position);
        if(currentCard != null){
            holder.name.setText(currentCard.getName());
            holder.name.setTextColor(Color.BLACK);
            //Manacost example : {2}{B}{B}
            String manacostStr = currentCard.getManacost();     
            int i=0;
            String currentMana = null;
            while(i < manacostStr.length()){
                char currentChar = manacostStr.charAt(i);
                if(currentChar == '{'){
                    currentMana = null;
                }
                else
                {
                    if(currentChar == '}'){
                        ImageView iv = new ImageView(getContext());
                        int idMana = getContext().getResources().getIdentifier("mana_"+currentMana.toLowerCase(), "drawable", getContext().getPackageName());
                        iv.setImageResource(idMana);
                        iv.setAdjustViewBounds(true);
                        holder.manacost.addView(iv);
                        currentMana = null;
                    }
                    else{
                        if(currentMana == null){
                            currentMana = String.valueOf(currentChar);
                        }
                        else{
                            currentMana += String.valueOf(currentChar);
                        }
                    }
                }
                i++;
            }

            String rarityStr = currentCard.getRarity().toLowerCase();
            int id = this.getContext().getResources().getIdentifier("rarity_"+rarityStr, "drawable", this.getContext().getPackageName());
            holder.rarity.setImageResource(id);
            /* COLOR SYMBOLS TO HANDLE LISTVIEW_ITEM BACKGROUNDCOLOR
             * 
             * Colored artifacts are not handled for now as : AG --> O
             * 
             * L : Land
             * B : Black
             * R : Red
             * W : White
             * G : Green
             * U : Blue
             * A : Artifact
             * O : Gold (2 colors or more)
             * C : DoubleSided Cards Back
             */
            boolean posIsPair = (position %2 == 0);
            int c;
            char color = '\0';
            if(currentCard.getColor().length()>1){
                if(currentCard.getColor().charAt(0) == 'A'){
                    color = currentCard.getColor().charAt(1);
                }
                else color = 'O';
            }
            else{
                color = currentCard.getColor().charAt(0);
            }
            switch(color){
            case 'L' :
                if(posIsPair)c = R.color.L1;
                else c = R.color.L2;
                break;
            case 'B' :
                if(posIsPair)c = R.color.B1;
                else c = R.color.B2;
                break;
            case 'R' :
                if(posIsPair)c = R.color.R1;
                else c = R.color.R2;
                break;
            case 'W' :
                if(posIsPair)c = R.color.W1;
                else c = R.color.W2;
                break;
            case 'G' :
                if(posIsPair)c = R.color.G1;
                else c = R.color.G2;
                break;
            case 'U' :
                if(posIsPair)c = R.color.U1;
                else c = R.color.U2;
                break;
            case 'A' :
                if(posIsPair)c = R.color.A1;
                else c = R.color.A2;
                break;
            case 'O' :
                if(posIsPair)c = R.color.O1;
                else c = R.color.O2;
                break;  
            case 'C' :
                c = Color.TRANSPARENT;
                break;  
            default :
                c = Color.TRANSPARENT;
                break;
            }
            convertView.setBackgroundColor(this.getContext().getResources().getColor(c));
        }
        return convertView;

    }

    @Override
    public int getCount() {
        return set.size();
    }

    @Override
    public MTGCard getItem(int arg0) {
        return set.get(arg0);
    }

}
Rudz17
  • 31
  • 1
  • 2
  • 3

1 Answers1

1

The ListView and its adapter try to create just enough views to support the elements of the list that are visible on-screen or while scrolling. You might have hundreds of objects in a ListView, but not all of them are attached to views at all times. When getView() is called, if enough view objects have already been created, the convertView parameter will provide you with one of those to repopulate for the row specified by the position argument.

Those view objects will already be populated not only with those views you store in your ViewHolder class, but any child views attached to them as well.

So in your "convertview is not null" case, you probably want to remove all the images which are children of holder.manacost. (Your code is only going to work correctly if the state of the pre-existing view hierarchy provided to you in convertView is identical to the views you create in the null convertView branch of your code.)

Alternatively, though this would be more complex, it may be appropriate to reuse those ImageView objects when repopulating the manacost view.

ajf
  • 31
  • 3