12

SDK デモ サンプルのEfficientAdapter の例に基づいて、BaseAdapter の拡張バージョンを使用しています。

私のデータは基本的にオブジェクト ( ListPlaces) でArrayList、場所の実際のリストを保持し、 経由でアクセスできますlistPlaces.getValues()。この ArrayList データは範囲でソートさArrayListれ、いくつかの特別な項目 (区切り記号) で構成され、データはありませんが、separatorフラグが に設定されていtrueます。

my がセパレーターであるデータオブジェクトを取得するたびに、現在のデータオブジェクトが実際のデータで構成されているか、単なるセパレーターダミーであるかに応じて、2 つの異なるレイアウトをEfficientAdapter返しfalse、膨張させます。public boolean isEnabled(int position)public View getView(int position, View convertView, ViewGroup parent)

毎回レイアウトを膨らませると、これはうまく機能します。ただし、毎回レイアウトを膨らませて呼び出すfindViewByIdと、ListViewほとんど使い物にならないほど遅くなります。

ViewHolderそこで、アプローチで EfficientAdapter を使用しようとしました。しかし、私がアクセスしようとしている 2 つの異なるビューが原因で、そのままでは機能しませんでした。したがって、my convertView != null(else-case) が ourViewHolderを介してレイアウト上の項目にアクセスするときはいつでも、前の View がセパレーターであった場合、もちろん、「実際の」項目レイアウトでのみ利用可能な TextView にアクセスすることはできません。

したがってgetView()、 の場合だけconvertView == nullでなく、前の listRow が現在のものと異なる場合にも、レイアウトをインフレートするように強制します。if (convertView == null || (listRow != listRow_previous)) { [....] }

これでほぼ動作するようになりました。または、少なくとも最初からクラッシュすることはありません。しかし、それでもクラッシュし、何をしなければならないのかわかりません。convertView.getID()とを調べてみましconvertView.getResources()たが、これまでのところあまり役に立ちませんでした。他の誰かが、現在convertViewのリスト項目レイアウトまたはリスト区切りレイアウトと一致するかどうかを確認する方法を知っているかもしれません。ありがとう。

これがコードです。[...] 読みやすく理解しやすいように、重要度の低いコードをいくつか取り出しました。

private class EfficientAdapter extends BaseAdapter {
  private LayoutInflater mInflater;
  private ListPlaces listPlaces;

  private ListRow listRow;
  private ListRow listRow_previous;


  public EfficientAdapter(Context context, ListPlaces listPlaces) {
      // Cache the LayoutInflate to avoid asking for a new one each time.
      mInflater = LayoutInflater.from(context);

      // Data
      this.listPlaces = listPlaces;
  }

  /**
    * The number of items in the list is determined by the number of items
    * in our ArrayList
    *
    * @see android.widget.ListAdapter#getCount()
    */
  public int getCount() {
      return listPlaces.getValues().size();
  }

  /**
    * Since the data comes from an array, just returning the index is
    * sufficent to get at the data. If we were using a more complex data
    * structure, we would return whatever object represents one row in the
    * list.
    *
    * @see android.widget.ListAdapter#getItem(int)
    */
  public Object getItem(int position) {
      return position;
  }

  /**
    * Use the array index as a unique id.
    *
    * @see android.widget.ListAdapter#getItemId(int)
    */
  public long getItemId(int position) {
      return position;
  }

  @Override
  public  boolean isEnabled(int position) {
      // return false if item is a separator:
      if(listPlaces.getValues().get(position).separator >= 0)
          return false;
      else
          return true;
  }

  @Override
  public boolean  areAllItemsEnabled() {
      return false;         
  }



  /**
    * Make a view to hold each row.
    *
    * @see android.widget.ListAdapter#getView(int, android.view.View,
    *      android.view.ViewGroup)
    */
  public View getView(int position, View convertView, ViewGroup parent) {

      // Get the values for the current list element
      ListPlacesValues curValues = listPlaces.getValues().get(position);
      if (curValues.separator >= 0) 
          listRow = ListRow.SEPARATOR;
      else
          listRow = ListRow.ITEM;
      Log.i(TAG,"Adapter: getView("+position+") " + listRow + " (" + listRow_previous + ") -> START");

      // A ViewHolder keeps references to children views to avoid unneccessary calls
      // to findViewById() on each row.
      ViewHolder holder;

      // When convertView is not null, we can reuse it directly, there is no need
      // to reinflate it. We only inflate a new View when the convertView supplied
      // by ListView is null.
      if (convertView == null || (listRow != listRow_previous)) {
          Log.i(TAG, "--> (convertView == null) at position: " + position);
          // Creates a ViewHolder and store references to the two children views
          // we want to bind data to.
          holder = new ViewHolder();

          if (listRow == ListRow.SEPARATOR) {
              convertView = mInflater.inflate(R.layout.taxonomy_list_separator, null);
              holder.separatorText = (TextView) convertView.findViewById(R.id.separatorText);
              convertView.setTag(holder);
              Log.i(TAG,"\tCREATE SEPARATOR: convertView ID: " + convertView.getId() + " Resource: " + convertView.getResources());

          }
          else {

              convertView = mInflater.inflate(R.layout.taxonomy_listitem, null);
              holder.name = (TextView) convertView.findViewById(R.id.name);
              holder.category = (TextView) convertView.findViewById(R.id.category);
              // [...]

              convertView.setTag(holder);

              Log.i(TAG,"\tCREATE ITEM: convertView ID: " + convertView.getId() + " Resource: " + convertView.getResources());
          }
      } else {
          // Get the ViewHolder back to get fast access to the TextView
          // and the ImageView.
          Log.i(TAG,"\tconvertView ID: " + convertView.getId() + " Resource: " + convertView.getResources());

          holder = (ViewHolder) convertView.getTag();
          convertView.setAnimation(null);
      }

      /* Bind the data efficiently with the holder */
      if (listRow == ListRow.SEPARATOR) {
          String separatorText;
          switch (curValues.separator) {
          case 0: separatorText="case 0"; break;
          case 1: separatorText="case 1"; break;
          case 2: separatorText="case 2"; break;
          // [...]
        default: separatorText="[ERROR]"; break;
          }
          holder.separatorText.setText(separatorText);
      } 
      else {
          // Set the name:
          holder.name.setText(curValues.name);
          // Set category
          String cat = curValues.classification.toString();
          cat = cat.substring(1,cat.length()-1);    // removing "[" and "]"
          if (cat.length() > 35) {
              cat = cat.substring(0, 35);
              cat = cat + "...";
          }
          holder.category.setText(cat);

          // [...] (and many more TextViews and ImageViews to be set)

      }

      listRow_previous = listRow;
      Log.i(TAG,"Adapter: getView("+position+") -> DONE");
      return convertView;
  }

  private class ViewHolder {
      TextView name;
      TextView category;
      // [...] -> many more TextViews and ImageViews

      TextView separatorText;
  }
}

そしてここに私のLogcat出力:

  755     ListPlaces_Activity  I  onPostExecute: notifyDataSetChanged()                                                                                                
  755     ListPlaces_Activity  I  Adapter: getView(0) SEPARATOR (null) -> START                                                                                        
  755     ListPlaces_Activity  I  --> (convertView == null) at position: 0                                                                                             
  755     ListPlaces_Activity  I        CREATE SEPARATOR: convertView ID: 2131296317 Resource: android.content.res.Resources@437613e0                                  
  755     ListPlaces_Activity  I  Adapter: getView(0) -> DONE                                                                                                          
  755     ListPlaces_Activity  I  Adapter: getView(1) ITEM (SEPARATOR) -> START                                                                                        
  755     ListPlaces_Activity  I  --> (convertView == null) at position: 1                                                                                             
  755     ListPlaces_Activity  I        CREATE ITEM: convertView ID: 2131296317 Resource: android.content.res.Resources@437613e0                                       
  755     ListPlaces_Activity  I  Adapter: getView(1) -> DONE                                                                                                          
  755     ListPlaces_Activity  I  Adapter: getView(2) SEPARATOR (ITEM) -> START                                                                                        
  755     ListPlaces_Activity  I  --> (convertView == null) at position: 2                                                                                             
  755     ListPlaces_Activity  I        CREATE SEPARATOR: convertView ID: 2131296317 Resource: android.content.res.Resources@437613e0                                  
  755     ListPlaces_Activity  I  Adapter: getView(2) -> DONE                                                                                                          
  755     ListPlaces_Activity  I  Adapter: getView(3) ITEM (SEPARATOR) -> START                                                                                        
  755     ListPlaces_Activity  I  --> (convertView == null) at position: 3                                                                                             
  755     ListPlaces_Activity  I        CREATE ITEM: convertView ID: 2131296317 Resource: android.content.res.Resources@437613e0                                       
  755     ListPlaces_Activity  I  Adapter: getView(3) -> DONE                                                                                                          
  755     ListPlaces_Activity  I  Adapter: getView(4) ITEM (ITEM) -> START                                                                                             
  755     ListPlaces_Activity  I        convertView ID: 2131296317 Resource: android.content.res.Resources@437613e0                                                    
  755     ListPlaces_Activity  I  Adapter: getView(4) -> DONE                                                                                                          
  755     ListPlaces_Activity  I  Adapter: getView(5) ITEM (ITEM) -> START                                                                                             
  755     ListPlaces_Activity  I        convertView ID: 2131296317 Resource: android.content.res.Resources@437613e0                                                    
  755     ListPlaces_Activity  I  Adapter: getView(5) -> DONE                                                                                                          
  755     ListPlaces_Activity  I  Adapter: getView(6) ITEM (ITEM) -> START                                                                                             
  755     ListPlaces_Activity  I        convertView ID: 2131296317 Resource: android.content.res.Resources@437613e0                                                    
  755     ListPlaces_Activity  I  Adapter: getView(6) -> DONE                                                                                                          
  755     ListPlaces_Activity  I  Adapter: getView(0) SEPARATOR (ITEM) -> START                                                                                        
  755     ListPlaces_Activity  I  --> (convertView == null) at position: 0                                                                                             
  755     ListPlaces_Activity  I        CREATE SEPARATOR: convertView ID: 2131296317 Resource: android.content.res.Resources@437613e0                                  
  755     ListPlaces_Activity  I  Adapter: getView(0) -> DONE                                                                                                          
  755     ListPlaces_Activity  I  Adapter: getView(1) ITEM (SEPARATOR) -> START                                                                                        
  755     ListPlaces_Activity  I  --> (convertView == null) at position: 1                                                                                             
  755     ListPlaces_Activity  I        CREATE ITEM: convertView ID: 2131296317 Resource: android.content.res.Resources@437613e0                                       
  755     ListPlaces_Activity  I  Adapter: getView(1) -> DONE                                                                                                          
  755     ListPlaces_Activity  I  Adapter: getView(2) SEPARATOR (ITEM) -> START                                                                                        
  755     ListPlaces_Activity  I  --> (convertView == null) at position: 2                                                                                             
  755     ListPlaces_Activity  I        CREATE SEPARATOR: convertView ID: 2131296317 Resource: android.content.res.Resources@437613e0                                  
  755     ListPlaces_Activity  I  Adapter: getView(2) -> DONE                                                                                                          
  755     ListPlaces_Activity  I  Adapter: getView(3) ITEM (SEPARATOR) -> START                                                                                        
  755     ListPlaces_Activity  I  --> (convertView == null) at position: 3                                                                                             
  755     ListPlaces_Activity  I        CREATE ITEM: convertView ID: 2131296317 Resource: android.content.res.Resources@437613e0                                       
  755     ListPlaces_Activity  I  Adapter: getView(3) -> DONE                                                                                                          
  755     ListPlaces_Activity  I  Adapter: getView(4) ITEM (ITEM) -> START                                                                                             
  755     ListPlaces_Activity  I        convertView ID: 2131296317 Resource: android.content.res.Resources@437613e0                                                    
  755     ListPlaces_Activity  I  Adapter: getView(4) -> DONE                                                                                                          
  755     ListPlaces_Activity  I  Adapter: getView(5) ITEM (ITEM) -> START                                                                                             
  755     ListPlaces_Activity  I        convertView ID: 2131296317 Resource: android.content.res.Resources@437613e0                                                    
  755          AndroidRuntime  D  Shutting down VM                                                                                                                     
  755                dalvikvm  W  threadid=3: thread exiting with uncaught exception (group=0x4001aa28)                                                                
  755          AndroidRuntime  E  Uncaught handler: thread main exiting due to uncaught exception                                                                      
  755          AndroidRuntime  E  java.lang.NullPointerException                                                                                                       
  755          AndroidRuntime  E        at com.tato.main.ListPlaces_Activity$EfficientAdapter.getView(ListPlaces_Activity.java:330)                                    
  755          AndroidRuntime  E        at android.widget.HeaderViewListAdapter.getView(HeaderViewListAdapter.java:191)                                                
  755          AndroidRuntime  E        at android.widget.AbsListView.obtainView(AbsListView.java:1255)                                                                
  755          AndroidRuntime  E        at android.widget.ListView.makeAndAddView(ListView.java:1658)                                                                  
  755          AndroidRuntime  E        at android.widget.ListView.fillDown(ListView.java:637)                                                                         
  755          AndroidRuntime  E        at android.widget.ListView.fillFromTop(ListView.java:694)                                                                      
  755          AndroidRuntime  E        at android.widget.ListView.layoutChildren(ListView.java:1502)                                                                  
  755          AndroidRuntime  E        at android.widget.AbsListView.onLayout(AbsListView.java:1112)                                                                  
  755          AndroidRuntime  E        at android.view.View.layout(View.java:6569)                                                                                    
  755          AndroidRuntime  E        at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1119)                                                           
  755          AndroidRuntime  E        at android.widget.LinearLayout.layoutVertical(LinearLayout.java:998)                                                           
  755          AndroidRuntime  E        at android.widget.LinearLayout.onLayout(LinearLayout.java:918)                                                                 
  755          AndroidRuntime  E        at android.view.View.layout(View.java:6569)                                                                                    
  755          AndroidRuntime  E        at android.widget.FrameLayout.onLayout(FrameLayout.java:333)                                                                   
  755          AndroidRuntime  E        at android.view.View.layout(View.java:6569)                                                                                    
  755          AndroidRuntime  E        at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1119)                                                           
  755          AndroidRuntime  E        at android.widget.LinearLayout.layoutVertical(LinearLayout.java:998)                                                           
  755          AndroidRuntime  E        at android.widget.LinearLayout.onLayout(LinearLayout.java:918)                                                                 
  755          AndroidRuntime  E        at android.view.View.layout(View.java:6569)                                                                                    
  755          AndroidRuntime  E        at android.widget.FrameLayout.onLayout(FrameLayout.java:333)                                                                   
  755          AndroidRuntime  E        at android.view.View.layout(View.java:6569)                                                                                    
  755          AndroidRuntime  E        at android.view.ViewRoot.performTraversals(ViewRoot.java:979)                                                                  
  755          AndroidRuntime  E        at android.view.ViewRoot.handleMessage(ViewRoot.java:1613)                                                                     
  755          AndroidRuntime  E        at android.os.Handler.dispatchMessage(Handler.java:99)                                                                         
  755          AndroidRuntime  E        at android.os.Looper.loop(Looper.java:123)                                                                                     
  755          AndroidRuntime  E        at android.app.ActivityThread.main(ActivityThread.java:4203)                                                                   
  755          AndroidRuntime  E        at java.lang.reflect.Method.invokeNative(Native Method)                                                                        
  755          AndroidRuntime  E        at java.lang.reflect.Method.invoke(Method.java:521)                                                                            
  755          AndroidRuntime  E        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:791)                                             
  755          AndroidRuntime  E        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:549)                                                                
  755          AndroidRuntime  E        at dalvik.system.NativeStart.main(Native Method)    
4

2 に答える 2

14

getViewTypeCount()getItemViewType( )をオーバーライドする必要があるいくつかのメソッドを忘れていました。これらは、すべての行が同じリストには必要ありませんが、シナリオにとっては非常に重要です。これらを適切に実装すると、Android はヘッダー行と詳細行に対して個別のオブジェクト プールを維持します。

または、次を参照できます。

于 2009-11-02T13:51:50.080 に答える
6

getViewTypeCount() と getItemViewType() のヒントのおかげで、完全に機能するようになりました。

これら 2 つのメソッドの実装は非常に簡単でした。

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

@Override
public int getItemViewType(int position) {
if(listPlaces.getValues().get(position).separator >= 0)
    return 0;
else
    return 1;
}

コモンズウェアが彼の回答でこのように述べたように、Android はさまざまなリスト項目に対してさまざまなオブジェクト プールを維持します。つまりlistRow_previous、私の例ではチェックを削除して、のみに変更するif (convertView == null || (listRow != listRow_previous))こともできif (convertView == null)ます。

于 2009-11-02T15:01:46.860 に答える