开发者

Android Extend BaseExpandableListAdapter

I am trying to extend the BaseExpandableListAdapter, however when once I view the list and I select one of the elements to expand, the order of the list gets reversed. For example, if I have a list with 4 elements and select the 1st element, the order (from top to bottom) is now 4, 3, 2, 1 with the 4th element (now at the top) expanded. If I unexpand the 4th element the order reverts to 1, 2, 3, 4 with no expanded elements.

Here is my implementation:

public class SensorExpandableAdapter extends BaseExpandableListAdapter {

    private static final int FILTER_POSITION = 0;
    private static final int FUNCTION_POSITION = 1;
    private static final int NUMBER_OF_CHILDREN = 2;
    ArrayList<SensorType> mParentGroups;
    private Context mContext;
    private LayoutInflater mInflater;

    public SensorExpandableAdapter(ArrayList<SensorType> parentGroup, Context context) {
        mParentGroups = parentGroup;
        mContext = context;
        mInflater = LayoutInflater.from(mContext);
    }
    @Override
    public Object getChild(int groupPosition, int childPosition) {
        // TODO Auto-generated method stub
        if(childPosition == FILTER_POSITION) return "filter";
        else return "function";
    }

    @Override
    public long getChildId(int groupPosition, int childPosition) {
        return childPosition;
    }

    @Override
    public View getChildView(int groupPosition, int childPosition,
            boolean isLastChild, View convertView, ViewGroup parent) {
        if(convertView == null)
        {
            convertView = (RelativeLayout)mInflater.inflate(R.layout.sensor_row_list_item, parent, false);
            if(childPosition == FILTER_POSITION) {
                ((CheckBox)convertView.findViewById(R.id.chkTextAddFilter)).setText("Add Filter");
            } else {
                ((CheckBox)convertView.findViewById(R.id.chkTextAddFilter)).setText("Add Function"); 
                ((CheckBox)convertView.findViewById(R.id.chkTextAddFilter)).setEnabled(false);
            }
        }
        return convertView;
    }

    @Override
    public int getChildrenCount(int groupPosition) {
        // TODO Auto-generated method stub
        return NUMBER_OF_CHILDREN;
    }

    @Override
    public Object getGroup(int groupPosition) {
        return mParentGroups.get(groupPosition);
    }

    @Override
    public int getGroupCount() {
        // TODO Auto-generated method stub
        return mParentGroups.size();
    }

    @Override
    public long getGroupId(int groupPosition) {
        // TODO Auto-generated method stub
        return groupPosition;
    }

    @Override
    public View getGroupView(int groupPosition, boolean isExpanded,
            View convertView, ViewGroup parent) {
        if(convertView == null)
        {
            convertView = mInflater.inflate(android.R.layout.simple_expandable_list_item_1, parent, false);
   开发者_StackOverflow         TextView tv = ((TextView)convertView.findViewById(android.R.id.text1));
            tv.setText(mParentGroups.get(groupPosition).toString());
        }
        return convertView;
    }

    @Override
    public boolean hasStableIds() {
        // TODO Auto-generated method stub
        return true;
    }

    @Override
    public boolean isChildSelectable(int groupPosition, int childPosition) {
        // TODO Auto-generated method stub
        return true;
    }
}

