Adapter
# 1. MVC类比Adapter
MVC 三件套中,最难理解的就是 Model,所以我们先来剖析它。前面我们说过,Model 层主要管理业务模型的数据和行为,它既保存程序的数据,也定义了处理该数据的逻辑,所以 Model = 数据 + 业务逻辑。因此,处理业务逻辑属于 Model 的职责,而非 Controller。从数据的维度来说,可以细分为数据的定义、数据的存储、数据的获取。数据的定义其实就是定义数据结构,一般用实体类来定义,以方便在不同角色间传递数据。数据的存储和获取则可能有几种途径:数据库、网络或缓存等。因此,在实际应用中,一个 Model 并不只是简单的一个对象,而是一个更广泛的层级。很多时候,会将 Model 层再进行分解,比如应用于客户端程序时,可以将 Model 层再细分为业务逻辑层、网络层、存储层等,而实体类其实只是贯穿其中的一种数据结构而已。不过,狭义上,当我们说一个 Model 对象的时候,主要是对外部组件而言的,更多是指这个 Model 对外所提供的数据,并不关心数据从何而来。这可能就是让很多人将 Model 误认为就是实体类的原因。
View 是 MVC 里最好理解的,它会接收用户的交互请求并展示数据信息给用户。一个 View 展示的数据可能只是一个 Model 对象的部分数据,也可能是一个 Model 对象的全部数据,甚至可能是多个 Model 对象数据的组合。在 MVC 里,View 被设计为可嵌套的,使用了组合(Composite)模式来实现。比如,列表视图(ListView)或表格视图(TableView)由每个 Item 组成,每个 Item 又可以由图片、文本、按钮等组成。View 是倾向于可复用的,因此,在实际应用中,倾向于将 View 开发成相对通用的组件。
Controller 层主要担任 Model 与 View 之间的桥梁,用于控制程序的流程。Controller 负责确保 View 可以访问到需要显示的 Model 对象数据,并充当 View 了解 Model 更改的渠道。View 接收到用户的交互请求之后,会将请求转发给 Controller,Controller 解析用户的请求之后,就会交给对应的 Model 去处理。因此,理论上,Controller 应该是很轻的。
而这个Adapter则是中间的这个Controller的部分: Model(数据) ---> Controller(以什么方式显示到)---> View(用户界面) 这就是简单MVC组件的简单理解!
# 2. 什么是Adapter
适配器是实现Adapter
接口的类的对象。它充当数据集和适配器视图之间的链接,适配器视图是扩展抽象AdapterView
类的类的对象 。适配器(Adapter)就像数据源Model 和 用户界面之间View的桥梁一样,将数据和视图分开(但是又将其关联起来),把数据匹配或者映射到外观的视图中。适配器从各种数据源读取数据,将其转换为View对象,并将其提供给链接的Adapter视图以创建UI组件。
数据源或数据集可以是Array对象,List对象等。
可以通过扩展
BaseAdapter
该类来创建自己的Adapter类,该类是所有其他适配器类的父类。Android SDK中还提供了一些准备使用的适配器类,如ArrayAdapter
,SimpleAdapter
等。
通常,当我们创建任何数据列表或网格时,我们认为可以使用循环对数据进行迭代,然后设置数据以创建列表或网格。
但是,如果数据是一百万个产品的集合,该怎么办?然后,使用循环不仅会消耗大量时间,使应用程序变慢,还可能最终耗尽所有运行时内存。
通过使用适配器和适配器视图解决了所有这些问题。
Adapter View是一个View
对象,可以像使用其他任何界面小部件一样使用。
这里唯一的陷阱是,它需要Adapter
向其提供内容,因为它无法自行显示数据。
# 3. 什么是适配器视图AdapterView
# 什么是适配器视图
ListView、GridView等AdapterView都是容器,而Adapter提供每个item组件,AdapterView负责采用合适的方式显示列表项
集合多个 “项”(称为:Item
)
AdapterView是一组重要的组件,本身也是一个抽象基类。AdapterView特性如下:
AdapterView继承ViewGrop
AdapterView可以包含多个列表项,将多个列表项以合适的形式显示出来
AdapterView显示的多个
item
由Adapter提供,调用AdapterView的setAdapter(Adapter)
方法设置Adapter即可
Adapter及其子类的继承关系:
# 适配器视图如何工作
适配器视图AdapterView可用于以适配器提供的列表或网格等形式有效地显示大量数据。
当我们有效地说时,我们是什么意思?
适配器视图能够在用户界面上显示数百万个项目,同时保持内存和CPU使用率非常低,并且没有任何明显的滞后。为此,不同的适配器遵循不同的策略,但是Android SDK中提供的默认适配器遵循以下技巧:
- 它仅呈现
View
当前在屏幕上或即将在屏幕上显示的那些对象。因此,无论您的数据集有多大,“适配器视图”将始终一次仅加载5个或6个或也许7个项目,具体取决于显示大小。因此节省了内存。 - 当用户滚动时,它还会重复使用已经创建的布局来填充数据项,从而节省了CPU使用率。
简单来说就是只显示屏幕上出现的数据,并且复用View
假设您有一个数据集,例如具有以下内容的String数组。
String days[] = {"Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"};
现在,适配器的作用是从该数组中获取数据,并根据该数据创建一个视图,然后将该视图提供给AdapterView。然后,AdapterView以所需的方式显示数据。
注意: 适配器仅负责从数据源获取数据并将其转换为View,然后将其传递给AdapterView。因此,它用于管理数据。AdapterView负责显示数据
因此,您可以从数据库或ArrayList
其他任何数据源中获取数据,然后可以按任何排列方式显示该数据。您可以垂直显示(ListView
(opens new window)),行或列(GridView
(opens new window))或下拉菜单(Spinners
(opens new window))等。
有不同类型的AdapterViews。让我们看一下其中的一些:
列表显示
它显示了可垂直滚动的视图集合,其中每个视图都位于列表中上一个视图的紧下方。
网格视图
GridView是一个ViewGroup,它在二维可滚动网格中显示项目。
# 4. 为什么要用Adapter
我们首先看看 Android 为什么要引入 Adapter,也就是使用 Adapter 有哪些好处?
在 Android 中Adapter 通常是搭配列表控件使用,我们先看看在没有学习 Adapter 的时候,如何实现一个列表样式,我们可能需要以下几步:
- 创建一个 ScrollView
- 在 ScrollView 中放置多个 View / ViewGroup,比如 TextView;
- 获取每个 TextView 实例,根据业务需求为 TextView 设置 Text;
- 编写额外代码管理所有的 TextView,并且需要分辨点击事件发生在第几行从而定位到相应的 TextView,从而相应列表的点击事件。
读到这里,脑海里已经有实现思路了吗?即使你能捋清思路,代码也很难写的优雅,因为编写 TextView 样式的这些 UI 代码一定会和 TextView 内容的数据代码耦合在一起,这样如何 UI 样式一变,数据也需要做很大的调整,后期的维护成本是相当高的。最好的办法就是能够有一套逻辑专门去管理数据和 UI 代码的绑定关系,用它来将 UI、Data 隔离开,提高代码的简洁性和可维护性。
我们结合一张图来理解一下 Adapter:
电源适配器将电器和电源接口适配到一起,好处是可以让手机等电子产品及家用电器厂商在生产过程中完全不需要考虑用户电源接口的类型,可以是 220V 交流电、也可以是 USB 接口,适配工作只需要交给相应的 Adapter 就可以完成。
Android 适配器是将数据和 UI 适配到一起,好处同样也是我们在做 UI 的时候,完全不用考虑未来填充的数据是什么样的,只需要针对不同的数据类型提供一个 Adapter 即可。
# 5. Adapter的接口及实现类
# Adapter的类型
就像电源适配器需要根据不同的电源接口类型提供不同的适配器一样,Android 中我们需要根据不同数据类型提供不同的 Adapter,系统已经为我们实现了几种Adapter:
- BaseAdapter: 所有 Adapter 的基类,通常我们需要实现自定义 Adapter 时,需要实现此抽象类,在实际开发中使用的最多的类型。
- ArrayAdapter: 适用于一个单项列表,并且数据可以以数据形式存放的场景。
- SimpleAdapter: 适用于一个列表项中有多个数据的场景,它可以将一个 map 里的数据映射到 xml 布局文件中的各个控件上。
- SimpleCursorAdapter: 针对数据库使用的 Adapter,使用场景很少。
# 6. 常见Adapter的用法
ArrayAdapter
构造方法
ArrayAdapter(Context context, int resource, T[] objects)
ArrayAdapter(Context context, int resource, List<T> objects)
2
3
- context:上下文对象,一般为当前Activity对象
- resource:item布局文件资源id
- objects: 需要显示的数据集合(Array或List)
SimpleAdapter
public SimpleAdapter(Context context, List<? extends Map<String, ?>> data,
@LayoutRes int resource, String[] from, @IdRes int[] to)
2
- context: 上下文件对象,一般为Acivity对象
- data: 需要显示的数据集合
- resource: item布局文件标识
- from: Map对象中的key的数组,用于得到对应的value
- to: item布局文件中的子View的id的数组
**BaseAdapter
视图对象可以复用,但是缓存不能复用
为防止内存溢出OutOfMemory,ListView需要复用缓存Item视图对象
// content如果没有复用
if (convertView == null) {
// 加载item的布局, 得到View对象
// 此处传递this是Adapter的对象
convertView = View.inflate(MainActivity.this, R.layout.item_base_adapter, null);
}
2
3
4
5
6
# ArrayAdapter的用法
执行效果:
1. 主布局activity_main.xml的ViewGroup中添加ListView控件
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"
android:orientation="vertical"
tools:context=".MainActivity">
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="10dp"
android:text="ArrayAdapter"
android:textSize="30sp"
android:textStyle="bold" />
<ListView
android:id="@+id/list_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="10dp"
android:divider="#a4b0be"
android:dividerHeight="2dp" />
</LinearLayout>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
2. 设置ListView控件的item条目的布局,通过 ArrayAdapter进行数据 / UI 的绑定
item_view.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="match_parent"
android:layout_margin="5dp"
android:orientation="vertical">
<TextView
android:id="@+id/item_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginLeft="10dp"
android:padding="10dp"
android:text="test"
android:textSize="20sp" />
</RelativeLayout>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
3. MainActivity中通过ArrayAdapter适配数据,更新UI
MainActivity充当了Model和Controller的角色
public class MainActivity extends AppCompatActivity {
String[] data = {"TextView", "EditText", "Button", "ImageButton", "RadioButton", "ToggleButton",
"ImageView", "ProgressBar", "SeekBar", "RatingBar", "ScrollView", "Adapter", "TextView", "EditText", "Button", "ImageButton", "RadioButton", "ToggleButton",
"ImageView", "ProgressBar", "SeekBar", "RatingBar", "ScrollView", "Adapter"};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ListView mListView = findViewById(R.id.list_view);
ArrayAdapter adapter = new ArrayAdapter<>(this, R.layout.item_view, R.id.item_text, data);
mListView.setAdapter(adapter);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
一些相关的东西:
**1.**除了通过数组外,我们还可以写到一个数组资源文件中:
比如:在res\valuse下创建一个数组资源的xml文件:arrays.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="myarray">
<item>语文</item>
<item>数学</item>
<item>英语</item>
</string-array>
</resources>
2
3
4
5
6
7
8
接着布局的listview属性设置下这个列表项:
<ListView
android:id="@id/list_test"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:entries="@array/myarray"/>
2
3
4
5
当然我们也可以在Java代码中这样写:
ArrayAdapter<String> adapter = new ArrayAdapter<String>
(this,android.R.layout.simple_expandable_list_item_1,data);
2
同样也是可以的!
ArrayAdapter支持泛型
List<String> data = new ArrayList<String>();
data.add("Android");
data.add("Flutter");
ArrayAdapter<String> adapter = new ArrayAdapter<String>
(this,android.R.layout.simple_expandable_list_item_1,data);
2
3
4
5
android.R.layout.simple_expandable_list_item_1 其实这些是系统给我们提供好的一些ListView模板,有下面几种:
simple_list_item_1 : 单独一行的文本框
simple_list_item_2 : 两个文本框组成
simple_list_item_checked : 每项都是由一个已选中的列表项
simple_list_item_multiple_choice : 都带有一个复选框
simple_list_item_single_choice : 都带有一个单选钮
ArrayAdapter较为简单,易用,但每个列表项只能是TextView,功能实现的局限性非常大。
# SimpleAdapter的用法
SimpleAdapter 相比 ArrayAdapter 会更丰富一点,主要体现在 ArrayAdapter 只能适用于列表中只有一项数据(上一小节中的 TextView)的场景,而如果列表项由多个数据组成,比如文字配图片的形式 ArrayAdapter 就有些力不从心,这时候就需要用到 SimpleAdapter 了。
activity_main不用修改
修改item_view.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="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="100dp">
<ImageView
android:id="@+id/item_image"
android:layout_width="90dp"
android:layout_height="90dp"
android:src="@mipmap/ic_launcher" />
<TextView
android:id="@+id/item_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginLeft="10dp"
android:layout_toRightOf="@id/item_image"
android:padding="10dp"
android:text="test"
android:textSize="25sp" />
</LinearLayout>
</RelativeLayout>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
从上面的布局文件可以看出,我们现在的列表项由两个部分组成:一个图片和一个文本
MainActiviy的修改:
public class MainActivity extends AppCompatActivity {
private ListView mListView;
private String[] mDataName = {"image01", "image02", "image03", "image04", "image05", "image06", "image07",
"image08", "image09", "image10", "image11", "image12", "image13", "image14"};
private int[] mDataImage = {R.mipmap.image_1, R.mipmap.image_2, R.mipmap.image_3, R.mipmap.image_4,
R.mipmap.image_5, R.mipmap.image_6, R.mipmap.image_7, R.mipmap.image_8, R.mipmap.image_9,
R.mipmap.image_10, R.mipmap.image_11, R.mipmap.image_12, R.mipmap.image_13, R.mipmap.image_14};
private List<Map<String, String>> list; // 乘方数据源的容器
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mListView = findViewById(R.id.list_view);
// 将水果图片和水果名称整合到一个map当中,最后将所有的水果都存放到ArrayList
list = new ArrayList<>();
Map<String, String> map = null;
for (int i = 0; i < mDataName.length; i++) {
map = new HashMap<>();
map.put("name", mDataName[i]);
map.put("image", mDataImage[i] + "");
list.add(map);
}
String[] from = {"name", "image"};
int[] to = {R.id.item_text, R.id.item_image};
// 初始化Adapter
SimpleAdapter adapter = new SimpleAdapter(this, list, R.layout.item_view, from, to);
mListView.setAdapter(adapter);
// item点击事件
mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
Toast.makeText(getApplicationContext(), mDataName[i], Toast.LENGTH_LONG).show();
}
});
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
- 两个数组
mDataName
和mDataImage
分别乘方text和image; - ListView的每个item上的数据(文字和图片)均放到HashMap中
- 每个item的数据最终放入到List中,通过SimpleAdapter来适配并显示到ListView的ViewGroup上
SimpleAdapter的构造参数
SimpleAdapter adapter = new SimpleAdapter(this, list, R.layout.item_view, from, to);
context
运行与此SimpleAdapter关联的View的上下文data
数据源,也就是存放所有水果 Map 的 ArrayList 对象resourcr
item的布局文件from
列名列表,一个字符串数组,表示水果 map 中的 key,也就是水果名和水果图片的 key,用来与具体的 UI 控件对应该列名将添加到与每个项目关联的Map中;to
用来与第四个参数匹配,告诉系统 map 中的哪些数据需要显示到哪个 View 上。这些都应该是TextViews。此列表中的前N个视图在from参数中获得了前N列的值。
# BaseAdapter Demo
# 注意点
一定要在Adapter中初始化数据源,否则显示到ListView是空
# 思考
- 当ListView有很多Item时,而item显示的数据很复杂,势必会造成App卡顿 [item复用]
- 每个item上使用相同的控件,当当前的item被销毁后,下次又需要重新创建,控件能否存起来复用呢? [ViewHolder-将
findViewById()
反射出来的控件对象进行存储]
# 实例
activity_main布局
<?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"
android:layout_margin="5dp"
android:orientation="vertical"
tools:context=".MainActivity">
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="10dp"
android:text="BaseAdapter"
android:textSize="30sp"
android:textStyle="bold" />
<ListView
android:id="@+id/list_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="10dp"
android:divider="#a4b0be"
android:dividerHeight="2dp" />
</LinearLayout>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
item布局
<?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="match_parent">
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FFFFFF"
app:cardUseCompatPadding="true">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="120dp"
android:layout_margin="5dp">
<ImageView
android:id="@+id/item_image"
android:layout_width="90dp"
android:layout_height="90dp"
android:layout_centerVertical="true"
android:src="@mipmap/ic_launcher" />
<RelativeLayout
android:id="@+id/item_layout"
android:layout_width="match_parent"
android:layout_height="120dp"
android:layout_margin="5dp"
android:layout_toRightOf="@id/item_image"
android:orientation="vertical">
<TextView
android:id="@+id/item_text_app_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:gravity="center_horizontal"
android:padding="10dp"
android:text="test"
android:textSize="20sp" />
<TextView
android:id="@+id/item_text_app_size"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/item_text_app_name"
android:layout_marginLeft="10dp"
android:gravity="center_horizontal"
android:padding="10dp"
android:text="test" />
</RelativeLayout>
<Button
android:id="@+id/item_btn_app"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:text="卸载" />
</RelativeLayout>
</androidx.cardview.widget.CardView>
</RelativeLayout>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
首先先创建实体类AppInfo,toStirng()
方法方便查看日志
public class AppInfo {
private String appName;
private String appSize;
private int appIcon;
public String getAppName() {
return appName;
}
public void setAppName(String appName) {
this.appName = appName;
}
public String getAppSize() {
return appSize;
}
public void setAppSize(String appSize) {
this.appSize = appSize;
}
public int getAppIcon() {
return appIcon;
}
public void setAppIcon(int appIcon) {
this.appIcon = appIcon;
}
@Override
public String toString() {
return "AppInfo{" +
"appName='" + appName + '\'' +
", appSize='" + appSize + '\'' +
", appIcon=" + appIcon +
'}';
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
Adapter继承自BaseAdapter
- 一级优化:item复用
- 二级优化:ViewHolder解决控件复用
public class MyBaseAdapter extends BaseAdapter {
private List<AppInfo> list; // 乘方数据源的容器
// 反射器: 将item的XML布局文件反射成为View
private LayoutInflater inflater;
public MyBaseAdapter(Context context, List<AppInfo> list) {
// 初始化上下文
this.inflater = LayoutInflater.from(context);
this.list = list;
}
@Override
public int getCount() {
return list == null ? 0 : list.size();
}
@Override
public Object getItem(int position) {
return list.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// [二级优化] ViewHolder
ViewHolder holder = null;
// [一级优化] convertView减少inflate的次数
if (convertView == null) {
Log.e("TAG", "getView() *** position = " + position + " convertView = " + convertView);
// 此处传递this是Adapter的对象
// 反射器: 将item的XML布局文件反射成为View
// 1. 拿到view视图对象,从item布局文件反射器获取而来(XML文件映射成为内存中实际存在的View对象)
// 父容器对象不需要传递,因为仅仅是展示
convertView = inflater.inflate(R.layout.item_view, null);
// 2. 获取控件
holder = new ViewHolder();
holder.logo = convertView.findViewById(R.id.item_image);
holder.app_name = convertView.findViewById(R.id.item_text_app_name);
holder.app_size = convertView.findViewById(R.id.item_text_app_size);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
// 每个item加载的内容是不同的,所以需要重复获取(无法优化)
AppInfo info = new AppInfo();
holder.logo.setImageResource(list.get(position).getAppIcon());
holder.app_name.setText(list.get(position).getAppName());
holder.app_size.setText(list.get(position).getAppSize());
// 返回实实在在的view供系统渲染item
return convertView;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
MainActivity
public class MainActivity extends AppCompatActivity {
public final static String TAG = "TAG";
private ListView mListView;
private String[] mDataName = {"Twitter", "Youtube", "Telegram", "Google", "VPN", "Discord", "Steam",
"Zoom", "SSR", "Twitch", "Tinder", "Instagram", "Adobe", "Via"};
// 数据源图片(自行放到mipmap文件夹中即可)
private int[] mDataImage = {R.mipmap.image_1, R.mipmap.image_2, R.mipmap.image_3, R.mipmap.image_4,
R.mipmap.image_5, R.mipmap.image_6, R.mipmap.image_7, R.mipmap.image_8, R.mipmap.image_9,
R.mipmap.image_10, R.mipmap.image_11, R.mipmap.image_12, R.mipmap.image_13, R.mipmap.image_14};
private List<AppInfo> list;
private AppInfo info;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mListView = findViewById(R.id.list_view);
list = new ArrayList<>();
for (int i = 0; i < mDataName.length; i++) {
info = new AppInfo();
info.setAppIcon(mDataImage[i]);
info.setAppName(mDataName[i]);
info.setAppSize("大小: " + randSize(100) + "MB");
list.add(info);
}
Log.i(TAG, "=====>AppInfo<======" + info.toString());
MyBaseAdapter adapter = new MyBaseAdapter(this, list);
mListView.setAdapter(adapter);
// item点击事件
mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
Toast.makeText(getApplicationContext(), mDataName[i], Toast.LENGTH_LONG).show();
}
});
}
public String randSize(int range) {
Random random = new Random();
return String.valueOf(random.nextInt(range) + 1);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
运行结果
【参考文章】
[1]Adapter and Adapter View[EB/OL].https://www.studytonight.com/android/adapter-and-adapter-view.
[2]Carson_Ho.Android:ListView与AdapterView全面解析[EB/OL].https://www.jianshu.com/p/4e8e4fd13cf7.
[3]Android 适配器 Adapter.https://m.imooc.com/wiki/androidlesson-adapter