900字范文,内容丰富有趣,生活中的好帮手!
900字范文 > Android Listview 自定义BaseAdapter的实现及Listview优化示例

Android Listview 自定义BaseAdapter的实现及Listview优化示例

时间:2024-06-27 19:16:54

相关推荐

Android Listview 自定义BaseAdapter的实现及Listview优化示例

上一篇文章中我们讲了Android Listview SimpleAdapter的使用完整示例(实现用户列表)_左眼看成爱的博客-CSDN博客

本示例实现的效果图:

每个item中的checkbox选中事件实现单独监听处理:

取消选中:

整个item点击事件(共存):

这篇文章我来讲一下自定义BaseAdapter的实现示例及优势在哪里? 通过查看SimpleAdapter的实现源码,我们可以发现SimpleAdapter实现的view复用方式其实就是convertView复用。但并没有避免复用时重复的调用findViewById,所以SimpleAdapter很难实现给item中的按钮或Checkbox单独添加监听事件。而且使用SimpleAdapter也无法解决Listview中带checkbox时滑动选中状态混乱的问题。

所以通常我们都会自定义一个继承自BaseAdapter(已继承ListViewAdapter)来实现更加灵活强大的listview适配器,通过查看源码可以发现:ArrayAdapter(继承自BaseAdapter),SimpleAdapter(继承自BaseAdapter)的类,所以,这节我们讲一下如何重写BaseAdapter 重写getView()方法,如何使用ViewHolder优化findView次数来实现我们自己想要的功能。

基于 BaseAdapter 使用 ListView

添加 ListView 组件,存放数据,设置列表项的布局文件都和 SimpleAdapter 中的操作相同

创建一个 Adapter 继承 BaseAdapter,并实现抽象方法。

BaseAdapter 有 4 个抽象方法需要去实现:

int getCount(); //返回的是数据源对象的个数,即列表项数Object getItem(int var1); //返回指定位置position上的列表项long getItemId(int var1); //返回指定位置处的行IDView getView(int var1, View var2, ViewGroup var3); //返回列表项对应的视图

继承 BaseAdapter 时需要去实现这 4 个抽象方法,这几个抽象方法都是 Adapter 接口中定义的方法。

前三个方法基本很简单不需要太多关注,重点在getView方法的实现

继承 BaseAdapter 基本样式:

package com.example.Listview_BaseAdapter;/*** @author wh445306* @version 1.0* @Description MyAdapter* @Date -03-17 13:10*/public class MyAdapter extends BaseAdapter {List<Map<String,Object>> list;LayoutInflater mInflater;Context context;// MyAdapter构造函数 建议把上下文context也传进来public MyAdapter(Context context, List<Map<String, Object>> list){super();mInflater = LayoutInflater.from(context);this.list = list;this.context=context;}@Overridepublic int getCount() {return list.size();}@Overridepublic Object getItem(int position) {return list.get(position);}@Overridepublic long getItemId(int position) {return position;}@Overridepublic View getView(final int position, View convertView, ViewGroup parent) {return null;}}

public View getView(final int position, View convertView, ViewGroup parent) {

return null;

}

第一个参数: int position,一般BaseAdapter都是很多类型一样的数据展示在界面,

该属性是判断显示在界面上的是第几个,通过position在BaseAdapter自定义的数组或者集合中取值。并展示在界面上。

第二个参数: View converView View converView是展示在界面上的一个item。因为手机屏幕就那么大,所以一次展示给用户看见的内容是固定的,如果你List中有1000条数据,不应该new1000个converView,那样内存肯定不足,应该学会控件重用,滑出屏幕的converView就在下面新进来的item中重新使用,只是修改下他展示的值。这样能减去很多消耗。

不过有的时候我们不能对其进行重构 比如带CheckBox的item,如果你使用判断,在你选中某个item的CheckBox时滑动时会出现混乱,这时你就必须去掉判断对其进行重构。

第三个参数:ViewGroup parent 这个属性是加载xml视图时使用。

所以在下面的代码中我们为了提高性能会先判定converView是否为空,为空的话猜重新创建并且后面选择保存布局到缓存

下面我们上一个完整示例代码:

MainActivity单元:

package com.example.Listview_BaseAdapter;import android.util.Log;import android.view.View;import android.widget.AdapterView;import android.widget.ListView;import android.widget.Toast;import androidx.appcompat.app.AppCompatActivity;import android.os.Bundle;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;public class MainActivity extends AppCompatActivity {String[] names={"张三","李四","王五","听雨","若兰","海子","大眼","卡卡","小米","小恐龙"};String[] ids={"wh445306","jyw8886","bmw8899","xx8yzz","888yzx","776yy9","99zz9","ka8ka8","xiaoni8","xkl888"};String[] ages={"28岁","27岁","22岁","24岁","28岁","18岁","15岁","13岁","17岁","20岁"};//String[] tels={"18322228898","13922278898","13719780706","15322228898"};//int[] pics={R.drawable.userface1,R.drawable.userface2,R.drawable.userface3,R.drawable.userface4};List<Map<String,Object>> list = new ArrayList<>();@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);for (int i = 0; i < names.length; i++) {Map<String,Object> map= new HashMap<>();map.put("name",names[i]);map.put("id",ids[i]);map.put("age",ages[i]);map.put("tel","138"+(int)(Math.random()*90000000+10000000));int picID = getResources().getIdentifier("userface"+(i+1), "drawable", getPackageName());map.put("pic",picID);map.put("box",false);list.add(map);}ListView listView=findViewById(R.id.lvTest);/* 使用SimpleAdapterSimpleAdapter adapter = new SimpleAdapter(MainActivity.this, list,R.layout.list_item,new String[] { "name", "id", "age","tel","pic" },new int[] { R.id.txtUserName, R.id.txtUserID, R.id.txtUserAge,R.id.txtUserTel,R.id.imgHead });*/// 使用BaseAdapterMyAdapter adapter =new MyAdapter(this,list);listView.setAdapter(adapter);//为 ListView 的列表项添加鼠标点击事件listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {/*** @param adapterView 发生单击事件的列表项 ListView* @param view view是当前listview中的item的view的布局,就是可用这个view获取里面控件id后操作控件* @param i 在列表项中的位置 position* @param l 被单击列表项的行ID*/@Overridepublic void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {String Tag = "onItemClick======";Log.d(Tag, "position=" + i);Log.d(Tag, "行 ID" + l);/* HashMap<String,String> map=(HashMap<String,String>)adapterView.getItemAtPosition(i);String Text= map.get("name");String id= map.get("id");*/String Text= list.get(i).get("name").toString();String id= list.get(i).get("id").toString();Toast.makeText(MainActivity.this, "您点击的行:Name:="+Text+" id:="+id, Toast.LENGTH_SHORT).show();}});}}

BaseAdapter实现单元:

package com.example.Listview_BaseAdapter;import android.content.Context;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.*;import java.util.HashMap;import java.util.List;import java.util.Map;/*** @author wh445306* @version 1.0* @Description MyAdapter* @Date -03-17 13:10*/public class MyAdapter extends BaseAdapter {List<Map<String,Object>> list;LayoutInflater mInflater;Context context;// 用于记录listView中的复选框有哪些是被选中的HashMap<Integer, Boolean> state = new HashMap<>();// MyAdapter构造函数 建议把上下文context也传进来public MyAdapter(Context context, List<Map<String, Object>> list){super();mInflater = LayoutInflater.from(context);this.list = list;this.context=context;}@Overridepublic int getCount() {return list.size();}@Overridepublic Object getItem(int position) {return list.get(position);}@Overridepublic long getItemId(int position) {return position;}@Overridepublic View getView(final int position, View convertView, ViewGroup parent) {ViewHolder holder;if(convertView==null){// 首次convertView为null时才会加载item布局文件holder= new ViewHolder();convertView= mInflater.inflate(R.layout.list_item,null);// 通过ViewHolder持有view中的子控件holder.name=convertView.findViewById(R.id.txtUserName);holder.id=convertView.findViewById(R.id.txtUserID);holder.age=convertView.findViewById(R.id.txtUserAge);holder.tel=convertView.findViewById(R.id.txtUserTel);holder.pic=convertView.findViewById(R.id.imgHead);holder.box =convertView.findViewById(R.id.chkBox);// 再通过setTag的形式和view绑定convertView.setTag(holder);}else {holder= (ViewHolder) convertView.getTag();}// 使用ViewHolder实现View组件的缓存和重用,重用View时就不用通过findViewById重新寻找view组件Map<String,Object> map = list.get(position);//holder.name.setText((String)list.get(position).get("name"));holder.name.setText((String)map.get("name"));holder.id.setText((String)map.get("id"));holder.age.setText((String)map.get("age"));holder.tel.setText((String)map.get("tel"));holder.pic.setImageResource((int) map.get("pic"));//holder.box.setChecked((Boolean) map.get("box"));// 根据state设置复选框是否被选中// 但是由于setChecked方法会触发下面setOnCheckedChangeListener// 所以需要在setOnCheckedChangeListener中添加一句,判断是用户点击的才触发处理holder.box.setChecked(state.get(position));holder.box.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {@Overridepublic void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {// 忽略非人为点击if(!buttonView.isPressed())return;// 记录那些复选框被选中,保存在List<map>中if (isChecked) {state.put(position, isChecked);} else {state.remove(position);}// 在这里处理选中或取消选中的操作if (isChecked) {Toast.makeText(context, "您选中了:Name:="+ list.get(position).get("name"), Toast.LENGTH_SHORT).show();} else {Toast.makeText(context, "您取消了选中:Name:="+ list.get(position).get("name"), Toast.LENGTH_SHORT).show();}}});return convertView;}// 定义一个ViewHolder静态类来持有convertView的每一个子控件public static class ViewHolder{public TextView name;public TextView id;public TextView age;public TextView tel;public ImageView pic;public CheckBox box;}}

item布局:

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="/apk/res/android"xmlns:tools="/tools"xmlns:app="/apk/res-auto"android:layout_width="match_parent"android:layout_height="match_parent"><!--顶部头像信息栏布局--><LinearLayoutandroid:orientation="horizontal"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_margin="10dp"><androidx.cardview.widget.CardViewandroid:id="@+id/imgCard"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"app:cardCornerRadius="5dp"app:cardElevation="5dp"android:layout_margin="10dp"><ImageViewandroid:id="@+id/imgHead"android:layout_width="100dp"android:layout_height="100dp"android:src="@drawable/userface1"/></androidx.cardview.widget.CardView><LinearLayoutandroid:orientation="vertical"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="5dp"><TextViewandroid:id="@+id/txtUserName"android:text="IT情深"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textColor="#000000"android:textSize="18sp"/><LinearLayoutandroid:orientation="horizontal"android:layout_width="wrap_content"android:layout_height="wrap_content"><TextViewandroid:text="ID:"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="5dp"/><TextViewandroid:id="@+id/txtUserID"android:text="wh445306"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginLeft="5dp"android:layout_marginTop="5dp"/></LinearLayout><LinearLayoutandroid:orientation="horizontal"android:layout_width="match_parent"android:layout_height="wrap_content"><TextViewandroid:text="年龄:"android:layout_width="wrap_content"android:layout_height="wrap_content" /><TextViewandroid:id="@+id/txtUserAge"android:text="28岁"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginLeft="5dp" /><CheckBoxandroid:id="@+id/chkBox"android:layout_width="wrap_content"android:layout_height="wrap_content"android:focusable="false"android:focusableInTouchMode="false"/></LinearLayout><LinearLayoutandroid:orientation="horizontal"android:layout_width="wrap_content"android:layout_height="wrap_content"><TextViewandroid:text="手机号码:"android:layout_width="wrap_content"android:layout_height="wrap_content"/><TextViewandroid:id="@+id/txtUserTel"android:text="13318780706"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginLeft="5dp"/></LinearLayout><LinearLayoutandroid:orientation="horizontal"android:layout_width="wrap_content"android:layout_height="wrap_content"><TextViewandroid:text="最后登录时间:"android:layout_width="wrap_content"android:layout_height="wrap_content"/><TextViewandroid:id="@+id/txtLastIP"android:text="-03-11 14:56"android:layout_width="match_parent"android:layout_height="wrap_content"/></LinearLayout></LinearLayout></LinearLayout></LinearLayout>

主布局文件

<?xml version="1.0" encoding="utf-8"?><LinearLayoutxmlns:android="/apk/res/android"xmlns:tools="/tools"xmlns:app="/apk/res-auto"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"tools:context=".MainActivity"><ListViewandroid:id="@+id/lvTest"android:layout_width="match_parent"android:layout_height="match_parent"/></LinearLayout>

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。