首页 > 其他分享 >Android家庭记账本开发第五天:ListAdapter适配器的编写

Android家庭记账本开发第五天:ListAdapter适配器的编写

时间:2024-02-20 19:11:58浏览次数:35  
标签:viewHolder 适配器 视图 ListAdapter position Android public convertView

昨天讲了数据库相关的操作现在来看我们当初在MainActivity的Java文件当中的initData方法:

 1 @SuppressLint("Range")
 2     private void initData() {
 3         helper=new DBHelper(MainActivity.this);
 4         list=new ArrayList<>();
 5         SQLiteDatabase db=helper.getReadableDatabase();
 6         Cursor cursor=db.query("account",null,null,null,null,
 7                 null,null);
 8         while (cursor.moveToNext()){
 9             costList clist=new costList();//构造实例
10             clist.set_id(cursor.getInt(cursor.getColumnIndex("_id")));
11             clist.setTitle(cursor.getString(cursor.getColumnIndex("Title")));
12             clist.setDate(cursor.getString(cursor.getColumnIndex("Date")));
13             clist.setMoney(cursor.getString(cursor.getColumnIndex("Money")));
14             list.add(clist);
15         }
16         listView = findViewById(R.id.list_view);
17         //绑定适配器
18         ListAdapter mAdapter = new ListAdapter(this,list);
19         mAdapter.setOnItemClickListener(this);
20         listView.setAdapter(mAdapter);
21         db.close();
22     }

大部分代码现在应该都能看懂了,现在我们来看适配器相关的部分,首先listView是我们在前面声明的一个ListView对象,我们通过findViewById将list_view的布局传给listView,告诉它数据显示的格式,这些我们都是在之前第二天所讲到的,之后就是适配器相关的代码了,这里我们首先需要了解适配器到底是什么,为什么显示数据需要用到适配器。

首先要知道安卓开发有很多种模式,适配器模式只是其中的一种,适配器模式是一种结构型设计模式。它可以把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。适配器模式是为了解决接口不兼容问题的。比如厂商给你的接口和你现有的接口对接不起来、旧的数据和新的数据接对接不起来等。

 而我们目前需要了解的就只有适配器是用来连接列表项与数据库数据的一个桥梁,下面我们看代码:

     ListAdapter mAdapter = new ListAdapter(this,list);
     mAdapter.setOnItemClickListener(this);
     listView.setAdapter(mAdapter);

第一行我们用list对象去实例化了一个ListAdapter对象,然后第二行代码设置了一个列表项的点击时间,最后将适配器绑定到listView当中,其中前两行代码都传入了this参数,这个指的是上下文的环境,通过传入this参数使得适配器和点击监听器能够与当前类进行交互,并在需要时访问当前类的成员变量和方法。

下面我们直接看适配器的代码:

 1 package com.example.myapplication3;
 2 
 3 import android.content.Context;
 4 import android.view.LayoutInflater;
 5 import android.view.View;
 6 import android.view.ViewGroup;
 7 import android.widget.BaseAdapter;
 8 import android.widget.TextView;
 9 
10 import java.util.List;
11 
12 public class ListAdapter extends BaseAdapter {
13     private Context mContext; // 保存上下文引用
14     private List<costList> mList;
15     private LayoutInflater mLayoutInflater;
16     private OnItemClickListener mListener;
17     public interface OnItemClickListener {
18         void onItemClick(int position);
19     }
20     public void setOnItemClickListener(OnItemClickListener listener) {
21         mListener = listener;
22     }
23     public ListAdapter(Context context, List<costList> list) {
24         mContext = context; // 保存上下文引用
25         mList = list;
26         // 通过外部传来的Context初始化LayoutInflater对象
27         mLayoutInflater = LayoutInflater.from(context);
28     }
29 
30     @Override
31     public int getCount() {
32         return mList.size();
33     }
34 
35     @Override
36     public Object getItem(int position) {
37         return mList.get(position);
38     }
39 
40     @Override
41     public long getItemId(int position) {
42         return position;
43     }
44 
45     @Override
46     public View getView(int position, View convertView, ViewGroup parent) {
47         ViewHolder viewHolder;
48         if (convertView == null) {
49             // 如果convertView为空,说明当前没有可重用的视图,需要创建新的视图
50             convertView = mLayoutInflater.inflate(R.layout.list_item, parent, false);
51             viewHolder = new ViewHolder();
52             viewHolder.tvTitle = convertView.findViewById(R.id.tv_title);
53             viewHolder.tvDate = convertView.findViewById(R.id.tv_date);
54             viewHolder.tvMoney = convertView.findViewById(R.id.tv_money);
55             convertView.setTag(viewHolder);
56         } else {
57             // 如果convertView不为空,说明有可重用的视图,直接从tag中获取viewHolder
58             viewHolder = (ViewHolder) convertView.getTag();
59         }
60         costList item = mList.get(position);
61         convertView.setOnClickListener(new View.OnClickListener() {
62             @Override
63             public void onClick(View v) {
64                 if (mListener != null) {
65                     mListener.onItemClick(position);
66                 }
67             }
68         });
69         viewHolder.tvTitle.setText(item.getTitle());
70         viewHolder.tvDate.setText(item.getDate());
71         viewHolder.tvMoney.setText(item.getMoney());
72 
73         return convertView;
74     }
75 
76 
77 
78     // 内部类ViewHolder,用于保存item中的控件实例,避免重复调用findViewById
79     static class ViewHolder {
80         TextView tvTitle;
81         TextView tvDate;
82         TextView tvMoney;
83     }
84 }

