【Android开发】ListView框架,Adapter进一步优化;(含完整实例详细注释,还有瀑布流实现)

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.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值