ViewView重新生成为ListView滚动吗?

时间:2012-07-02 21:29:03

标签: android listview

我有一个自定义baseadapter,我绑定到ListView。我正在从自定义类加载对象列表。

当数据发生变化时,我正在改变某些行的布局,以创建标题(是的,我知道有一些逻辑,我仍然需要修复,但它有效)。

我的问题是,当我将listview滚动到orginally-visible时,应用程序在HeaderHolder上崩溃并出现ClassCastException错误(我看到我在catch处理程序中设置了断点)。我认为这是由于视图被破坏和重新创建,不确定。有人可以证实这一点吗?

public class MyCustomBaseAdapter extends BaseAdapter {
 private static ArrayList<Appointment> searchArrayList;

 private LayoutInflater mInflater;

 public MyCustomBaseAdapter(Context context, ArrayList<Appointment> results) {
  searchArrayList = results;
  mInflater = LayoutInflater.from(context);
 }

 public int getCount() {
  return searchArrayList.size();
 }

 public Object getItem(int position) {
  return searchArrayList.get(position);
 }

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

 public String lastDate = null;
 public String thisItemDate = null;

 public View getView(int position, View convertView, ViewGroup parent) 
 {
     try
     {
         thisItemDate = searchArrayList.get(position).GetDTStart().toString().substring(0,10);
         if(!thisItemDate.equals(lastDate))
         {
             HeaderHolder holder;
             if (convertView == null) 
             {
                 convertView = mInflater.inflate(R.layout.calendar_item_header, null);

                 holder = new HeaderHolder();

                 holder.txtHeader = (TextView) convertView.findViewById(R.id.header);

                 convertView.setTag(holder);
                 convertView.setPadding(2,2,2,2);
             } 
             else 
             {
                 holder = (HeaderHolder) convertView.getTag();
             }

             holder.txtHeader.setText(thisItemDate);

             lastDate = thisItemDate;
             return convertView;                 
         }
     }
     catch (Exception e)
     {  //Catch exception if any
        System.err.println("Error: " + e.getMessage());
     }


     ViewHolder holder;
     if (convertView == null) 
     {
         convertView = mInflater.inflate(R.layout.calendar_item, null);

         holder = new ViewHolder();
         holder.txtAttendee = (TextView) convertView.findViewById(R.id.attendee);
         holder.txtSummary = (TextView) convertView.findViewById(R.id.summary);
         holder.txtStarts = (TextView) convertView.findViewById(R.id.starts);
         holder.txtEnds = (TextView) convertView.findViewById(R.id.ends);

         convertView.setTag(holder);
         convertView.setPadding(4, 4, 4, 16);
     } 
     else 
     {
         holder = (ViewHolder) convertView.getTag();
     }

     holder.txtAttendee.setText(searchArrayList.get(position).GetAttendee());
     holder.txtSummary.setText(">" + searchArrayList.get(position).GetSummary());
     String st = searchArrayList.get(position).GetDTStart().toString();
     String en = searchArrayList.get(position).GetDTEnd().toString();

     holder.txtStarts.setText(st.substring(0,16));
     holder.txtEnds.setText(en.substring(0,16));

     return convertView;         
 }

 static class ViewHolder 
 {
     TextView txtAttendee;
     TextView txtSummary;
     TextView txtStarts;
     TextView txtEnds;
 }

 static class HeaderHolder
 {
     TextView txtHeader;

2 个答案:

答案 0 :(得分:3)

您必须通过适配器告诉ListView它在内部创建/更新的视图类型的数量以及在哪个列表位置查找的视图类型。这是通过以下方法完成的:

编辑:你的实现有点复杂。您应该重新设计适配器,以明确包含部分标题作为内部列表数据结构的数据项。

这样做的一种方法是使用ArrayList&lt; Object&gt;来支持适配器。而不是ArrayList&lt; Appointment&gt;。这样,您可以在同一列表中同时拥有约会对象部分标题字符串。

两个方法getView和getItemViewType都需要在请求的位置获取ArrayList项,并检查item对象的类型:

public int getItemViewType(int position) {
    Object item = getItem(position);

    if(item instanceof Appointment) {
        return 0;
    } else {
        // It's a section title:
        return 1;
    }
}

您可以在getView方法中进行类似的操作:

public View getView(int position, View convertView, ViewGroup parent) {
    Object item = getItem(position);

    if(convertView == null) {
        // Create item view for first time

        if(item instanceof Appointment) {
            convertView = ... // inflate appointment list view item layout
        } else {
            convertView = ... // inflate title section list view item layout
        }
    }

    // Update list view item view according to type:
    if(item instanceof Appointment) {
        Appointment a = (Appointment) item;
        // Retrieve TextViews etc from convertView, cache it as Tag in a ViewHolder
        // and update these views based on Appointment a
    } else {
        // Item is a section header string:
        String label = (String) item;
        // Retrieve label TextView from convertView... etc...
    }

    return convertView;
}

实际上没有其他内容。

答案 1 :(得分:0)

嗯,我差不多......它运行正常,有一个例外:当我向下滚过列表视图的底部时,条目开始出现故障。使用调试器,我已经验证了arraylist以正确的顺序加载,并且日期标签正确的位置。然而,一旦我开始滚动,事情就会乱七八糟(例如,listview条目移动并且标签向上和/或向下移动。我认为问题是由于我得到的nullpointer异常(在catch块中)它的右边的注释。)但是我不确定为什么会发生这种情况,并且只有当列表滚动得足以使某些元素弹出而其他元素需要进入视图时才会发生。

public class MyCustomBaseAdapter extends BaseAdapter {
 //private static ArrayList<Appointment> searchArrayList;
 private static ArrayList<Object> searchArrayList;

