0

ListView にバインドしているカスタム baseadapter があります。カスタム クラスからオブジェクトのリストを読み込んでいます。

データが変更されたときに、いくつかの行のレイアウトを変更してヘッダーを作成しています (そうです、まだ修正しなければならないロジックがあることはわかっていますが、機能します)。

私の問題は、本来表示されているものを超えてリストビューをスクロールすると、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;
4

2 に答える 2

3

Adapter を介して ListView に、内部で作成/更新するビュー タイプの量と、リストのどの位置でどのビュー タイプを見つけるかを伝える必要があります。これは、次の方法で行われます。

編集:実装は少し複雑です。内部リスト データ構造のデータ項目としてセクション タイトルを明示的に含めるようにアダプタを再設計する必要があります。

これを行う 1 つの方法は、ArrayList<Appointment> の代わりに ArrayList<Object> を使用してアダプターをバックアップすることです。こうすることで、Appointment オブジェクトセクション タイトル文字列の両方を同じリストに含めることができます。

getView と getItemViewType の両方のメソッドは、要求された位置で ArrayList アイテムをフェッチし、アイテム オブジェクトのタイプをチェックする必要があります。

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;
}

実際にはそれ以上のものはありません。

于 2012-07-02T21:34:24.873 に答える
0

まあ、私はほとんどそこにいます...それは1つの例外を除いて正常に動作します.リストビューの一番下を過ぎて下にスクロールすると、エントリが順不同になり始めます. デバッガーを使用して、arraylist が正確に正しい順序で読み込まれ、日付ラベルが正しい場所にあることを確認しました。ただし、スクロールを開始すると、順序が乱れます(たとえば、リストビューエントリが移動し、ラベルが上下に移動します。問題は、取得している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;

 }
于 2012-07-04T18:25:09.760 に答える