Android基础之ListView | Adapter | MVC | 带源码

Android基础之ListView | Adapter | MVC | 带源码,第1张

Android基础之ListView | Adapter | MVC | 带源码 ListView
  • 在讲ListView的使用之前,需要了解Adapter适配器,也顺便讲一下MVC的原理以及Adapter在其中的作用
MVC
  • 图解

View:用户 *** 作接口,GUI,可以想象成用户看到的界面

Model:事务逻辑层,负责执行程序的核心运算和逻辑判断,通过view来获取用户输入的数据,然后根据数据库查询相关 *** 作,将结果返回给view展示

Controller:控制器,view与model之间的枢纽,通过控制程序的执行流程来进行view和model的交互

Adapter
  • 在android中就是充当controller的作用
  • 连接view和model的桥梁
  • 图解

  • 表格说明

baseAdapter:抽象类,实际开发中我们一般继承该类并重写相关的方法

ArrayAdapter:支持泛型 *** 作,只能展示一行文字

SimpleAdapter:具有良好扩展性的简单Adapter,可以自定义多种效果

SimpleCursorAdapter:一般在数据库会用到,用来显示简单文本类型的listView(textview或imageView等)

简单的ListView实现
private String[] data = {"Apple","Banana","Orange","Watermelon","Pear",
            "Grape","Pineapple","Strawberry","Cherry","Mango","Apple","Banana",
            "Orange","Watermelon","Pear", "Grape","Pineapple","Strawberry","Cherry","Mango"};

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    ArrayAdapter adapter = new ArrayAdapter(this,android.R.layout.simple_list_item_1,data);
    ListView listView = findViewById(R.id.list_view);
    listView.setAdapter(adapter);
}

ArrayAdapter有多个构造函数的重载,需要三个参数(当前上下文/ListView子项布局的id/要适配的数据)

android.R.layout.simple_list_item_1是一个Android内置的布局文件,里面只有一个TextView,可用于简单的显示一段文本

就相当于ListView每一行就是一个TextView

实例(定制ListView界面)
  • 定义一个实体类,作为ListView适配器的适配类型
public class Fruit {

    private String name;
    private int imageId;

    public Fruit(String name, int imageId) {
        this.name = name;
        this.imageId = imageId;
    }

    public String getName() {
        return name;
    }

    public int getImageId() {
        return imageId;
    }
}
  • 为ListView的子项定义一个布局fruit_item.xml


  • 创建一个适配器FruitAdapter,继承自ArrayAdapter

重写了父类的一组构造函数,用于将上下文、ListView的子项布局id和数据都传递进来

重写了getView()方法,每个子项被滚动到屏幕内的时候会被调用

在此方法中,首先通过getItem()方法得到当前项的Fruit实例,然后使用LayoutInflater来为子项加载我们传入的布局

LayoutInflater的inflate()有三个参数,分别是子项布局id,父布局,false(表示只让我们在父布局中声明的layout属性生效,但不会为这个view添加父布局。因为一旦view有了父布局,就不能被添加进ListView中了)

public class FruitAdapter extends ArrayAdapter {

    private int resourceId;

    public FruitAdapter(@NonNull Context context, int resourceId, @NonNull List objects) {
        super(context, resourceId, objects);
        this.resourceId = resourceId;
    }

    @NonNull
    @Override
    public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {

        //获取当前项的fruit实例
        Fruit fruit = getItem(position);
        View view = LayoutInflater.from(getContext()).inflate(resourceId,parent,false);
        ImageView imageView = view.findViewById(R.id.image_fruit);
        TextView textView = view.findViewById(R.id.text_fruit_name);

        imageView.setImageResource(fruit.getImageId());
        textView.setText(fruit.getName());

        return view;

    }
}
  • 修改MainActivity

initFruits()用于初始化所有的水果数据

在onCreate()里创建FruitAdapter对象,并将FruitAdapter作为适配器传递给listView

private List fruitList = new ArrayList<>();

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    initFruits();
    FruitAdapter adapter = new FruitAdapter(this,R.layout.fruit_item,fruitList);

    ListView listView = findViewById(R.id.list_view);
    listView.setAdapter(adapter);

}

