Easy Tutorial
❮ Android Oom Js Call Apply Bind ❯

2.5.0 Building a Reusable Custom BaseAdapter

Category Android Basic Tutorial

Introduction to This Section:

>

As the title suggests, this section is about building a reusable custom BaseAdapter. Every time we deal with ListView, GridView, and other adapter controls, we have to write a separate BaseAdapter class, which is quite troublesome. For instance, if we want to display two ListViews on one interface, we would also need to write two BaseAdapters... Well, programmers like to take shortcuts, right? In this section, we will write a reusable custom BaseAdapter class~


1. Let's Start Gradually:

First, let's post the custom BaseAdapter we wrote in the previous section, which we will upgrade and transform later.

/**
 * Created by Jay on 2015/9/21 0021.
 */
public class MyAdapter extends BaseAdapter {

    private Context mContext;
    private LinkedList<Data> mData;

    public MyAdapter() {
    }

    public MyAdapter(LinkedList<Data> mData, Context mContext) {
        this.mData = mData;
        this.mContext = mContext;
    }

    @Override
    public int getCount() {
        return mData.size();
    }

    @Override
    public Object getItem(int position) {
        return null;
    }

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

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder = null;
        if (convertView == null) {
            convertView = LayoutInflater.from(mContext).inflate(R.layout.item_list, parent, false);
            holder = new ViewHolder();
            holder.img_icon = (ImageView) convertView.findViewById(R.id.img_icon);
            holder.txt_content = (TextView) convertView.findViewById(R.id.txt_content);
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }
        holder.img_icon.setImageResource(mData.get(position).getImgId());
        holder.txt_content.setText(mData.get(position).getContent());
        return convertView;
    }

    // Add an element
    public void add(Data data) {
        if (mData == null) {
            mData = new LinkedList<>();
        }
        mData.add(data);
        notifyDataSetChanged();
    }

    // Add an element at a specific position
    public void add(int position, Data data){
        if (mData == null) {
            mData = new LinkedList<>();
        }
        mData.add(position, data);
        notifyDataSetChanged();
    }

    public void remove(Data data) {
        if(mData != null) {
            mData.remove(data);
        }
        notifyDataSetChanged();
    }

    public void remove(int position) {
        if(mData != null) {
            mData.remove(position);
        }
        notifyDataSetChanged();
    }

    public void clear() {
        if(mData != null) {
            mData.clear();
        }
        notifyDataSetChanged();
    }

    private class ViewHolder {
        ImageView img_icon;
        TextView txt_content;
    }

}

Upgrade 1: Set Entity as a Generic Type

Alright, since the Entity class we pass may vary greatly, such as Person, Book, Weather, etc., we will set Entity as a generic type. The modified code is as follows:

public class MyAdapter<T> extends BaseAdapter {

    private Context mContext;
    private LinkedList<T> mData;

    public MyAdapter() {
    }

    public MyAdapter(LinkedList<T> mData, Context mContext) {
        this.mData = mData;
        this.mContext = mContext;
    }

    @Override
    public int getCount() {
        return mData.size();
    }

