I recently decided to convert my simple ListView into a Separted List
View in order to categorize by list items. After creating my custom
ArrayAdapter to hold each section within my List
I noticed that adding sections and items to my ListView containing
default data when my application loads works fine. However, when I
call my update function to remove default data and append data from
background server communications my application crashes with a
ArrayIndexOutOfBoundsException.

I've searched the net and found a few others with similar issues but
found no solutions. I'm thinking it has to do with my getView of the
Custom ArrayAdapter I created (PlayerArrayAdapter).

After logging, I noticed that the first section returns views
correctly, however after the first list item of the second category
(section) is created, I get the exception. My initial thoughts were
that I was attempting to access data that did not exists, however that
was not the case as you can see below in my log:

(Data contained in first section's arrayAdapter)
04-05 04:19:18.939: WARN/PlayerArrayAdapter.getView(15716): 0.
playerID=DE8574E5-603C-4E8B-94B4-36F9BD4FD546
04-05 04:19:18.939: WARN/PlayerArrayAdapter.getView(15716): 1.
playerID=DE7574E5-603C-4E8B-94B4-36F9BD4FD546

(Creating View for first List Item)
04-05 04:19:18.939: WARN/PlayerArrayAdapter.getView(15716): Getting
view for Pos=0 View=null parent=android.widget.ListView@44ea39f0
04-05 04:19:18.989: WARN/PlayerArrayAdapter.getView(15716):  -- PARSED
A PLAYER: playerID=DE8574E5-603C-4E8B-94B4-36F9BD4FD546
(Returned a View for first List Item)
04-05 04:19:19.039: WARN/PlayerArrayAdapter.getView(15716):  --
CREATED NEW VIEW: playerID=DE8574E5-603C-4E8B-94B4-36F9BD4FD546

(Data contained in first section's arrayAdapter)
04-05 04:19:19.099: WARN/PlayerArrayAdapter.getView(15716): 0.
playerID=DE8574E5-603C-4E8B-94B4-36F9BD4FD546
04-05 04:19:19.099: WARN/PlayerArrayAdapter.getView(15716): 1.
playerID=DE7574E5-603C-4E8B-94B4-36F9BD4FD546

(Reusing View (convertView) from first item for second List Item)
04-05 04:19:19.099: WARN/PlayerArrayAdapter.getView(15716): Getting
view for Pos=1 View=android.widget.LinearLayout@44f1ca30
parent=android.widget.ListView@44ea39f0
04-05 04:19:19.109: WARN/PlayerArrayAdapter.getView(15716): Convert
view from ViewHolder.pos=0 for pos=1
04-05 04:19:19.109: WARN/PlayerArrayAdapter.getView(15716):  -- PARSED
A PLAYER: playerID=DE7574E5-603C-4E8B-94B4-36F9BD4FD546

(Returned a view reused view for second list item)
04-05 04:19:19.279: WARN/PlayerArrayAdapter.getView(15716):  --
CREATED NEW VIEW: playerID=DE7574E5-603C-4E8B-94B4-36F9BD4FD546

(Data contained in second section/category)
04-05 04:19:19.309: WARN/PlayerArrayAdapter.getView(15716): 0.
playerID=2791CB11-6B61-48A6-94AB-E888D745E048
04-05 04:19:19.319: WARN/PlayerArrayAdapter.getView(15716): 1.
playerID=77EE8049-2909-4F17-BB9E-A1BDC576AEBF
04-05 04:19:19.329: WARN/PlayerArrayAdapter.getView(15716): 2.
playerID=9AC5F033-5014-4FB6-B5DD-E9087858DFFA
04-05 04:19:19.329: WARN/PlayerArrayAdapter.getView(15716): 3.
playerID=ED9CB89B-0252-4E72-B3F5-CC00978B49DF

(Parses, creates and returns a view for the first item since
convertView == null)
04-05 04:19:19.339: WARN/PlayerArrayAdapter.getView(15716): Getting
view for Pos=0 View=null parent=android.widget.ListView@44ea39f0
04-05 04:19:19.359: WARN/PlayerArrayAdapter.getView(15716):  -- PARSED
A PLAYER: playerID=2791CB11-6B61-48A6-94AB-E888D745E048
04-05 04:19:19.389: WARN/PlayerArrayAdapter.getView(15716):  --
CREATED NEW VIEW: playerID=2791CB11-6B61-48A6-94AB-E888D745E048

[[[Then I get this error ]]]
04-05 04:19:19.460: ERROR/AndroidRuntime(15716): FATAL EXCEPTION: main
04-05 04:19:19.460: ERROR/AndroidRuntime(15716):
java.lang.ArrayIndexOutOfBoundsException
04-05 04:19:19.460: ERROR/AndroidRuntime(15716):     at
android.widget.AbsListView$RecycleBin.addScrapView(AbsListView.java:
4078)
04-05 04:19:19.460: ERROR/AndroidRuntime(15716):     at
android.widget.ListView.measureHeightOfChildren(ListView.java:1210)
04-05 04:19:19.460: ERROR/AndroidRuntime(15716):     at
android.widget.ListView.onMeasure(ListView.java:1109)
04-05 04:19:19.460: ERROR/AndroidRuntime(15716):     at
android.view.View.measure(View.java:8171)
04-05 04:19:19.460: ERROR/AndroidRuntime(15716):     at
android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:3132)
04-05 04:19:19.460: ERROR/AndroidRuntime(15716):     at
android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:
1012)
04-05 04:19:19.460: ERROR/AndroidRuntime(15716):     at
android.widget.LinearLayout.measureVertical(LinearLayout.java:381)
04-05 04:19:19.460: ERROR/AndroidRuntime(15716):     at
android.widget.LinearLayout.onMeasure(LinearLayout.java:304)
04-05 04:19:19.460: ERROR/AndroidRuntime(15716):     at
android.view.View.measure(View.java:8171)
04-05 04:19:19.460: ERROR/AndroidRuntime(15716):     at
android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:3132)
04-05 04:19:19.460: ERROR/AndroidRuntime(15716):     at
android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:
1012)
04-05 04:19:19.460: ERROR/AndroidRuntime(15716):     at
android.widget.LinearLayout.measureVertical(LinearLayout.java:381)
04-05 04:19:19.460: ERROR/AndroidRuntime(15716):     at
android.widget.LinearLayout.onMeasure(LinearLayout.java:304)
04-05 04:19:19.460: ERROR/AndroidRuntime(15716):     at
android.view.View.measure(View.java:8171)
04-05 04:19:19.460: ERROR/AndroidRuntime(15716):     at
android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:3132)
04-05 04:19:19.460: ERROR/AndroidRuntime(15716):     at
android.widget.FrameLayout.onMeasure(FrameLayout.java:245)
04-05 04:19:19.460: ERROR/AndroidRuntime(15716):     at
android.view.View.measure(View.java:8171)
04-05 04:19:19.460: ERROR/AndroidRuntime(15716):     at
android.widget.LinearLayout.measureVertical(LinearLayout.java:526)
04-05 04:19:19.460: ERROR/AndroidRuntime(15716):     at
android.widget.LinearLayout.onMeasure(LinearLayout.java:304)

