自定义BaseAdapter如何重写getItem和getItemId

Posted Ang_qq_252390816

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了自定义BaseAdapter如何重写getItem和getItemId相关的知识,希望对你有一定的参考价值。

前言

在自定义BaseAdapter的时候经常忽略getItem()和getItemId()两个方法,最近在使用Spinner实现下拉框的时候配和BaseAdapter实现自定义布局;但是按常规方法不重写getItem()和getItemId(),也就是默认的写法导致出现了一些问题;所以这里研究了一下BaseAdapter的源码;

方法解释

getItem()   获取与数据集中指定位置关联的数据项

getItemId()  获取与列表中指定位置关联的行ID

一般自定义BaseAdapter(对BaseAdapter做了优化的写法,自定义ViewHolder复用view)如下:

class MyBaseAdapter extends BaseAdapter {

    private List list = new ArrayList<>();
    public MyBaseAdapter(List list) {
        this.list = list;
    }

    @Override
    public int getCount() {
        return list.size();
    }
    
    @Override
    public Object getItem(int i) {
        return null;
    }

    @Override
    public long getItemId(int i) {
        return 0;
    }
    
    @Override
    public View getView(int i, View view, ViewGroup viewGroup) {//获取视图
        LayoutInflater layoutInflater = LayoutInflater.from(viewGroup.getContext());
        ViewHolder holder;
        if (view == null) {
            holder = new ViewHolder();
            view = layoutInflater.inflate(R.layout.adapter_item, null);
            view.setTag(holder);
            holder.imageView = view.findViewById(R.id.imageView);
            holder.textView = view.findViewById(R.id.textView);
        }else {
            holder = (ViewHolder) view.getTag(); //复用View
        }
        holder.imageView.setImageResource(list.get(i).getUrlInt());
        holder.textView.setText(list.get(i).getName());
        return view;
    }

    static class ViewHolder {
        ImageView imageView;
        TextView textView;
    }

}

可以看到自定义BaseAdapter自动生成的getItem()和getItemId()一般不做改变,只重写getView和getCount这个两个方法;

如果和Spinner配合使用,Spinner设置setOnItemSelectedListener监听,在onItemSelected种通过getItemAtPosition(i) 和 getSelectedItem()方法获取点击的item的数据时,会引发空指针,就是因为没有重写getItem()方法;

spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {

        @Override
        public void onItemSelected(AdapterView adapterView, View view, int i, long l) {
            TextView textView = view.findViewById(R.id.textView);
            Toast.makeText(MainActivity.this, textView.getText(), Toast.LENGTH_SHORT).show();
            adapterView.getItemAtPosition(i);//空指针
            adapterView.getSelectedItem(); //空指针
    
        }

        @Override
        public void onNothingSelected(AdapterView adapterView) {

        }
});

查看AdapterView源码发现getItemAtPosition(i) 和 getSelectedItem()都调用了getAdapter()获取一个Adapter,从源码也可以看出getAdapter是一个抽象方法,需要子类重写,我们使用的Spinner就是AdapterView的子类从源码不难发现,使用Spinner的时候会设置一个Adapter;所以这个getAdapter获取到的Adapter就是我们给Spinner设置的自定义的BaseAdapter;显然getItemAtPosition() 和 getSelectedItem()中的 adapter.getItem(selection)最终调用的是自定义的BaseAdapter中的getItem()方法获取到的数据是点击某个Item的数据;所以出现空指针的问题所在就是没有重写BaseAdapter中的getItem()方法;

public Object getSelectedItem() {
    T adapter = getAdapter();
    int selection = getSelectedItemPosition();
    if (adapter != null && adapter.getCount() > 0 && selection >= 0) {
        return adapter.getItem(selection);
    } else {
        return null;
    }
}
public Object getItemAtPosition(int position) {

    T adapter = getAdapter();
    return (adapter == null || position < 0) ? null : adapter.getItem(position);
}
public abstract T getAdapter();

接下怎么从写getItem和getItemId方法呢;我们可以查看一下ArrayAdapter的源码就知道怎么写了,

@Override
public @Nullable T getItem(int position) {
    return mObjects.get(position); //mObjects就是上面我们自定义的MyBaseAdapter 中的list;
}
@Override
public long getItemId(int position) {
    return position;
}

所以最终的自定义的BaseAdapter

class MyBaseAdapter extends BaseAdapter {

    private List list = new ArrayList<>();

    public MyBaseAdapter(List list) {
        this.list = list;
    }

    @Override

    public int getCount() {
        return list.size();
    }

    @Override
    public Object getItem(int i) {
        return list.get(i);
    }

    @Override
    public long getItemId(int i) {
        return i;
    }

    @Override

    public View getView(int i, View view, ViewGroup viewGroup) {
        LayoutInflater layoutInflater = LayoutInflater.from(viewGroup.getContext());
        ViewHolder holder;
        if (view == null) {
            holder = new ViewHolder();
            view = layoutInflater.inflate(R.layout.adapter_item, null);
            view.setTag(holder);
            holder.imageView = view.findViewById(R.id.imageView);
            holder.textView = view.findViewById(R.id.textView);
        }else {
            holder = (ViewHolder) view.getTag(); //复用View
        }

        holder.imageView.setImageResource(list.get(i).getUrlInt());
        holder.textView.setText(list.get(i).getName());
        return view;

    }

    static class ViewHolder {
        ImageView imageView;
        TextView textView;
    }
}

以上自定义BaseAdapter 是采用了优化的方式;

以上是关于自定义BaseAdapter如何重写getItem和getItemId的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 baseadapter 自定义列表视图

如何将数据添加到 listView 的自定义 BaseAdapter - Android

如何在android中使用baseadapter刷新自定义列表视图

使用 CardView BaseAdapter OnItemClick 自定义 ListView

构建一个可复用的自定义BaseAdapter

android-BaseAdapter自定义控件深刻理解