    @Override
    public Object getItem(int position) {
        return null;
    }

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

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder = null;
        if (convertView == null) {
            convertView = LayoutInflater.from(mContext).inflate(R.layout.item_list, parent, false);
            holder = new ViewHolder();
            holder.img_icon = (ImageView) convertView.findViewById(R.id.img_icon);
            holder.txt_content = (TextView) convertView.findViewById(R.id.txt_content);
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }
        holder.img_icon.setImageResource(mData.get(position).getImgId());
        holder.txt_content.setText(mData.get(position).getContent());
        return convertView;
    }

    // Add an element
    public void add(T data) {
        if (mData == null) {
            mData = new LinkedList<>();
        }
        mData.add(data);
        notifyDataSetChanged();
    }

    // Add an element at a specific position
    public void add(int position, T data){
        if (mData == null) {
            mData = new LinkedList<>();
        }
        mData.add(position, data);

Control ID, and the content set, such as setting the text of a TextView:
public ViewHolder setText(int id, CharSequence text) {Text setting}

- Move the convertView reuse part here, then you need to pass a context object, and we write the parts that need to be obtained into the constructor method!

- Write a bunch of setting methods (public), such as setting text size, color, picture background, etc.!

Okay, let's transform our ViewHolder class step by step.

---

### 1) Related parameters and constructor method:

public static class ViewHolder {

private SparseArray<View> mViews;   //Stores the Views in the ListView item
private View item;                  //Stores the convertView
private int position;               //Cursor
private Context context;            //Context

//Constructor method, completes the relevant initialization
private ViewHolder(Context context, ViewGroup parent, int layoutRes) {
    mViews = new SparseArray<>();
    this.context = context;
    View convertView = LayoutInflater.from(context).inflate(layoutRes, parent, false);
    convertView.setTag(this);
    item = convertView;
}

ImageView img_icon;
TextView txt_content;

}


---

### 2) Binding ViewHolder and Item

On the basis of the above, we add a binding method

//Bind ViewHolder and item public static ViewHolder bind(Context context, View convertView, ViewGroup parent, int layoutRes, int position) { ViewHolder holder; if(convertView == null) { holder = new ViewHolder(context, parent, layoutRes); } else { holder = (ViewHolder) convertView.getTag(); holder.item = convertView; } holder.position = position; return holder; }


---

### 3) Get the saved control in the collection according to the id

public <T extends View> T getView(int id) { T t = (T) mViews.get(id); if(t == null) { t = (T) item.findViewById(id); mViews.put(id, t); } return t; }


### 4) Then we define a bunch of exposed methods

/**

/**

/**

/**

/**

/**

/**

//Other methods can be expanded by yourself


Okay, the transformation and upgrade of ViewHolder is completed~

---

## Upgrade 3: Define an abstract method to complete the binding of ViewHolder and Data dataset

public abstract void bindView(ViewHolder holder, T obj);


When we create a new BaseAdapter, we just need to implement this method, and don't forget to change our custom BaseAdapter to abstract!

---

## Upgrade 4: Modify the content of getView()

@Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder = ViewHolder.bind(parent.getContext(), convertView, parent, mLayoutRes , position); bindView(holder,getItem(position)); return holder.getItemView(); }


---

## 2. Upgrade is complete, let's write code to experience it:

The effect we want to achieve:

There are two lists above, with different layouts, but I only use one BaseAdapter class to achieve the above effect!

The key code is as follows:

**MainActivity.java** :

public class MainActivity extends AppCompatActivity {

private Context mContext;
private ListView list_book;
private ListView list_app;

private MyAdapter<App> myAdapter1 = null;
private MyAdapter<Book> myAdapter2 = null;
private List<App> mData1 = null;
private List<Book> mData2 = null;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    mContext = MainActivity.this;
    init();

}

private void init() {

    list

The reusable BaseAdapter we wrote is used as described above.


3. Code Sample Download:

ListViewDemo4.zip

Let's post the final MyAdapter class we wrote, which can be expanded according to your own needs:

MyAdapter.java :

```java /**

private ArrayList<T> mData;
private int mLayoutRes;           // Layout ID

public MyAdapter() {
}

public MyAdapter(ArrayList<T> mData, int mLayoutRes) {
    this.mData = mData;
    this.mLayoutRes = mLayoutRes;
}

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

@Override
public T getItem(int position) {
    return mData.get(position);
}

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

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    ViewHolder holder = ViewHolder.bind(parent.getContext(), convertView, parent, mLayoutRes
            , position);
    bindView(holder, getItem(position));
    return holder.getItemView();
}

public abstract void bindView(ViewHolder holder, T obj);

// Add an element
public void add(T data) {
    if (mData == null) {
        mData = new ArrayList<>();
    }
    mData.add(data);
    notifyDataSetChanged();
}

// Add an element at a specific position
public void add(int position, T data) {
    if (mData == null) {
        mData = new ArrayList<>();
    }
    mData.add(position, data);
    notifyDataSetChanged();
}

public void remove(T data) {
    if (mData != null) {
        mData.remove(data);
    }
    notifyDataSetChanged();
}

public void remove(int position) {
    if (mData != null) {
        mData.remove(position);
    }
    notifyDataSetChanged();
}

public void clear() {
    if (mData != null) {
        mData.clear();
    }
    notifyDataSetChanged();
}

public static class ViewHolder {

    private SparseArray<View> mViews;   // Store ListView item's views
    private View item;                  // Store convertView
    private int position;               // Cursor
    private Context context;            // Context

    // Constructor, complete initialization
    private ViewHolder(Context context, ViewGroup parent, int layoutRes) {
        mViews = new SparseArray<>();
        this.context = context;
        View convertView = LayoutInflater.from(context).inflate(layoutRes, parent, false);
        convertView.setTag(this);
        item = convertView;
    }

    // Bind ViewHolder with an item
    public static ViewHolder bind(Context context, View convertView, ViewGroup parent,
                                  int layoutRes, int position) {
        ViewHolder holder;
        if (convertView == null) {
            holder = new ViewHolder(context, parent, layoutRes);
        } else {
            holder = (ViewHolder) convertView.getTag();
            holder.item = convertView;
        }
        holder.position = position;
        return holder;
    }

    @SuppressWarnings("unchecked")
    public &lt;T extends View> T getView(int id) {
        T t = (T) mViews.get(id);
        if (t == null) {
            t = (T) item.findViewById(id);
            mViews.put(id, t);
        }
        return t;
    }

    /**
     * Get the current entry
     */
    public View getItemView() {
        return item;
    }

    /**
     * Get the entry position
     */
    public int getItemPosition() {
        return position;
    }

    /**
     * Set text
     */
    public ViewHolder setText(int id, CharSequence text) {
        View view = getView(id);
        if (view instanceof TextView) {
            ((TextView) view).setText(text);
        }
        return this;
    }

    /**
     * Set image resource
     */
    public ViewHolder setImageResource(int id, int drawableRes) {
        View view = getView(id);
        if (view instanceof ImageView) {
            ((ImageView) view).setImageResource(drawableRes);
        } else {
            view.setBackgroundResource(drawableRes);
        }
        return this;
    }

    /**
     * Set click listener
     */
    public ViewHolder setOnClickListener(int id, View.OnClickListener listener) {
        getView(id).setOnClickListener(listener);
        return this;
    }

    /**
     * Set visibility
     */
    public ViewHolder setVisibility(int id, int visible) {
        getView(id).setVisibility(visible);
        return this;
    }

    /**
     * Set tag
     */
    public ViewHolder setTag(int id, Object obj) {
        getView(id).setTag(obj);
        return this;
    }

    // Other methods can be expanded by yourself

}

WeChat Follow

❮ Android Oom Js Call Apply Bind ❯