2013-05-06 26 views
7

我正在嘗試製作具有分隔符的ActionBar微調器。我實施了一個SpinnerAdapter,它有兩個項目視圖類型(感謝getViewTypeCount)。問題是我正在從其他類型發送一些convertViewsAndroid爲什麼在我的SpinnerAdapter中回收錯誤的視圖類型?

這裏是我的SpinnerAdapter:

public abstract class SeparatorSpinnerAdapter implements SpinnerAdapter { 
    Context mContext; 
    List<Object> mData; 
    int mSeparatorLayoutResId, mActionBarItemLayoutResId, mDropDownItemLayoutResId, mTextViewResId; 

    public static class SpinnerSeparator { 
     public int separatorTextResId; 

     public SpinnerSeparator(final int resId) { 
      separatorTextResId = resId; 
     } 
    } 

    public abstract String getText(int position); 

    public SeparatorSpinnerAdapter(final Context ctx, final List<Object> data, final int separatorLayoutResId, final int actionBarItemLayoutResId, 
      final int dropDownItemLayoutResId, final int textViewResId) { 
     mContext = ctx; 
     mData = data; 
     mSeparatorLayoutResId = separatorLayoutResId; 
     mActionBarItemLayoutResId = actionBarItemLayoutResId; 
     mDropDownItemLayoutResId = dropDownItemLayoutResId; 
     mTextViewResId = textViewResId; 
    } 

    protected String getString(final int resId) { 
     return mContext.getString(resId); 
    } 

    @Override 
    public void registerDataSetObserver(final DataSetObserver observer) { 
    } 

    @Override 
    public void unregisterDataSetObserver(final DataSetObserver observer) { 
    } 

    @Override 
    public int getCount() { 
     if (mData != null) { 
      return mData.size(); 
     } 
     return 0; 
    } 

    @Override 
    public Object getItem(final int position) { 
     return mData == null ? null : mData.get(position); 
    } 

    @Override 
    public boolean isEmpty() { 
     return getCount() == 0; 
    } 

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

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

    @Override 
    public View getView(final int position, final View convertView, final ViewGroup parent) { 
     return getView(mActionBarItemLayoutResId, position, convertView, parent); 
    } 

    public boolean isSeparator(final int position) { 
     final Object item = getItem(position); 
     if (item != null) { 
      return item instanceof SpinnerSeparator; 
     } 
     return false; 
    } 

    @Override 
    public int getItemViewType(final int position) { 
     return isSeparator(position) ? 0 : 1; 
    } 

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

    @Override 
    public View getDropDownView(final int position, final View convertView, final ViewGroup parent) { 
     return getView(isSeparator(position) ? mSeparatorLayoutResId : mDropDownItemLayoutResId, position, convertView, parent); 
    } 

    private View getView(final int layoutResId, final int position, final View convertView, final ViewGroup parent) { 
     View v; 

     Log.i("TAG", "getView #" + position + "\tVT=" + getItemViewType(position) + "\tCV=" 
       + (convertView == null ? " null " : convertView.getClass().getSimpleName()) + "\ttext=> " + getText(position)); 

     if (convertView == null) { 
      final LayoutInflater li = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
      v = li.inflate(layoutResId, parent, false); 
     } else { 
      v = convertView; 
     } 

     final TextView tv = (TextView) v.findViewById(mTextViewResId); 
     if (tv != null) { 
      tv.setText(getText(position)); 

      if (isSeparator(position)) { 
       tv.setOnClickListener(null); 
       tv.setOnTouchListener(null); 
      } 
     } 

     return v; 
    } 
} 

一個實現:

public class IssuesMainFilterAdapter extends SeparatorSpinnerAdapter { 
    public IssuesMainFilterAdapter(final Context ctx, final List<Query> queries, final List<Project> projects) { 
     super(ctx, buildDataArray(queries, projects), R.layout.issues_filter_spinner_separator, R.layout.issues_filter_spinner_in_actionbar, 
       R.layout.issues_filter_spinner, R.id.issues_filter_spinner_text); 
    } 

    private static List<Object> buildDataArray(final List<Query> queries, final List<Project> projects) { 
     final List<Object> data = new ArrayList<Object>(); 
     data.add(null); // "ALL" 
     data.add(new SpinnerSeparator(R.string.issue_filter_queries)); 
     data.addAll(queries); 
     data.add(new SpinnerSeparator(R.string.issue_filter_projects)); 
     data.addAll(projects); 
     return data; 
    } 

    @Override 
    public String getText(final int position) { 
     final Object item = getItem(position); 
     if (item == null) { 
      return getString(R.string.issue_filter_all); 
     } else if (item instanceof Query) { 
      return ((Query) item).name; 
     } else if (item instanceof Project) { 
      return ((Project) item).name; 
     } else if (item instanceof SpinnerSeparator) { 
      return getString(((SpinnerSeparator) item).separatorTextResId); 
     } 
     throw new InvalidParameterException("Item has unknown type: " + item); 
    } 
} 

正如你可能已經注意到,我已經設置了日誌行到getView()讓我更好地瞭解這是怎麼回事:

05-06 14:01:28.721 I/TAG(5879): getView #0 VT=1 CV=TextView text=> #### 
05-06 14:01:28.721 I/TAG(5879): getView #1 VT=0 CV=LinearLayout text=> #### 
05-06 14:01:28.729 I/TAG(5879): getView #2 VT=1 CV=TextView text=> #### 
05-06 14:01:28.745 I/TAG(5879): getView #3 VT=1 CV=TextView text=> #### 
05-06 14:01:28.745 I/TAG(5879): getView #4 VT=0 CV=LinearLayout text=> #### 
05-06 14:01:28.745 I/TAG(5879): getView #5 VT=1 CV=TextView text=> #### 
05-06 14:01:28.753 I/TAG(5879): getView #6 VT=1 CV=TextView text=> #### 
05-06 14:01:28.768 I/TAG(5879): getView #7 VT=1 CV=TextView text=> #### 
05-06 14:01:28.768 I/TAG(5879): getView #8 VT=1 CV=TextView text=> #### 
05-06 14:01:28.768 I/TAG(5879): getView #9 VT=1 CV=TextView text=> #### 
05-06 14:01:28.776 I/TAG(5879): getView #10 VT=1 CV=TextView text=> #### 
05-06 14:01:28.792 I/TAG(5879): getView #11 VT=1 CV=TextView text=> #### 
05-06 14:01:32.081 I/TAG(5879): getView #12 VT=1 CV=TextView text=> #### 
05-06 14:01:34.690 I/TAG(5879): getView #13 VT=1 CV=LinearLayout text=> #### 
05-06 14:01:35.573 I/TAG(5879): getView #14 VT=1 CV=TextView text=> #### 
05-06 14:01:37.237 I/TAG(5879): getView #15 VT=1 CV=TextView text=> #### 

正如你可能已經瞭解,我的佈局l項目是TextViews,分隔符佈局是一個LinearLayout。如您所見,一個「真實」物品(日誌中的VT=1,請參閱物品#13)正在回收分隔物視圖(CV=LinearLayout)。我原以爲Android會提供convertView相同的類型,所以只有當滾動時必須創建相同類型的視圖(即另一個分隔符)時纔會回收第一個分隔符。

+0

你應該接受這些答案之一。 – 2013-05-08 14:00:06

+0

我知道,但直到現在我還沒有。 – 2013-05-08 15:06:26

回答

7

正如David發現的,這與Android框架有關。如here所述,該框架不期望Spinner具有不同的視圖類型。

這是我用來做我的工作SpinnerAdapter因爲我想解決方法:

  • 店在視圖的標籤視圖類型;
  • 充氣一個新的佈局,如果沒有視圖轉換OR如果當前視圖類型從從轉換視圖不同。

這裏是我的自定義getView方法的代碼:

private View getView(final int layoutResId, final int position, final View convertView, final ViewGroup parent) { 
    View v; 

    if (convertView == null || (Integer)convertView.getTag() != getItemViewType(position)) { 
     final LayoutInflater li = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
     v = li.inflate(layoutResId, parent, false); 
    } else { 
     v = convertView; 
    } 

    v.setTag(Integer.valueOf(getItemViewType(position))); 

    final TextView tv = (TextView) v.findViewById(mTextViewResId); 
    if (tv != null) { 
     tv.setText(getText(position)); 

     if (isSeparator(position)) { 
      tv.setOnClickListener(null); 
      tv.setOnTouchListener(null); 
     } 
    } 

    return v; 
} 
+0

+1 - 這個例子使我基本上,這些標籤是無法覆蓋'''getViewTypeCount''的。我會說這個答案可能會有更多的上下文拋出;執行getItemViewType ',被重寫的'''getView'''(也許重寫的'''getDropDownView''')等等。尼韋,謝謝! – 2015-10-01 20:07:33

1

的問題是在這裏:

public View getView(final int position, final View convertView, final ViewGroup parent) { 
    return getView(mActionBarItemLayoutResId, position, convertView, parent); 
} 

此方法將總是返回View型,無論是呼籲建立一個分離器或一個數據項。您需要在此查看位置並返回適當的視圖。

+0

這個'getView'是爲'ActionBar'項目調用的,而不是下拉視圖。此外,Android正在調用'getView'和'getDropDownView',以瞭解當前項目類型和循環查看項目類型。根據我的理解(和期望),Android應該保留兩個(或'getViewTypeCount')視圖池,當滾動將它們移出可見性時,它們將被回收。所以在調用'getDropDownView'時,Android應該選擇相同類型的可回收視圖,或者提供'null'。我對嗎? – 2013-05-06 13:18:47

+0

是的,Android應該保留2個視圖池並且正確地回收它們。不管怎樣,這都是搞砸了。它變得困惑。我現在看到你已經覆蓋'getItemId()'並且總是返回0.這可能是令人困惑的事情。嘗試刪除該方法,並刪除重寫的'hasStableIds()',看看是否有幫助。 – 2013-05-06 13:35:34

+4

啊,找到了。這是一個[Android錯誤](http://code.google.com/p/android/issues/detail?id=17128):-(微視圖下拉視圖不支持多視圖回收。不便之處 – 2013-05-06 13:39:52

相關問題