`

I just need to take a simple ArrayList of my own SensorType class. The children are the same for all classes, just two.

Also, how do I go about making the parent in each group LongClickable? I have tried in my ExpandableListActivity with this getExpandableListView().setOnLongClickableListener() ... and on the parent TextView set its OnLongClickableListener but neither works.

Any help on either of these is greatly appreciated!


public View getGroupView(int groupPosition, boolean isExpanded,
            View convertView, ViewGroup parent) {
        if(convertView == null)
        {

Just comment out "if". This should help.


this is my first stackoverflow.com -answer.

I was struggling with this problem today, and I tried the solutions provided in the previous posts.

Commenting out the "if"-clause does fix the problem, but I believe this is not a recommended solution. As described in this ListView video (http://www.youtube.com/watch?v=wDBM6wVEO70), the re-use of convertView is essential when dealing with large datasets.

My solution is very simple and it worked perfectly in my case. I got the idea from the previously mentioned video:

   public View getGroupView(int groupPosition, boolean isExpanded,
            View convertView, ViewGroup parent)     {

        // 1. Step: check if convertView can be re-used or if it should be created.

        if (convertView == null) {

                // create the view or inflate the view from xml here
                // Note: inlating is expensive process, so do it only if needed 
                //       (it's needed when convertView can not be re-used)
                //
                // TODO: your code here

        }

        // 2. Step: populate the convertView with correct data.
        // Correct data can be accessed through groupPosition.
        //
        // TODO: your code here

        return convertView;
    } 

I believe that this second step was missing from the code provided in the question?

I hope this helps someone with this same problem.

  • Tuomas


Update: This answer comes way too late; but for anyone having the same problem, here is my solution.

I just had the same issue and managed to work it out after reading the chome2phone source code.

The key is indeed in this method:

public View getChildView(int groupPosition, int childPosition,
            boolean isLastChild, View convertView, ViewGroup parent) {
        if(convertView == null)
        {
            convertView = (RelativeLayout)mInflater.inflate(R.layout.sensor_row_list_item, parent, false);
            if(childPosition == FILTER_POSITION) {
                ((CheckBox)convertView.findViewById(R.id.chkTextAddFilter)).setText("Add Filter");
            } else {
                ((CheckBox)convertView.findViewById(R.id.chkTextAddFilter)).setText("Add Function"); 
                ((CheckBox)convertView.findViewById(R.id.chkTextAddFilter)).setEnabled(false);
            }
        }
        return convertView;
    }

AS @Dan said, convertView is a cached item and as the documentation says:

convertView: the old view to reuse, if possible. 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. It is not guaranteed that the convertView will have been previously created by getChildView(int, int, boolean, View, ViewGroup).

In my case, the object passed to getChildView() came probably from a cache in the exact reverse order than created; a Stack probably (LIFO).

There are mainly two solutions; either you will remove

if(convertView == null)

thus recreating the child on every expand/collapse action or on every orientation change, or (way better performance wise) do something this:

public View getChildView(int groupPosition, int childPosition,boolean isLastChild, View convertView, ViewGroup parent) {
    RelativeLayout mItemView;
    if (null == convertView || !(convertView instanceof RelativeLayout)) {
        mItemView = (RelativeLayout)mInflater.inflate(R.layout.sensor_row_list_item, parent, false);
    }else{
        mItemView = (RelativeLayout) convertView;
    }
    if(childPosition == FILTER_POSITION) {
        ((CheckBox)convertView.findViewById(R.id.chkTextAddFilter)).setText("Add Filter");
    } else {
        ((CheckBox)convertView.findViewById(R.id.chkTextAddFilter)).setText("Add Function"); 
        ((CheckBox)convertView.findViewById(R.id.chkTextAddFilter)).setEnabled(false);
    }
}
return convertView;

Which means that you will use the object convertView to render the item instead of creating a new one.

I hope this works for you too.


I hope this is the answer you are looking for

public class Sample extends ExpandableListActivity {

    ExpandableListAdapter mAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
          mAdapter = new MyExpandableListAdapter();
          setListAdapter(mAdapter);
          registerForContextMenu(getExpandableListView());
    }

   @Override
public void onCreateContextMenu(ContextMenu menu, View v,
        ContextMenuInfo menuInfo) {
    // TODO Auto-generated method stub
    super.onCreateContextMenu(menu, v, menuInfo);

      menu.setHeaderTitle("Sample menu");
      menu.add(0, 0, 0, R.string.expandable_list_sample_action);

}

    @Override
    public boolean onContextItemSelected(MenuItem item) {
        // TODO Auto-generated method stub

         ExpandableListContextMenuInfo info = (ExpandableListContextMenuInfo) item.getMenuInfo();

         String title = ((TextView) info.targetView).getText().toString();



         int type = ExpandableListView.getPackedPositionType(info.packedPosition);

         if (type == ExpandableListView.PACKED_POSITION_TYPE_CHILD) {
             int groupPos = ExpandableListView.getPackedPositionGroup(info.packedPosition); 
             int childPos = ExpandableListView.getPackedPositionChild(info.packedPosition); 
             Toast.makeText(Sample.this, title + ": Child " + childPos + " clicked in group " + groupPos,
                     Toast.LENGTH_SHORT).show();
             return true;
         } else if (type == ExpandableListView.PACKED_POSITION_TYPE_GROUP) {
             int groupPos = ExpandableListView.getPackedPositionGroup(info.packedPosition); 
             Toast.makeText(this, title + ": Group " + groupPos + " clicked", Toast.LENGTH_SHORT).show();
             return true;
         }

         return false;

    }
    /**
     * A simple adapter which maintains an ArrayList of photo resource Ids. 
     * Each photo is displayed as an image. This adapter supports clearing the
     * list of photos and adding a new photo.
     *
     */
    public class MyExpandableListAdapter extends BaseExpandableListAdapter {
        // Sample data set.  children[i] contains the children (String[]) for groups[i].
        private String[] groups = { "People Names", "Dog Names", "Cat Names", "Fish Names" };
        private String[][] children = {
                { "Arnold", "Barry", "Chuck", "David" },
                { "Ace", "Bandit", "Cha-Cha", "Deuce" },
                { "Fluffy", "Snuggles" },
                { "Goldy", "Bubbles" }
        };

        public Object getChild(int groupPosition, int childPosition) {
            return children[groupPosition][childPosition];
        }

        public long getChildId(int groupPosition, int childPosition) {
            return childPosition;
        }

        public int getChildrenCount(int groupPosition) {
            return children[groupPosition].length;
        }

        public TextView getGenericView() {
            // Layout parameters for the ExpandableListView
            AbsListView.LayoutParams lp = new AbsListView.LayoutParams(
                    ViewGroup.LayoutParams.FILL_PARENT, 64);

            TextView textView = new TextView(Sample.this);
            textView.setLayoutParams(lp);
            // Center the text vertically
            textView.setGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT);
            // Set the text starting position
            textView.setPadding(36, 0, 0, 0);
            return textView;
        }

        public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
                View convertView, ViewGroup parent) {
            TextView textView = getGenericView();
            textView.setText(getChild(groupPosition, childPosition).toString());
            return textView;
        }

        public Object getGroup(int groupPosition) {
            return groups[groupPosition];
        }

        public int getGroupCount() {
            return groups.length;
        }

        public long getGroupId(int groupPosition) {
            return groupPosition;
        }

        public View getGroupView(int groupPosition, boolean isExpanded, View convertView,
                ViewGroup parent) {
            TextView textView = getGenericView();
            textView.setText(getGroup(groupPosition).toString());
            return textView;
        }

        public boolean isChildSelectable(int groupPosition, int childPosition) {
            return true;
        }

        public boolean hasStableIds() {
            return true;
        }

    }}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