9.Android 万能ViewHolder

9.Android 万能ViewHolder

  • Android 万能ViewHolder
    • ViewHolder的作用
    • 万能ViewHolder的原理
    • 在你的BaseListAdapter中可以这么实现

ViewHolder的作用

Adapter的getVIew()以得到旧视图(convertView):

    /**
     * Get a View that displays the data at the specified position in the data set. You can either
     * create a View manually or inflate it from an XML layout file. When the View is inflated, the
     * parent View (GridView, ListView...) will apply default layout parameters unless you use
     * {@link android.view.LayoutInflater#inflate(int, android.view.ViewGroup, boolean)}
     * to specify a root view and to prevent attachment to the root.
     * 
     * @param position The position of the item within the adapter's data set of the item whose view
     *        we want.
     * @param convertView The old view to reuse, if possible. Note: You should check that this view
     *        is non-null and of an appropriate type before using. If it is not possible to convert
     *        this view to display the correct data, this method can create a new view.
     *        Heterogeneous lists can specify their number of view types, so that this View is
     *        always of the right type (see {@link #getViewTypeCount()} and
     *        {@link #getItemViewType(int)}).
     * @param parent The parent that this view will eventually be attached to
     * @return A View corresponding to the data at the specified position.
     */
    View getView(int position, View convertView, ViewGroup parent);

看过精致Adapter都知道,ListView的一个Item移出屏幕的范围,和一个Item进入屏幕的范围的时候,Adapter的getView(int position, View convertView, ViewGroup parent)里都能得到这个Item的View,也就是上述所说的旧视图(convertView) 。ListView的的Item如果样式都是一样的话,我们可以拿到旧视图的View,然后根据ViewId上的去取得组件并修改其内容,然后return该View。达到复用的效果。所以这里,涉及到了ViewHolder去保存该View上组件的各个ViewId,并且将ViewHolder继续保存到return的convertView的tag中,以供下一次拿到convertView时取得,规避了ViewHolder的不断创建,也实现了ViewHolder的复用。

其实findViewById()的性能是很低的,引入ViewHolder的目的也是为减少getView()时findViewById()的次数。

万能ViewHolder的原理

类似于内部存放了一个字典,用于根据ViewId得到View。

    public class ViewHolder {
        private final SparseArray<View> views;
        private View convertView;

        public ViewHolder(View convertView) {
            this.views = new SparseArray<>();
            this.convertView = convertView;
        }

        public <T extends View> T findViewById(int viewId) {
            View view = views.get(viewId);
            if (view == null) {
                view = convertView.findViewById(viewId);
                views.put(viewId, view);
            }
            return (T) view;
        }
    }

在你的BaseListAdapter中可以这么实现


    public abstract View getView(int position, View convertView, ViewHolder viewHolder);

    @Override
    public final View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder viewHolder;
        if (convertView == null) {
            convertView = mInflater.inflate(getItemLayout(), null);
            viewHolder = new ViewHolder(convertView);
            convertView.setTag(viewHolder);
        } else {
            viewHolder = (ViewHolder) convertView.getTag();
        }
        try {
            return getView(position, convertView, viewHolder);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return convertView;

    }

这样的话可以让BaseListAdapter的子类强制继承getView然后与BaseListAdapter的getView对接后续操作。相当于执行了:BaseListAdapter.getView() -> BaseListAdapter子类.getView()

你可能感兴趣的:(android,viewholder,万能ViewHold)