private void initFruits(){

    for (int i = 0; i < 2; i++){

        Fruit apple = new Fruit("Apple",R.drawable.apple);
        fruitList.add(apple);

        Fruit banana = new Fruit("Banana",R.drawable.banana);
        fruitList.add(banana);

        Fruit orange = new Fruit("Orange",R.drawable.orange);
        fruitList.add(orange);

        Fruit watermelon = new Fruit("Watermelon",R.drawable.watermelon);
        fruitList.add(watermelon);

        Fruit pear = new Fruit("Pear",R.drawable.pear);
        fruitList.add(pear);

        Fruit grape = new Fruit("Grape",R.drawable.grape);
        fruitList.add(grape);

        Fruit pineapple = new Fruit("Pineapple",R.drawable.pineapple);
        fruitList.add(pineapple);

        Fruit strawberry = new Fruit("Strawberry",R.drawable.strawberry);
        fruitList.add(strawberry);

        Fruit cherry = new Fruit("Cherry",R.drawable.cherry);
        fruitList.add(cherry);

        Fruit mango = new Fruit("Mango",R.drawable.mango);
        fruitList.add(mango);

    }

}
  • 提升ListView运行效率

在FruitAdapter里,getView()方法每次都将布局重新加载,当List View快速滚动时,会成为性能的瓶颈

convertView参数用于将之前加载好的布局进行缓存,以便之后可以进行重用

public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {

    //获取当前项的fruit实例
    Fruit fruit = getItem(position);

    View view;
    if(convertView == null){
        view = LayoutInflater.from(getContext()).inflate(resourceId,parent,false);
    }else {
        view = convertView;
    }

    ImageView imageView = view.findViewById(R.id.image_fruit);
    TextView textView = view.findViewById(R.id.text_fruit_name);

    imageView.setImageResource(fruit.getImageId());
    textView.setText(fruit.getName());

    return view;

}
  • 继续更好的优化

前一个虽然不会重复去加载布局,但是每次还是会重复调用View的findViewById()方法来获取一次控件的实例

我们可以借助ViewHolder(内部类)来对此进行优化

ViewHolder用于对控件的实例进行缓存

view的setTag方法,将viewHolder对象存储在view中

@NonNull
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {

    //获取当前项的fruit实例
    Fruit fruit = getItem(position);

    View view;
    ViewHolder viewHolder;
    if(convertView == null){
        view = LayoutInflater.from(getContext()).inflate(resourceId,parent,false);
        viewHolder = new ViewHolder();

        viewHolder.imageView = view.findViewById(R.id.image_fruit);
        viewHolder.textView = view.findViewById(R.id.text_fruit_name);

        //将viewHolder储存在View中
        view.setTag(viewHolder);
    }else {
        view = convertView;

        //重新获取viewHolder
        viewHolder = (ViewHolder) view.getTag();
    }

    viewHolder.imageView.setImageResource(fruit.getImageId());
    viewHolder.textView.setText(fruit.getName());

    return view;

}

class ViewHolder{

    ImageView imageView;
    TextView textView;

}
  • 点击事件

使用setOnItemClickListener给listView注册了一个监听器,当用户点击任何一个子项时,都会回调onItemClick()方法,可以通过position参数判断用户点击的哪一个子项

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    initFruits();
    FruitAdapter adapter = new FruitAdapter(this,R.layout.fruit_item,fruitList);

    ListView listView = findViewById(R.id.list_view);
    listView.setAdapter(adapter);

    listView.setonItemClickListener(new AdapterView.onItemClickListener() {
        @Override
        public void onItemClick(AdapterView adapterView, View view, int position, long id) {
            Fruit fruit = fruitList.get(position);
            Toast.makeText(MainActivity.this,fruit.getName(),Toast.LENGTH_SHORT).show();
        }
    });

}
  • 源码地址

DoSomeAndroidTest/ListViewTest at main · qricis/DoSomeAndroidTest · GitHub

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5686016.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存