Warum ist Android recycling die falsche Ansicht Typ in meinem SpinnerAdapter?

Ich versuche, einen ActionBar Spinner zu machen, der Trennzeichen hat. Ich habe einen SpinnerAdapter implementiert, der 2 Item View-Typen hat (dank getViewTypeCount ). Das Problem ist, dass ich einige convertViews von der anderen Art gesendet convertViews .

Hier ist mein 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; } } 

Eine Implementierung:

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

Wie Sie vielleicht bemerkt haben, habe ich eine Log-Zeile in getView() damit ich besser verstehe, was los ist:

 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=> #### 

Wie Sie vielleicht verstanden haben, sind meine Layouts für die realen Items TextViews, und das Trennzeichen ist ein LinearLayout.

Wie Sie sehen können, wird ein "echtes" Element ( VT=1 im Protokoll, siehe Punkt 13) eine CV=LinearLayout ( CV=LinearLayout ) CV=LinearLayout . Ich hätte gedacht, dass Android eine convertView des gleichen Typs bereitstellen würde, also würde der erste Trenner nur dann recycelt werden, wenn beim Scrollen eine Ansicht des gleichen Typs (dh ein anderer Trennzeichen) erzeugt werden müsste.

2 Solutions collect form web for “Warum ist Android recycling die falsche Ansicht Typ in meinem SpinnerAdapter?”

Als David herausfand, ist dies mit dem Android-Framework verwandt. Wie hier erwähnt , erwartet das Framework nicht, dass Spinner s unterschiedliche View-Typen hat.

Dies ist die Umgehung, die ich verwendet habe, um meine SpinnerAdapter Arbeit zu machen, wie ich wollte:

  • Speichern Sie den Ansichtstyp in der Ansicht der Ansicht.
  • Aufblasen eines neuen Layouts, wenn es keine Sicht zum Konvertieren von ODER gibt, wenn sich der aktuelle View-Typ von der Ansicht unterscheidet.

Hier ist der Code meiner benutzerdefinierten getView Methode:

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

Das Problem ist hier:

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

Diese Methode wird immer denselben View Typ zurückgeben, egal ob für einen Trenner oder ein Datenelement. Sie müssen die Position hier überprüfen und eine entsprechende Ansicht zurückgeben.

Das Android ist ein Google Android Fan-Website, Alles ├╝ber Android Phones, Android Wear, Android Dev und Android Spiele Apps und so weiter.