Android - 管理ListViews的ViewHolders

时间:2015-01-02 10:01:57

标签: android listview android-adapter android-viewholder

我有ViewHolder个自定义BaseAdapter来填充ListView,其数据来源为ArrayList<HashMap<String,String>>。我的用例涉及重新排序,追加和删除ListView中的元素。我将列表视图元素存储在ViewHolder中以便进行回收。我需要每次都致电notifyDataSetChanged()更改ListView

  

public class MycustomAdapter extends BaseAdapter{

    private ArrayList<HashMap<String,String>> datalist;
    private LayoutInflater inflater; 

    public MycustomAdapter(Context context,ArrayList<HashMap<String,String>> list){

        this.datalist = list;
        this.inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 

    }

    private static class ViewHolder{

        int index;
        TextView menuItemName;
        TextView status;
        TextView customIndicator;
        Button multiPurposeButton;
        Button rejectButton;
    }

    @Override
    public int getCount() {
        // TODO Auto-generated method stub
        return this.datalist.size();

    }

    @Override
    public Object getItem(int position) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public long getItemId(int position) {
        // TODO Auto-generated method stub
        return 0;
    }

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

        ViewHolder viewHolder;

        if(convertView == null){

            convertView = inflater.inflate(R.layout.list_element,parent,false);

            viewHolder = new ViewHolder();

            // Setting menu-item name text-box in view holder.
            viewHolder.menuItemName = (TextView)convertView.findViewById(R.id.item_name);

            // Setting status text-box in view holder.
            viewHolder.status = (TextView)convertView.findViewById(R.id.status);

            // Setting custom-indicator text-box in view holder.
            viewHolder.customIndicator = (TextView)convertView.findViewById(R.id.custom_indicator);

            // Setting accept/finish button in view holder.
            viewHolder.multiPurposeButton = (Button)convertView.findViewById(R.id.accept_button);

            // Setting reject button in view holder
            viewHolder.rejectButton = (Button) convertView.findViewById(R.id.reject_button);

            // Setting positiopn of view holder
            viewHolder.index = position;

            // setting tag for view holder
            convertView.setTag(viewHolder);
        }
        else{

            viewHolder = (ViewHolder)convertView.getTag();  
        }

        viewHolder.menuItemName.setText(datalist.get(position).get("itemname"));
        viewHolder.status.setText(datalist.get(position).get("status"));  
           viewHolder.customIndicator.setText(datalist.get(position).get("orderid"));
       viewHolder.multiPurposeButton.setText(datalist.get(position).get("buttontext"));

        return convertView;
    }

    public ArrayList<HashMap<String,String>> getData(){

        return this.datalist;
    }

    public void setData(ArrayList<HashMap<String,String>> datalist){

        this.datalist = datalist;
    }


}

以下是我在调用notifyDataSetChanged()修改ListView时从列表中删除项目时获得的异常:

FATAL EXCEPTION: main
java.lang.IndexOutOfBoundsException: Invalid index 3, size is 3
    at java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:251)
    at java.util.ArrayList.get(ArrayList.java:304)
    at com.sample.application.MycustomAdapter.getView(MycustomAdapter.java:96)
    at android.widget.AbsListView.obtainView(AbsListView.java:2319)
    at android.widget.ListView.makeAndAddView(ListView.java:1793)
    at android.widget.ListView.fillDown(ListView.java:678)
    at android.widget.ListView.fillGap(ListView.java:642)
    at android.widget.AbsListView.trackMotionScroll(AbsListView.java:5489)
    at android.widget.AbsListView.scrollIfNeeded(AbsListView.java:3310)
    at android.widget.AbsListView.onTouchEvent(AbsListView.java:3654)
    at android.view.View.dispatchTouchEvent(View.java:7143)
    at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2238)
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1935)
    at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2244)
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1949)
    at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2244)
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1949)
    at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2244)
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1949)
    at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2244)
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1949)
    at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2244)
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1949)
    at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2244)
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1949)
    at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:1938)
    at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1392)
    at android.app.Activity.dispatchTouchEvent(Activity.java:2408)
    at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:1886)
    at android.view.View.dispatchPointerEvent(View.java:7323)
    at android.view.ViewRootImpl.deliverPointerEvent(ViewRootImpl.java:3560)
    at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:3490)
    at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:4637)
    at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:4597)
    at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:4749)
    at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:171)
    at android.view.InputEventReceiver.nativeConsumeBatchedInputEvents(Native Method)
    at android.view.InputEventReceiver.consumeBatchedInputEvents(InputEventReceiver.java:163)
    at android.view.ViewRootImpl.doConsumeBatchedInput(ViewRootImpl.java:4717)
    at android.view.ViewRootImpl$ConsumeBatchedInputRunnable.run(ViewRootImpl.java:4771)
    at android.view.Choreographer$CallbackRecord.run(Choreographer.java:747)
    at android.view.Choreographer.doCallbacks(Choreographer.java:567)
    at android.view.Choreographer.doFrame(Choreographer.java:534)
    at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:733)
    at android.os.Handler.handleCallback(Handler.java:615)
    at android.os.Handler.dispatchMessage(Handler.java:92)
    at android.os.Looper.loop(Looper.java:153)
    at android.app.ActivityThread.main(ActivityThread.java:5000)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:511)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:821)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:584)
    at dalvik.system.NativeStart.main(Native Method)

我已将此错误的原因确定为与ListView的数据源大小相关。当数据源最初有10个元素,然后在删除项目后有9个元素时,我的理解是否正确ListView期望缺少的元素存在?这些行引用了IndexOutOfBoundsException

viewHolder.menuItemName.setText(datalist.get(position).get("menu_item_name"));
viewHolder.status.setText(datalist.get(position).get("status"));
       viewHolder.customIndicator.setText(datalist.get(position).get("order_id"));
viewHolder.multiPurposeButton.setText(datalist.get(position).get("button_text"));

这里的问题是我修改的数据源中不存在第10个元素,并且没有要设置的数据。解决这个问题的好方法是什么?

1 个答案:

答案 0 :(得分:1)

我认为问题出在getItem()和getItemId()方法上。像这样覆盖这些方法

    @Override
    public Object getItem(int position) {
        return this.datalist.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }