2009-11-02 2 views
10

SDK 데모 샘플의 EfficientAdapter example을 기반으로하는 BaseAdapter의 확장 버전을 사용하고 있습니다.Android : 두 개의 다른보기가있는 EfficientAdapter

내 데이터는 기본적으로 listPlaces.getValues()을 통해 액세스 할 수있는 실제 장소 목록이 ArrayList 인 객체 (ListPlaces)입니다. 이 ArrayList 데이터는 범위에 따라 정렬되고 ArrayList은 데이터가없고 으로 설정된 separator 플래그가있는 특수 항목 (구분 기호)으로 구성됩니다. 내 EfficientAdapter 그것이 public boolean isEnabled(int position)에 대한 false 반환하고 public View getView(int position, View convertView, ViewGroup parent)는 현재 데이터 객체가 실제 데이터로 구성하거나 구분 더미 경우에 따라 두 개의 서로 다른 레이아웃을 팽창 구분하는 데이터 객체를 가져옵니다 이제 때마다

.

레이아웃을 매번 팽창 시키면 멋지게 작동합니다. 그러나 매번 레이아웃을 늘리고 findViewById을 호출하면 ListView이 거의 비정상적으로 느려집니다.

그래서 나는 ViewHolder 접근 방식으로 EfficientAdapter를 사용하려고했습니다. 하지만 액세스하려고하는 두 가지 견해 때문에 상자 밖에서 제대로 작동하지 않았습니다. 따라서 convertView != null (else-case)이 ViewHolder을 통해 레이아웃의 항목에 액세스 할 때마다 이전보기가 구분 기호 일 때 당연히 "실제"항목 레이아웃에서만 사용할 수있는 TextView에 액세스 할 수 없습니다 . 이전 listRow이 현재보다 다른 경우

그래서 나는 또한 또한 내 getView() 레이아웃뿐만 아니라 convertView == null을 팽창 강제 있지만 : 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; 
    } 
} 

그리고 내 로그 캣 출력 :

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: [email protected]         
    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: [email protected]          
    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: [email protected]         
    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: [email protected]          
    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: [email protected]              
    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: [email protected]              
    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: [email protected]              
    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: [email protected]         
    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: [email protected]          
    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: [email protected]         
    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: [email protected]          
    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: [email protected]              
    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: [email protected]              
    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)  
+0

줄 300이 스택 트레이스에있는 위치를 나타내는 주석을 추가 할 수 있습니까? 'if (curValues.separator> = 0)'인 경우,리스트의 끝 부분에서 1까지 위치를 처리 할 수 ​​있어야합니까? – rsp

답변

12

당신은 잊었을 재정의가 필요한 몇 가지 방법 : getViewTypeCount()getItemViewType(). 이들은 모든 행이 같은 목록에는 필요하지 않지만 시나리오에서는 매우 중요합니다. 이것들을 적절하게 구현하면 안드로이드는 헤더와 세부 행을위한 별도의 객체 풀을 유지합니다.

또는 당신이 볼 수 있었다 :

+1

빠른 응답을 보내 주셔서 감사합니다. getViewTypeCount() 및 getItemViewType()의 힌트는 매우 유용했습니다. 나는이 어댑터 물건을 좋아한다. Jeff Sharkey의 소스 코드를 공유해 주셔서 감사합니다. 지난주에 이미 살펴 봤지만, 현재 폐쇄적 인 소스 프로젝트를 수행 중이므로 적어도 GPL 예제를 구현할 수는 없습니다. 그래서 저는 제 자신의 구현을 시작하기로 결정했습니다. 여러분의 도움으로 마침내 작동합니다. Muchas gracias! – znq

+0

업데이트 된 링크가 더 이상 작동하지 않습니다. 여전히 작동하는 링크를 찾을 수 없습니다. – rtack

6

getViewTypeCount() 및 getItemViewType() 힌트 덕분에 이제 완벽하게 작동합니다.

매우 간단 이러한 두 가지 방법을했다 구현 : 그의 대답 또한 listRow_previous에 대한 체크를 제거 할 수 있음을 의미 다른 목록 항목에 대해 서로 다른 객체 풀을 유지합니다 이런 식으로 안드로이드에서 언급

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

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

commonsware 으로 내 예에서는 if (convertView == null || (listRow != listRow_previous))if (convertView == null)으로 변경하십시오.

관련 문제