1.介绍
总结:ListView 是一个可以以垂直滚动的方式展示条目内容的一个列表,条目的内容来自于ListAdapter(适配器)。
2.操作步骤
3.ListView中convertView和ViewHolder的工作原理
Android中有个叫做Recycler(反复循环器)的构件,下图是它的工作原理:
(1)如果你有10亿个项目(item),其中只有可见的项目存在内存中,其他的在Recycler中
(2)当item1滚出屏幕,并且一个新的项目从屏幕地段上来时,ListView再请求一个type1视图。convertView此时不是空值了,它的值是item1.你只需要设定新的数据返回convertView,不必重新创建一个视图。这样直接使用convertView从而减少了很不不必要view的创建
4.典型ListView数据适配器方法分析
示例代码:
(1)xml布局文件
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="6dp" android:layout_centerVertical="true"> <TextView android:layout_marginTop="10dp" android:id="@+id/tv_phone_number" android:text="拦截号码" android:textSize="18dp" android:textColor="#000000" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <TextView android:id="@+id/tv_function_type" android:text="拦截类型" android:textSize="18dp" android:layout_below="@+id/tv_phone_number" android:layout_marginTop="10dp" android:textColor="#000000" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <!--<ImageView--> <!--android:layout_alignParentRight="true"--> <!--android:background="@drawable/selector_black_call_delete1_bg"--> <!--android:layout_width="wrap_content"--> <!--android:layout_height="wrap_content" />--> <!--android:background="@drawable/selector_black_call_delete1_bg"--> <ImageView android:id="@+id/iv_black_call_delete" android:layout_alignParentRight="true" android:background="@drawable/selector_black_call_delete1_bg" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </RelativeLayout>
(2)java后台代码:
/** * listview的数据适配器 */ private class MyAdapter extends BaseAdapter { //getCount决定了listview一共有多少个item @Override public int getCount() { return blackCallList.size(); } //获得相应数据集合中特定位置的数据项 @Override public Object getItem(int position) { return blackCallList.get(position); } //返回该postion对应item的id @Override public long getItemId(int position) { return position; } //getView()返回了每个item项所显示的view @Override public View getView(final int position, View convertView, ViewGroup parent) { //复用convertView,并减少了findViewById的次数 ViewHolder holder=null; //1.convertView为空,代表当前的条目是首次构建,需要查找控件,查找到的控件在后续的条目中可以去做复用 if(convertView==null){ convertView=View.inflate(getApplicationContext(), R.layout.listview_black_list_call_item, null); //2.创建一个ViewHolder对象,去存储所找到的控件 holder=new ViewHolder(); holder.tv_phone_number=convertView.findViewById(R.id.tv_phone_number); holder.tv_function_type=convertView.findViewById(R.id.tv_function_type); holder.iv_black_call_delete=convertView.findViewById(R.id.iv_black_call_delete); //3.存储当前的ViewHolder对象 convertView.setTag(holder); }else { //4.复用convertView中存储的ViewHolder对象 holder= (ViewHolder) convertView.getTag(); } holder.tv_phone_number.setText(blackCallList.get(position).getPhoneNumber()); holder.tv_function_type.setText(blackCallList.get(position).getFunctionType()); //给图片imageview绑定点击事件 holder.iv_black_call_delete.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { BlackListCallDBUtil.deleteOneRecord(blackCallList.get(position).getPhoneNumber(),blackCallList.get(position).getFunctionType()); initData(); //重新显示列表数据 } }); return convertView; } private class ViewHolder { public TextView tv_phone_number; public TextView tv_function_type; public ImageView iv_black_call_delete; } }
(1)getCount()方法:决定了listview一共有多少个item(条目)
(2)getItem()方法:获得相应数据集合中特定位置的数据项
常用于:listview的点击事件(例如setOnItemSelectedListener),方便地调用来获取获取当前行数据。
(3)getItemId()方法:返回该postion对应item的id
(4)getView()方法:返回了每个item项所要显示的view
5.内存溢出问题(快速拖到条目)
利用getView(int i, View view, ViewGroup viewGroup) 方法的第二个参数,回收已经隐藏的组件
6.listView 显示数据的原理
mvc模式:
<1>javaweb中
m:mode 数据 ;v:view 视图 jsp ;c:controller servlet
<2>Android
m:mode 数据(javabean)
v:view 视图 组件
c:adapter (适配器)
注意:无论是哪种Adapter,其作用都是把数据展示到listview中
7.xml布局
<1>activity_main.xml布局
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <ListView android:id="@+id/lv_message" android:layout_width="match_parent" android:layout_height="match_parent"> </ListView> </LinearLayout>
注意:ListView的高度必须设置为 android:layout_height="match_parent"
<2>item_show.xml布局
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="wrap_content"> <ImageView android:id="@+id/imageView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@mipmap/ic_launcher" /> <TextView android:id="@+id/tv_title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@+id/imageView" android:ellipsize="end" android:singleLine="true" android:text="掘金115-105雷霆,默里27+5+9,约基奇23+16,威少27+9+9,乔治25+9" android:textColor="#000000" android:textSize="20dp" /> <TextView android:id="@+id/tv_content" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/tv_title" android:layout_toRightOf="@+id/imageView" android:ellipsize="end" android:maxLines="2" android:textColor="#6D6E72" android:text="虎扑3月30日讯,雷霆坐镇主场迎来了掘金的挑战。首节比赛,约基奇展现了自己在内线的统治力,4投4中单节砍下10分7篮板2助攻。于此同时,还让对位的雷霆中锋亚当斯在首节数据挂零。凭借约基奇的出色表现,掘金在首节就取得了33-29的领先。次节比赛,掘金攻势依然凶猛,开场一波7-0的小高潮立刻将分差拉大到了两位数。但首节表现低迷的亚当斯终于迎来了复苏,5投全中砍下10分,帮助雷霆奋起直追,最终雷霆成功将分差再次缩小到了4分,两队的比分定格在了56-52。" android:textSize="15dp" /> </RelativeLayout>
注意:采用相对布局,若图片不能加载,设置图片来源为 android:src="@mipmap/ic_launcher"
8.java后台
package com.example.lucky.test53listview; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ListView; import android.widget.TextView; public class MainActivity extends AppCompatActivity { ListView lv_message; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); lv_message=findViewById(R.id.lv_message); lv_message.setAdapter(new MyListAdapter()); } //ListView的数据适配器 public class MyListAdapter extends BaseAdapter{ //设置一共需要显示的数据条数 @Override public int getCount() { return 60; } //返回position位置对应的对象 @Override public Object getItem(int i) { return null; } //返回position位置对应的id @Override public long getItemId(int i) { return 0; } //获取一个view,用来显示ListView的数据,会作为ListView的一个条目出现 //参数2为历史缓存对象(页面一次会显示的textView对象都是新创建的,当用户滑动列表时,后面显示textview 是复用前面的view) @Override public View getView(int i, View view, ViewGroup viewGroup) { View viewShow; if(view==null){ //创建新的view对象,可以通过打气筒(View.inflate())把一个布局资源转换成一个view对象 viewShow=View.inflate(getApplicationContext(),R.layout.item_show,null); System.out.println("创建新的view对象"+i); }else { System.out.println("复用历史缓存对象"+i); viewShow= view; } return viewShow; } } }
9.效果图