首先适配器当中需要有一个构造函数来接收参数并初始化适配器,之后的三个方法是BaseAdapterListAdapter的父类)中的重要方法,用于定义适配器的行为和提供数据。

  1. getCount():该方法返回适配器中包含的数据项的数量。在ListView或GridView等列表视图中,它确定了列表的长度,即列表将显示多少个项目。通常,它返回数据集的大小。

  2. getItem(int position):该方法根据给定的位置返回对应的数据项。在列表视图中,它用于获取特定位置上的数据对象。通常,它返回数据集中指定位置的数据对象。

  3. getItemId(int position):该方法返回给定位置上的项的ID。这个ID在列表中是唯一的,并且用于帮助列表视图管理项目的状态。通常,它返回指定位置的项目ID或者位置本身作为ID。

最重要的是下面的getView方法,我们来详细解释一下这个方法

 1 @Override
 2     public View getView(int position, View convertView, ViewGroup parent) {
 3         ViewHolder viewHolder;
 4         if (convertView == null) {
 5             // 如果convertView为空,说明当前没有可重用的视图,需要创建新的视图
 6             convertView = mLayoutInflater.inflate(R.layout.list_item, parent, false);
 7             viewHolder = new ViewHolder();
 8             viewHolder.tvTitle = convertView.findViewById(R.id.tv_title);
 9             viewHolder.tvDate = convertView.findViewById(R.id.tv_date);
10             viewHolder.tvMoney = convertView.findViewById(R.id.tv_money);
11             convertView.setTag(viewHolder);
12         } else {
13             // 如果convertView不为空,说明有可重用的视图,直接从tag中获取viewHolder
14             viewHolder = (ViewHolder) convertView.getTag();
15         }
16         costList item = mList.get(position);
17         convertView.setOnClickListener(new View.OnClickListener() {
18             @Override
19             public void onClick(View v) {
20                 if (mListener != null) {
21                     mListener.onItemClick(position);
22                 }
23             }
24         });
25         viewHolder.tvTitle.setText(item.getTitle());
26         viewHolder.tvDate.setText(item.getDate());
27         viewHolder.tvMoney.setText(item.getMoney());
28 
29         return convertView;
30     }

getView方法:负责为每个列表项提供视图,通常在此方法中设置列表项的布局和数据。

我们先解释一下之前在构造函数就有的一个未知的类LayoutInflater:LayoutInflater是一个抽象类,继承自Object,位于android.view包下,作用类似于findViewById(),但是不同的是,LayoutInflater找的是xml布局文件并且实例化,而finViewById()是找到具体的widget控件。具体想要进一步了解的这里给出链接:https://blog.csdn.net/JMW1407/article/details/116227026

我们这里只需要知道这个是用来管理布局的即可

我们看一下getView的参数

  • position:当前要显示的列表项的位置。
  • convertView:用于重用的已存在的视图(可能是之前滑出屏幕的),在第一次显示某个位置的时候,该参数为null,需要我们创建一个新的视图。之后滑出屏幕的视图会被传递给这个参数,我们可以直接对其进行重用,避免重复创建视图,提高性能。
  • parent:父视图,即包含列表项的ListView或者其他列表视图。

关于安卓开发当中的视图体系这里就不详细展开了,附上链接:https://zhuanlan.zhihu.com/p/638260835?utm_id=0

通过判断convertView是否为null来确定当前是否有可重用的视图。如果convertView为null,说明当前没有可重用的视图,需要创建新的视图。如果convertView不为null,说明有可重用的视图,直接从convertView的tag中获取之前保存的ViewHolder对象。ViewHolder是一种模式,用于在列表中存储视图的子视图引用,避免重复调用findViewById方法,提高性能。

之后就是对点击相关逻辑的处理,首先通过传入的位置参数从costList列表当中获取到点击的数据项,然后设置一个点击监听器。关于监听器的设置这里需要详细介绍一下,我这里采用的是通过使用接口的方式设立监听器:

首先定义一个监听器的接口

1     public interface OnItemClickListener {
2         void onItemClick(int position);
3     }

