为什么Android的回收在我SpinnerAdapter错误的视图类型? [英] Why is Android recycling the wrong view type in my SpinnerAdapter?

查看:161
本文介绍了为什么Android的回收在我SpinnerAdapter错误的视图类型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图做一个动作条微调,有分隔符。我实现了一个 SpinnerAdapter ,有2项视图类型(感谢 getViewTypeCount )。问题是,我被送到一些 convertViews 从其他类型的。

I'm trying to make an ActionBar spinner that has separators. I have implemented a SpinnerAdapter that has 2 item view types (thanks to getViewTypeCount). The problem is that I'm being sent some convertViews from the other type.

下面是我的SpinnerAdapter:

Here's my 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()让我更好地了解发生了什么:

As you may have noticed, I have set a log line into getView() so that I better understand what's going on:

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

正如你可能已经明白,我的布局为真正的项目是TextViews和隔板布局是一个LinearLayout中。

As you may have understood, my layouts for the real items are TextViews, and the separator layout is a LinearLayout.

正如你所看到的,真正的项目(VT = 1 在日志中,见项目#13 <$ C C $>)正在再造一个分离器视图( CV =的LinearLayout )。我本来以为机器人将提供一个 convertView 同类型的,所以第一个符号将被回收只有在相同类型的视图(即另一个分离器)将有滚动时被创建。

As you can see, a "real" item (VT=1 in the log, see item #13) is being recycling a separator view (CV=LinearLayout). I would have thought that Android would provide a convertView of the same type, so the first separator would be recycled only if a view of the same type (i.e. another separator) would have to be created when scrolling.

推荐答案

当大卫发现,这是关系到Android框架。正如这里,框架不期望微调 s到具有不同的视图类型。

As David found out, this is related to the Android framework. As noted here, the framework doesn't expect Spinners to have different view types.

这是我用来做我SpinnerAdapter工作,因为我想要的解决方法:

This is the workaround I used to make my SpinnerAdapter work as I wanted:

  • 存储视图类型的视图的标签;
  • 充气一个新的布局,如果没有视图转换的如果当前视图类型不同的观点,从转换。

下面是我的自定义的code getView 方法:

Here's the code of my custom getView method:

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

这篇关于为什么Android的回收在我SpinnerAdapter错误的视图类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