Here is my update and clearData functions added to the Jeff's list
adapter:

        /*
                 * Used to clear contents of this Instance before updating.
                 */

                public void clearData()
                {
                        final String CONTEXT = CLASS_NAME+".clearData()";

                        Log.i(CONTEXT, "** Separated List Adapter Cleared **");
                        sections.clear();
                        headers.clear();
                        this.notifyDataSetInvalidated();
                }

            /**
             * Used to update the data in our view
             * @param response - GenereicInViewPlayerInfoResponse Instance
containing new player Data
             */

            public void update(Map <String,PlayerInfo[]> m)
            {
                        final String CONTEXT = CLASS_NAME+".update(PlayerInfo)";

                        int playerCount = 0;
                        if (m != null && !m.isEmpty())
                        {
                        this.clearData();                                       
                        // Clear Adapter data
contents
                        PlayerInfo [] data;
                        for(Object title : m.keySet())
                                {
                                        data = m.get(title);
                                        Log.i(CONTEXT, "Adding New Category: " 
+ (String)title + "
- contains " + data.length + " players.");

                                        for(int x=0;x<data.length;x++)
                                        {
                                                Log.i(CONTEXT, 
data[x].toString());
                                        }
                                        Log.i(CONTEXT, "Num of players added: " 
+ data.length);
                                        playerCount += data.length;

                                        this.addSection((String)title,
                                                new 
PlayerArrayAdapter((Activity)context,
R.layout.playerinfoadapter,data));      // Add data to Separated ListView

                                }
                        notifyDataSetChanged();
                        if (AppMain.isLogi) Log.i(CONTEXT,"Updated view with "+
playerCount +" PlayerInfos");
                        }
                        else{
                                if (AppMain.isLogi) Log.i(CONTEXT,"No data 
found to update");
                        }
            }

            /**
             * Used to update the data in our view
             * @param str - String Array contain data to update view
             */
            public void update(String [] str) {
                        final String CONTEXT = CLASS_NAME+".update(String [])";

                        System.out.println("Array of Strings outputted, No 
Content
Found");

                        int playerCount = str.length;
                        if(str != null && str.length > 0)
                                {
                                        this.clearData();                       
                                        // Clear Adapter data contents
                                        // Add data to Separated ListView
                                        this.addSection("Content",
                                                        new
PlayerArrayAdapter((Activity)context,R.layout.playerinfoadapter,str));
                                }
                    notifyDataSetChanged();
                    if (AppMain.isLogv) Log.v(CONTEXT,"Updated view with "+
playerCount +" PlayerInfos");
            }

            /**
             * Used to update the data in our view
             * @param s - String to be parsed into an Array that will contain
data to update view
             */
            public void update(String s) {
                        final String CONTEXT = CLASS_NAME+".update(String [])";

                        System.out.println("Array of Strings outputted, No 
Content
Found");

                        String [] str = new String[1];
                        str[0] = s;
                        if(str != null && str.length > 0)
                                {
                                        this.clearData();                       
                                        // Clear Adapter data contents
                                        // Add data to Separated ListView
                                        this.addSection("Content",new
PlayerArrayAdapter((Activity)context,R.layout.playerinfoadapter,str));
                                }
                    notifyDataSetChanged();
                    if (AppMain.isLogv) Log.v(CONTEXT,"Updated view with "+ 1 +"
PlayerInfos");
            }

Custom ArrayAdapter:

public class PlayerArrayAdapter extends ArrayAdapter<Object>{

        // Static CONSTANTS
        private final static String                             CLASS_NAME = 
"PlayerArrayAdapter";

        /** Handles the reading the XML and building a view from it */
    private static LayoutInflater                               inflater = null;

    /** Common instance of the AppMain */
    private static AppMain                                              appMain 
= null;

        private Activity                                                        
activity;
    private Object[]                                                    data;
    private boolean                                                             
stringData;
    private boolean                                                             
playerData;
    private boolean                                                             
showLastViewed; // used for Favorites and
History view

    public String                                                               
title;
    public String                                                               
textline1;
    public String                                                               
textline2;

    /**
     * Inner class to hold the instance of each view
     */
    public static class ViewHolder  {
                public int                      position = -1;
                //public String         playerName;
                //public String         playerID;
                public TextView         text;
                public ImageView        image;
                public PlayerInfo       player;
                //public String         browserURL;
                public boolean          playerInfo;

                public String toString() {
                        if (player != null) return "PlayerInfoAdapter for
"+player.playerName;
                        return "PlayerInfoAdapter";
                }
    }

    private void initialize() {
        if (inflater == null) inflater =
(LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        if (appMain == null) appMain = AppMain.getInstance();
    }

    ////////////////////////////////////////////
Constructors /////////////////////////////////////////

    /**
     * Create an instance of this View adapter
     * @param a Current Activity instance
     */
    public PlayerArrayAdapter (Activity a, int viewResourceId) {
        super(a, viewResourceId);
                final String CONTEXT = CLASS_NAME+"()";

        activity = a;
        initialize();
    }

    /**
     * Create an instance of this View adapter
     * @param a -  Current Activity instance
     * @param viewResourceId - XML layout to use
     * @param objects - Data to be used to build List View
     */
    public PlayerArrayAdapter(Activity a, int viewResourceId, Object[]
objects)
          {
          super(a, viewResourceId, objects);
          data = objects;
          activity = a;
          // TODO Auto-generated constructor stub
          initialize();
         }


    /**
     * Create an instance of this View adapter with the list of
Strings
     * @param a Current Activity instance
     * @param viewResourceId - XML layout to use
     * @param s Strings to create this list
     */

    public PlayerArrayAdapter (Activity a, int viewResourceId, String
s) {
        super(a, viewResourceId);
                final String CONTEXT = CLASS_NAME+"(String[])";

        activity = a;
        String [] str = new String[1];
        str[0] = s;
        data = str;
        this.add(data);
        stringData = true;
        initialize();
    }

    /**
     * Create an instance of this View adapter with the list of
Strings
     * @param a Current Activity instance
     * @param viewResourceId - XML layout to use
     * @param d Array of Strings to create this list
     */

    public PlayerArrayAdapter (Activity a, int viewResourceId,
String[] d) {
        super(a, viewResourceId, d);
                final String CONTEXT = CLASS_NAME+"(String[])";

                if (AppMain.isLogv) Log.v(CONTEXT,"Loading "+d.length+" 
Strings");
        activity = a;
        if(d!= null && d.length>0){
                data = d;
            this.add(data);
        }
        stringData = true;
        initialize();
    }

    /**
     * Create an instance of this View adapter with the list of our
Players
     * @param a Current Activity instance
     * @param viewResourceId - XML layout to use
     * @param players Array of PlayerInfo to create this list
     *
     */

    public PlayerArrayAdapter (Activity a, int viewResourceId,
PlayerInfo[] players) {
        super(a,viewResourceId,players);
                final String CONTEXT = CLASS_NAME+"(PlayerInfo[])";
                if (AppMain.isLogv) Log.v(CONTEXT,"Loading "+players.length+"
Players");
        activity = a;
        data = players;
        //this.clear(); // Clear Adapter data contents
        //this.add(data);
        playerData = true;
        initialize();
    }

        /**
            * Get a View that displays the data at the specified position in
the data set
                * You can either create a View manually or inflate it from an 
XML
layout file.
                * When the View is inflated, the parent View (GridView, 
ListView...)
will
                * apply default layout parameters unless you use
                * inflate(int, android.view.ViewGroup, boolean) to specify a 
root
view and
                * to prevent attachment to the root.
                *
                * @param position  The position of the item within the adapter's
data set
                * of the item whose view we want.
                * @param convertView The old view to reuse, if possible.
                * Note: You should check that this view is non-null and of an
appropriate
                * type before using. If it is not possible to convert this view 
to
display
                * the correct data, this method can create a new view.
                * @param parent The parent that this view will eventually be
attached to
                * @return A View corresponding to the data at the specified
position.
            */

            @Override
            public View getView(int position, View convertView, ViewGroup
parent) {
                        final String CONTEXT = CLASS_NAME+".getView";

                        for(int x=0;x<data.length;x++)
                        {
                                Log.w(CONTEXT, x + ". " + data[x].toString());
                        }

                View vi = convertView;

                try {
                                Log.w(CONTEXT,"Getting view for 
Pos="+position+" View="+convertView
+" parent="+parent);
                                ViewHolder holder = null;
                        if (convertView == null) {
                                if (AppMain.isLogv) Log.v(CONTEXT,"Building 
view for pos="+
(position));
                            vi = inflater.inflate(R.layout.playerinfoadapter, 
null);
                            holder = null;
                            holder = new ViewHolder();
                            holder.position = position;
                            holder.text = (TextView)vi.findViewById(R.id.text);
                            holder.image = 
(ImageView)vi.findViewById(R.id.image);
                            vi.setTag(holder);
                        }
                        else {
                                // Getting existing view
                                holder = (ViewHolder) vi.getTag();
                                Log.w(CONTEXT,"Convert view from
ViewHolder.pos="+holder.position+" for pos="+position);
                        }

                        // Build the view
                        if (data != null) {
                                if (holder != null) {
                                        if (data instanceof PlayerInfo[]) {
                                                String result = 
"Pos:"+(position);
                                                StringBuilder sbuf = new 
StringBuilder(256);


                                                PlayerInfo player = 
(PlayerInfo) data[position];
                                                Log.w(CONTEXT, " -- PARSED A 
PLAYER: " +
data[position].toString());

                                                String iconURL = null;
                                                if (player != null) {
                                                        holder.player = null;
                                                        holder.player = player;
                                                        holder.playerInfo = 
true;
                                                        title = 
player.playerName;
                                                        textline1 = 
player.locationDescription;
                                                        // The next line varies 
depending on if we display the
distance or last viewed time
                                                        StringBuilder line2 = 
new StringBuilder(24);
                                                        if (showLastViewed) {
                                                                // if over 7 
days display the date, otherwise display
the time
                                                                String 
lastViewedTime = player.lastViewed;
                                                                if 
(lastViewedTime != null) {
                                                                        //
line2.append(activity.getString(R.string.lastviewed));
                                                                        
line2.append(lastViewedTime);
                                                                } else {
                                                                        // 
never viewed
                                                                }
                                                            } else {
                                                                if 
(player.onSite > 0 || player.distance < 16093.44d) {
                                                                        
line2.append("<b><font color='green'>");
                                                                        
line2.append(player.getDistance(false));
                                                                        
line2.append("</font></b>");
                                                                } else {
                                                                        
line2.append(player.getDistance(false));;
                                                                }
                                                        }
                                                        textline2= 
line2.toString();
                                                        line2 = null;
                                                        
sbuf.append("<b>").append(title).append("</b><br/>");
                                                        
sbuf.append("<small>").append(textline1).append("</
small><br/>");
                                                
sbuf.append("<small>").append(textline2).append("</
small>");
                                                //holder.playerName = 
player.playerName;
                                                        //holder.browserURL = 
player.playerAddress;
                                                        //holder.playerID = 
player.playerID;
                                                        iconURL = 
player.iconURL;
                                                        result += " Set 
Text="+title;
                                                } else {
        
sbuf.append(activity.getString(R.string.noplayerdatafound));
                                                }
                                                
holder.text.setText(Html.fromHtml(sbuf.toString()));

                                                if (holder.image != null && 
iconURL != null) {
                                                        
holder.image.setTag(iconURL);
                                                        // load the image from 
our cache
                                                        
appMain.getImageLoader().getImage (iconURL, activity,
holder.image);
                                                        result += " Set 
Image="+iconURL;
                                                }
                                                if (AppMain.isLogd) 
Log.d(CONTEXT,result);
                                        }

                                        else if (data instanceof String[])
                                        {
                                                String result = 
"Pos:"+(position);
                                                Log.w(CONTEXT, 
(String)data[position].toString());
                                                String stringData = (String) 
data[position];
                                                
holder.text.setText(Html.fromHtml(stringData));
                                                holder.playerInfo = false;
                                                holder.player = null;
                                                result += " Set 
Text="+stringData;

                                                Log.w(CONTEXT, " -- PARSED A 
PLAYER: " + result);

                                                
appMain.getImageLoader().displayDefaultIcon
(holder.image);
                                                if (AppMain.isLogd) 
Log.d(CONTEXT,result);
                                        }

                                        else {
                                                Log.w(CONTEXT,"Incorrect data 
for view.
"+data.toString());
                                        }
                                } else {
                                        Log.w(CONTEXT,"Null view");
                                }
                        } else {// else no data defined yet
                                if (AppMain.isLogd) Log.d(CONTEXT,"Data not 
defined");
                        }
                        }
                        catch (Exception e) {
                                Log.e(CONTEXT,e.getMessage()+" Pos="+(position) 
+"
View="+convertView+" parent="+parent);
                        }

                        Log.w(CONTEXT, " -- CREATED NEW VIEW: " +
data[position].toString());

                return vi;
            }

        /**
     * Get the row id associated with the specified position in the
list.
     * <p>
     * Called when we have focused or clicked on,
         * @param position  The position of the item within the adapter's
data set whose row id we want.
         * @return The id of the item at the specified position.
         *
         */

   @Override
   public long getItemId(int position) {
                final String CONTEXT = CLASS_NAME+".getItemId";
                if (AppMain.isLogv) Log.v(CONTEXT,"position="+position);

        return position;
    }

        /**
    * Returns a count of how many elements we have in the view List
    * @return 0 if no elements or the number of elements
   */

   @Override
   public int getCount() {
                final String CONTEXT = CLASS_NAME+".getItemId";

                int count = data.length;
                //Log.w(CONTEXT, "GOT TOTAL COUNT: " + count);

                return count;
   }

   @Override
   public int getViewTypeCount() {
    return 1;
   }

   @Override
   public int getItemViewType(int position) {
           return 0;
   }

   /**
    * Get the data item associated with the specified position in the
data set
         * @param position  Position of the item whose data we want within
the adapter's data set.
         * @return The data at the specified position.
         *
         *
         */

   @Override
   public Object getItem(int position) {
                final String CONTEXT = CLASS_NAME+".getItem";
                Object itemData = null;
                if (data != null) {
                        if (AppMain.isLogv) Log.v(CONTEXT,"position="+position);
                        if (playerData) {
                                itemData = (PlayerInfo)data[position];
                                if (AppMain.isLogv) Log.v(CONTEXT,"Player "+
((PlayerInfo)data[position]).playerName);
                        } if (stringData) {
                                itemData = (String)data[position];
                                if (AppMain.isLogv) Log.v(CONTEXT,"String "+
((String)data[position]));
                        } else {
                                itemData = data[position];
                                if (AppMain.isLogv) 
Log.v(CONTEXT,"position="+position);
                        }
                } else {
                        Log.w(CONTEXT,"Data set is empty");
                }
                return itemData;
   }

   public void showLastViewed(boolean value) {
                showLastViewed = value;
   }

}

I've been at this for days, and my deadline is slowly tightening
around my neck! Anyone can help? Thx in advanced

-- 
You received this message because you are subscribed to the Google
Groups "Android Developers" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/android-developers?hl=en

Reply via email to