然后,在适配器类中添加一个成员变量来保存接口的引用,并添加一个方法用于设置点击监听器:

 1     private OnItemClickListener mListener;
 2 ...
 3     public void setOnItemClickListener(OnItemClickListener listener) {
 4         mListener = listener;
 5     }
 6 ...
 7     convertView.setOnClickListener(new View.OnClickListener() {
 8             @Override
 9             public void onClick(View v) {
10                 if (mListener != null) {
11                     mListener.onItemClick(position);
12                 }
13             }
14         });

getView方法中,当列表项被点击时,调用接口的onItemClick方法,并传递点击的位置。在setOnItemClickListener方法中,用于外部类设置点击监听器。

在MainActivity当中首先要声明接口

public class MainActivity extends AppCompatActivity implements ListAdapter.OnItemClickListener 然后再重写点击事件的逻辑
1   @Override
2     public void onItemClick(int position) {
3         // 处理点击事件的逻辑
4         Log.d("Main", "jump");
5         costList item = list.get(position);
6         Intent intent = new Intent(MainActivity.this, upgrade_cost.class);
7         intent.putExtra("item_id", item.get_id());
8         startActivityForResult(intent, 1);
9     }

这样就可以完成监听器的设置,在点击时后完成携带点击项数据的跳转

有关其他监听器设置的文章我也没有找到比较全面的文章,这里就不给出推荐了,自行寻找。

标签:viewHolder,适配器,视图,ListAdapter,position,Android,public,convertView
From: https://www.cnblogs.com/qmz-znv2/p/18023846

相关文章

  • Android 《ViewPager 实现引导页》
    布局文件activity_launch_simple.xml<?xmlversion="1.0"encoding="utf-8"?><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xm......
  • Android 《ViewPagerStrip》简单应用
    布局文件activity_pager_tab_strip.xml<?xmlversion="1.0"encoding="utf-8"?><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"......
  • Android命令-lshal
    一、lahal--help翻译/#lshal--helplshal:列出并调试HIDLHAL。(对于AIDLHAL,请参阅“dumpsys”)commands:list列出HIDLHAL。debug调试指定的HIDLHAL。help打印帮助消息。wait如果HIDLHAL尚未启动,请等待其启动。如果未指定命令,则默认为“l......
  • Android 《ViewPager》简单应用
    布局文件<?xmlversion="1.0"encoding="utf-8"?><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://sche......
  • Kotlin学习, 新手向,变量总汇,基于《第一行代码Android(第三版)》
    作者做的思维导图变量val和var区别valvalue不可变变量varvariable可变变量变量的自动类型推导(弱)vala=10;print("a="+a);变量的显式声明(强)vala:Int=10;数据类型注意和java不同,这些都是对象数据类型,大写开头:IntShortLongFloatDoubleB......
  • 第一行代码 Android(第3版)PDF下载
    《第一行代码Android第3版》被Android开发者誉为“Android学习第一书”。全书系统全面、循序渐进地介绍了Android软件开发的必备知识、经验和技巧。《第一行代码Android第3版》基于Android10.0对第2版进行了全面更新,不仅将所有知识点都在Android10.0系统上进行了重新适配,同......
  • Android家庭记账本开发第四天:SQLite数据库操作
    SQlite数据库是一个轻量级的数据库,被用在嵌入式设备上,2019年6月还在流行的两大移动终端操作系统,Android和ios都支持这款数据库。AndroidSDK中有一个包android.database.sqlite,其中专门对SQLite数据库进行了封装,并提供了一套供android使用的API。SQLiteOpenHelper 类包含一组用......
  • 踩坑小计-Android Flutter应用设置沉浸式状态栏
    之前写过一篇关于设置Flutter页面沉浸式状态栏的文章。https://www.cnblogs.com/mrhan9941/p/16482604.html主要是基于Flutterboost的原生Android项目的,那时候是在原生Android项目嵌入了FlutterModule。项目重构后已经改为纯Flutter项目,确发现一个小问题,沿用之前的设置沉浸式状......
  • Android家庭记账本开发第三天:MainActivity主界面逻辑文件
    昨天讲了主界面的xml文件的布局,这里讲一下对应的主界面的Java文件,首先上代码:1packagecom.example.myapplication3;23importandroid.annotation.SuppressLint;4importandroid.content.Intent;5importandroid.database.Cursor;6importandroid.databas......
  • Android家庭记账本开发第二天:activity_main布局文件
    本次开发记录是在开发完成之后记录的,所以能写几篇我也不知道,可能没有十篇,将这次的开发记录作为一次知识点复习的机会。开发完成之后的目录如下安卓开发相较于之前进行的Javaweb开发难度要高上不少,因为之前的都是通过tomcat服务器去运行,我们只需要将对应的页面完善好就行,但是安......