ListView是Android中最重要的组件之一,几乎每个Android应用中都会使用ListView。 它以垂直列表的方式列出所需的列表项。
列表的显示需要三个元素 | 内容 |
---|---|
ListVeiw | 用来展示列表的View |
数据源 | 具体的将被映射的字符串、图片,或者基本组件 |
适配器 | 用来把数据映射到ListView上的中介 |
为什么要进行优化
在使用ListView展示数据时需要创建对应的Item条目展示每条数据,如果展示的数据有成千上万条,那么就需要创建成千上万个Item,这样会大大增加内存的消耗,甚至会由于内存溢出导致程序崩溃。
而使用的框架中,就对ListView进行了优化1.复用convertView;2.使用DViewHolder类,防止了这种情况出现。
使用ListView注意以下两点
1.数据源:有时会用多个数组来引用数据,其实是非常不合适的,因为一旦涉及添加会重新new,浪费内存;另外, 还会造成两个数组的不一致性;实际开发时应该封装为类,在下面实例中展示!
// 需要适配的数据
private String[] names = {"京东商城", "QQ", "QQ斗地主", "新浪微博","天猫","UC浏览器", "微信"};
// 图片集合
private int[] icons = {R.drawable.jd, R.drawable.qq, R.drawable.dz, R.drawable.xl, R.drawable.tm, R.drawable.uc,R.drawable.wx};
2.适配器:一个连接数据和AdapterView的桥梁,通过它能有效地实现数据与 AdapterView的分离设置,使AdapterView与数据的绑定更加简便,修改更加方便。将数据源的数据适配到ListView中的常用适配器有
➢ ArrayAdapter:最为简单,只能展示一行字
➢ SimpleAdapter:有最好的扩充性,可以自定义各种各样的布局,除了文本外, 还可以放ImageView(图片)、Button(按钮)、CheckBox(复选框)等等
➢ SimpleCursorAdapter:可以认为是SimpleAdapter对数据库的简单结合,可以 方便地把数据库的内容以列表的形式展示出来
➢ 实际工作中,常用自定义适配器。即继承于BaseAdapter的自定义适配器类。实例中展示!
在AS中以Android应用市场为例,来使用这个框架;
1.新建程序,设计用户交互界面
2.新建Item的布局(名称Itme随意起的展示用,不建议这么做)
3.应用的框架(核心部分+可扩展部分)
核心部分:DAdapter.java和DViewHolder.java
可扩展部分:MyAdapter.java和Infos.java
DAdapter.java
package com.example.listview_frame;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import java.util.List;
//MyAdapter的框架类DAdapter<T>
public abstract class DAdapter<T> extends BaseAdapter{
private Context context;//Context对象,加载当前布局
private List<T> dataList;//不用new ArrayList<Infos>(),多余
//DAdapter构造方法
public DAdapter(Context context) {
super();
//最好在构造方法中传入Context对象的值,避免忘记
this.context = context;
}
//获取List<>数据
public List<T> getDataList() {
return dataList;
}
//设置List<>数据
public void setDataList(List<T> dataList) {
this.dataList = dataList;
}
//获取Context对象
public Context getContext() {
return context;
}
@Override
public int getCount() {
//返回ListView Item条目的总数
if (null!=dataList){
//有多少个数据,getView()重复多少次
return dataList.size();
}
return 0;//return 999//瀑布流
}
@Override
public Object getItem(int position) {
//返回ListView Item条目代表的对象
return position;//return position%7//瀑布流
}
@Override
public long getItemId(int position) {
//返回ListView Item的id
return position;//return position%7//瀑布流
}
@Override
//得到Item的View视图
//getView()设置成抽象方法,用户在这个类的子类中实现getView()方法
//方便用户使用自己的逻辑得到Item的View视图
//position是当前Item的位置,convertView用于复用旧视图,parent用于加载xml布局
public abstract View getView(int position, View convertView, ViewGroup parent);
}
DViewHolder.java
package com.example.listview_frame;
import android.util.SparseArray;
import android.view.View;
//ViewHolder的框架类DViewHolder
//用于传递数据的DViewHolder
public class DViewHolder {
public static <T extends View> T get(View view, int id) {
//viewHolder是一个Map<Integer,V> map,存放传入的view.getTag();
SparseArray<View> viewHolder = (SparseArray<View>) view.getTag();
if (viewHolder == null) {
//如果viewHolder为空,新建并setTag()
viewHolder = new SparseArray<View>();
view.setTag(viewHolder);
}
//新建View对象childView,存放传入的view里的id
View childView = viewHolder.get(id);
if (childView == null) {
//childView为空,绑定id
childView = view.findViewById(id);
//存放到viewHolder中,下次取就不为空了
viewHolder.put(id, childView);
}
return (T) childView;
}
}
4.编写使用者自己逻辑的MyAdapter类用于数据适配
MyAdapter.java
package com.example.listview_frame;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
public class MyAdapter extends DAdapter<Infos>{
public MyAdapter(Context context) {
super(context);
}
@Override
public View getView(int position, //当前item的位置
View convertView,//用于复用旧视图,回收站
ViewGroup parent) {//此视图最终将附加到的父级,用于加载XML布局
if (convertView == null) {
//convertView为空的话,就在新视图新建Item
convertView = LayoutInflater.from(getContext()).//获取Context对象
inflate(R.layout.item, parent, false);
//参数inflate(Item布局的资源id,父视图,依附父视图)
}
//convertView不为空的话,就获取convertView里Item的数据
ImageView imageView = DViewHolder.get(convertView, R.id.item_image);
TextView textView = DViewHolder.get(convertView, R.id.item_tv);
//获取当前position对应Item中的数据
Infos infos = getDataList().get(position);//position%7//瀑布流
//获取的数据设置到新视图的Item中
imageView.setBackgroundResource(infos.getResId());
textView.setText(infos.getName());
//返回convertView
return convertView;
}
}
5.编写封装每个Item数据的类Infos类
Infos.java
package com.example.listview_frame;
//将ListView需要的数据封装成类
public class Infos {
//声明数据类型,用成员变量存数据
private String name;//字符型数据
private int resId;//int型数据,如图片
public Infos(){}
public Infos(String name, int resId){
super();
//最好在构造方法中传入数据,避免忘记
this.name=name;
this.resId=resId;
}
//获取字符型数据
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//获取int型数据
public int getResId() {
return resId;
}
public void setResId(int resId) {
this.resId = resId;
}
}
6.编写主界面交互代码
MainActivity.java
package com.example.listview_frame;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.ListView;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//初始化ListView控件
ListView mListView = (ListView) findViewById(R.id.lv);
//创建一个Adapter的实例
MyAdapter mAdapter = new MyAdapter(this);
//将需要适配的数据和图片,存储在List<>对象list中
List<Infos> list=new ArrayList<Infos>();
list.add(new Infos("京东商城",R.drawable.jd));//名字对应着图片
list.add(new Infos("QQ",R.drawable.qq));
list.add(new Infos("QQ斗地主",R.drawable.dz));
list.add(new Infos("新浪微博",R.drawable.xl));
list.add(new Infos("天猫",R.drawable.tm));
list.add(new Infos("UC浏览器",R.drawable.uc));
list.add(new Infos("微信",R.drawable.wx));
//设置适配的数据
mAdapter.setDataList(list);
//设置Adapter
mListView.setAdapter(mAdapter);
}
}
让我们看下运行效果:
瀑布流效果的实现,增大ListView Item的总数,使用取余的操作。
使用这个框架,使用者只需在自定义的适配类继承DAdapter并实现getView()这个抽象方法。完整实例已给出,赶紧去试试吧!
为什么ListView需要有适配器,下面这篇文章让我们彻底理解它的工作原理!
链接: https://blog.csdn.net/guolin_blog/article/details/44996879.