 private LayoutInflater mInflater;

 //public MyCustomBaseAdapter(Context context, ArrayList<Appointment> results) {
 public MyCustomBaseAdapter(Context context, ArrayList<Object> results) {

  searchArrayList = results;
  mInflater = LayoutInflater.from(context);
 }

 public int getCount() {
  return searchArrayList.size();
 }

 public Object getItem(int position) {
  return searchArrayList.get(position);
 }

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


 // One way for doing that would be to back the adapter with an ArrayList<Object> instead of ArrayList<Appointment>. 
 // That way you can have both Appointment objects and section title strings in the same list.
 // Both methods getView and getItemViewType need to fetch the ArrayList item at the requested position and check the item object for its type:

public int getItemViewType(int position) {
    Object item = getItem(position);

    if(item instanceof Appointment) {
        return 0;
    } else {
        // It's a section title:
        return 1;
    }
}

public View getView(int position, View convertView, ViewGroup parent) 
{
    Object item = getItem(position);

    if(convertView == null) 
    {
        // Create item view for first time
        if(item instanceof Appointment) 
        {   // inflate appointment list view item layout
            convertView = mInflater.inflate(R.layout.calendar_item, null);
        } 
        else 
        {   // inflate title section list view item layout
            convertView = mInflater.inflate(R.layout.calendar_item_header, null); 
        }
    }

    // Update list view item view according to type:
    if(item instanceof Appointment) 
    {
        Appointment a = (Appointment) item;
        // Retrieve TextViews etc from convertView, cache it as Tag in a ViewHolder
        // and update these views based on Appointment a
        ViewHolder holder;

        holder = new ViewHolder();
        holder.txtAttendee = (TextView) convertView.findViewById(R.id.attendee);
        holder.txtSummary = (TextView) convertView.findViewById(R.id.summary);
        holder.txtStarts = (TextView) convertView.findViewById(R.id.starts);
        holder.txtEnds = (TextView) convertView.findViewById(R.id.ends);
        holder.txtCategories = (TextView) convertView.findViewById(R.id.categories);

        convertView.setTag(holder);
        convertView.setPadding(4, 4, 4, 16);

        try
        {
            holder.txtAttendee.setText(a.GetAttendee());
            holder.txtSummary.setText(">" + a.GetSummary());
            String st = a.GetDTStart().toString();
            String en = a.GetDTEnd().toString();

            holder.txtStarts.setText(st.substring(0,16));
            holder.txtEnds.setText(en.substring(0,16)); 

            String cat = a.GetCategories();
            holder.txtCategories.setText(cat);



        }
        catch (Exception e)
        {
            String err = e.getMessage();  // here's the error location

        }
    } 
    else 
    {
        // Item is a section header string:
        String label = (String) item;
        // Retrieve label TextView from convertView... etc...
        HeaderHolder holder;

        holder = new HeaderHolder();

        holder.txtHeader = (TextView) convertView.findViewById(R.id.header);

        convertView.setTag(holder);
        convertView.setPadding(2,2,2,2);
        convertView.setClickable(false);
        convertView.setFocusable(false);

        try
        {
            holder.txtHeader.setText(" " + label);
        }
        catch (Exception e)
        {

        }
    }

    return convertView;
}

 static class ViewHolder 
 {
     TextView txtAttendee;
     TextView txtSummary;
     TextView txtStarts;
     TextView txtEnds;
     TextView txtCategories;
 }

 static class HeaderHolder
 {
     TextView txtHeader;

 }