Android入门之旅

注:这是一个学习笔记。很可惜今年的 Google Study Jams 活动取消了,于是就只能自己来了,幸好 Google 官方有很多面向新手的教程,那么,开干!本文基于https://developers.google.cn/training/android/ 给出的教程(而且是中文教程,感觉很良心)

2018©Fu_Qingchen,Typora

本文的运行环境是:

1
2
3
4
5
Android Studio 3.1
Build #AI-173.4670197, built on March 22, 2018
JRE: 1.8.0_152-release-1024-b02 amd64
JVM: OpenJDK 64-Bit Server VM by JetBrains s.r.o
Windows 10 10.0

总体规划

参照 Google Study Jams 的活动进行

第一阶段

  • L1 (3:38:59):1A (1:04:07) 、1B (1:13:59)、1C (1:20:53)
  • L2 (5:07:02):2A (2:00:40)、2B (1:03:40)、2C (2:02:42)
  • L3 (4:25:20):3A (2:15:36)、3B (2:09:44)
  • 拓展 (2:06:44):Firebase 介绍(0:34:25) + Firebase 周末(1:32:19)

第二阶段

  • 实践教程:制作结业 App、上载结业 App 到 Google Play

总时长 15:18:05,建议 40 - 45 小时的空闲时间学习 ,比如工作日每天一个小时,周末每天两个小时。

用户界面

1C为AndroidStudio的运用,暂不介绍

View

简单来说一个展示内容的长方形,有很多,像什么TestView,ImageView,Button等等

XML

描述Android外观的语言

注:下面的代码块中,注释的写法是错误的,但是为了方便,还是这么写了

例如

1
2
3
4
5
6
7
8
<TextView //类型
android:text="Happy Birthday!"
//属性名="值" 的形式
android:background="@android:color/darker_gray"//属性值放在引号内部
android:layout_width="150dp"
android:layout_height="75dp"</TextView>
//当然也可以如果需要嵌套,必须使用
//</TextView>来结束

TextView

1
2
3
4
5
6
7
8
9
10
11
12
13
<TextView
android:text="Happy Birthday!"
android:background="@android:color/darker_gray"
android:background="#2196F3"//替换自己的颜色
android:layout_width="150dp"
dp代表密度无关像素,其中可以接触的东东需要至少48dp
//用dp的原因是不同的设备点像素点的大小是不同的,dp可以使不同的设备显示相同的尺寸
//android:layout_height="75dp"
android:layout_height="warp_content"
//让TextView的高度正好等于文字的高度
//android:textSize="45sp"//大小可以按照MD的说明来弄,其中sp是比例无关像素
android:textAppearance="?android:textAppearanceLarge"
//用系统的文字大小进行匹配/>

相关链接:TextView官方文档

ImageView

1
2
3
4
5
6
7
8
9
10
<ImageView
android:src="@drawable/cake"
//使用@符号表示在Android APP里面引用一个资源
//drawable是一种资源类型,能将图形显示在屏幕上
//cake是图片名,不需要添加文件的扩展名
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="center"
//不改变图片大小,然后居中显示
//android:scaleType="centerCrop"//放大缩小以满足 View 的宽高要求/>

相关链接:ImageView官方文档

ViewGroup

ViewGroup是一个组,相当于是一个容器,他能管理底下的TextView,ImageView,Button等等

LinearLayout

线性布局,分为水平和竖直两种。一般竖直的比较常用

在下面的例子中会介绍线性布局的一些基础内容,还有布局权重

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
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
//线性布局的方向为"竖直"
android:layout_width="match_parent"
//这是一种新的标尺寸的东东,与之前的"wrap_content"类似。
//"match_parent"的含义是:这个尺寸与父级的尺寸相同
//此处LinearLayout宽就与设备宽度相同,下同
android:layout_height="match_parent">
<注意这里有一个">"/>

<ImageView
android:src="@drawable/ocean"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="5"
android:scaleType="centerCrop" />
<
这里出现了layout_weight="1"此处的weight就是权重。
在这个例子中,ImageView占比5/6,TextView占比1/6
当有权重weight出现时通常把对应的值设置为0(竖直:height)
/>
<TextView
android:text="You're invited!"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:textColor="@android:color/white"
android:textSize="54sp"
android:layout_weight="1"
android:background="#009688" />

</LinearLayout>

RelativeLayout

相对布局

顾名思义嘛,同样的,在例子中解释

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
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<
相对布局就不需要android:orientation这个方向属性了
/>

<ImageView
android:id="@+id/ocean_image_view"
//相对的嘛,就需要参照物了,参照物需要一个名字,就是id
//由于这里是添加属性,因此是"@+id"
//一般习惯性的给每个View都给一个id
android:layout_width="56dp"
android:layout_height="56dp"
android:scaleType="centerCrop"
android:src="@drawable/ocean" />

<TextView
android:id="@+id/Pebble_Beach_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Pebble Beach"
android:layout_toRightOf="@id/ocean_image_view"
android:textAppearance="?android:textAppearanceMedium" />
<
其中layout_toRightOf属性就是表示相对位置的,含义是在参照物的右边
同理,还有layout_below,layout_above,toLeftOf,见下方
/>

<TextView
android:id="@+id/California_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="California"
android:layout_toRightOf="@id/ocean_image_view"
android:layout_below="@id/Pebble_Beach_text_view"
android:textAppearance="?android:textAppearanceSmall" />

<
除了把其他View当作参照物,还可以直接把父视图当作参照物,用以下的语句表示:
android:layout_alignParentTop="true"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_centerHorizontal="true"//水平居中
android:layout_centerVertical="true"//竖直居中
/>
</RelativeLayout>

注意:为了避免过于复杂,能够使用线性视图就使用线性视图

内边距与外边距

内边距(padding)呢就是View本身往外边扩展一层,如果View有背景颜色的话,背景颜色也会扩充

外边距(margin)就是把View隔开一下,隔开的地方是没有颜色的。外边距讲究一种隔开的情况,因此需要建立在ViewGroup里面

下面的图形就是内边距和外边距的例子(PS:Google的教程截图)

内边距和外边距

其中蓝色部分代表TextView,红色部分代表ViewGroup,左边是内边距,右边是外边距

其实感觉外边距的运用广泛一些,可能跟最近卡片风格流行有关吧

控制内边距(padding)的语句有

1
2
3
4
5
android:padding="8dp"	//对于全局
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:paddingTop="8dp"
android:paddingBottom="8dp"

控制外边距的语句有

1
2
3
4
5
android:layout_margin="8dp"	//对于全局
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"

当然,这个是可以对各个View分别设置的,也可以对ViewGroup设置

ConstraintLayout

约束布局,能够非常快速地制作自适应 UI的一种布局。

※ 构建布局的步骤

  1. 选择视图类型

    3 Button, 4 TextView

  2. 确定视图的位置

    标题下面是一行按钮和一个TextView,然后是另一个标题和TextView,最后面是一个Button

  3. 设置视图的样式

    内边距外边距什么的

用户交互

什么是Activity?

Activity是应用中用户可以操作的东西,有时候Activity就是应用中的一个屏幕。

比如在Google日历中,你点开时看到的就是一个Activity,让你查看日程的,而且这个Activity有一个侧边栏。Google日历的设置是另外一个Activity,让你设置一些东西的。

XML与Java在Android中有什么作用?

XML其实就是一个控制布局的,你可以在里边编辑你的UI

Java呢,就是控制程序的,实现各种各样的功能

XML如何调用Java?

在XML中,我们可以看到这样的语句:

1
2
3
4
5
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="submitOrders"
android:text="order" />

其中android:onClick="submitOrders" 就是用来调用Java中的submitOrders 方法的

如果submitOrders 方法是这样的,那么当用户点击ORDER 按钮时,就会执行相对应的display方法和displayPrice方法

1
2
3
4
5
6
7
public void submitOrders(View view) {
//将submitOrders变为submitOrder会在应用运行时报错
int numberOfCoffee = 2;
int price = 3;
display(numberOfCoffee);
displayPrice(numberOfCoffee * price);
}

Debug

debug是消除bug的调试过程

系统日志

System Log: Android开发中常用logcat这个工具来分层次、分类型地显示不同等级的日志,方便程序员查找感兴趣的信息(错误信息或者更琐碎、更底层的信息)。

断点功能

为了快速找到错误指令,我们可以在希望设备暂停的指令位置插入一个断点,类似停车标志或路障。然后我们可以让调试器从第一条指令开始全速运行应用,运行至断点时,设备一定会暂停供我们进行检查。

使用方法

进行Debugging必须首先进入debug模式,Android的debug是用一只小瓢虫代替。

进入Debug模式之后,程序会和运行时一样重新编译这个App,此时手机会弹出提示,过一会等弄好了,提示也就自己消失了。

当在手机上操作时,在Android Studio的程序框里面就会显示信息,程序运行到断点就会停止,你可以看到一些数据的值

https://blog.csdn.net/Yaoobs/article/details/51296198 这里非常详细的介绍了Debug模式的使用方法

Nested ViewGroups

嵌套视图组,简单的说就是可以在一个布局里面嵌套多个布局。比如说在竖直的线性布局里面嵌套水平布局。

比如说下面这个图例:

  • 图例首先是包含两个子视图一个竖直的线性布局(vertical LinearLayout)
  • 第一个子视图是一个包含3个子视图的水平线性布局(horizontal LinearLayout)
  • 第二个子视图是一个包含4个子视图的相对布局(RelativeLayout)
    • 其中一个子视图还包含着一个子视图

嵌套

Java字符串

1
2
String message = "Item count" + quantity + 3;	
//字符串还可以这么写,其中quantity是字符变量

其他的都是Java基础了,这里就不写了

控制对齐的属性

主要有两个:layout_gravity 以及 gravity

关于两者的区别:

  • layout_gravity是对整个view的布局。view整体发生变化,但是view里面的内容改咋样还是咋样
  • gravity是对view内的布局。view本身不变,变的是里面的东西

下图是一个很好的例子(来源:stackoverflow

Java常量

在编程语言中,常量是指在整个程序中永远不会改变的值。在 Java 中,你可以使用关键字 final 来强制规定某个值不得被更改。例如:

1
final int POINTS_FOR_FREE_THROW = 1;

Then if you wrote the following, you’d get an error:

1
POINTS_FOR_FREE_THROW = 100;

注意,按照惯例,常量的名称全为大写形式。此外,单词之间用下划线连接,而不用空格或用骆驼拼写法。你可以将变量声明为常量,防止自己意外地更改了变量的值。

Android的构成

一个Android应用主要由资源文件和java代码构成。

  • java代码负责处理一些事情,比如说按按钮之后还会干啥。。。
  • 资源文件就是资源是代码使用的附加文件和静态内容,例如位图,布局定义,用户界面字符串,动画说明等。像一些什么布局文件(XML)啊,图片啊,音乐啊等等

相关资源在 这里

Java获取资源

在运用编译时,Android中有一个叫 aapt 的工具,这个工具会产生 R 类(就是一个简单的R.java文件)这个里面S目录里包含所有资源文件的ID

有两种方式使用ID:

  • 在Java代码中用 R.资源类型.资源名 的形式调用。

    比如 R.string.helloR.drawable.photo

  • 在XML文件中,用 @资源类型/资源名 的形式调用

    比如@string/hello@drawable/photo

XML&JAVA

当你点击APP的时候,它会打开MainActivity,此时什么都看不到,因为它在初始化。然后java中的onCreate方法会被自动调用,activity会被创建。

MainActivity中的 onCreate方法中有一句setContentView(R.layout.activity_main);,这个对应着布局文件的资源ID。此时XML文件与Java文件就结合起来了 。Android程序就开始解析XML文件,识别XML文件中的各种布局还有View等等。

findViewById方法

这个方法会在XML文件中找到与传入ID相对应的View,然后在onCreate方法中处理它

例如下面这个:

1
View textView = findViewById(R.id.order_summary_text_view);

这个语句的意思就是:我们传入一个id参数 R.id.order_summary_text_viewfindViewById 方法。这个方法会遍历整个XML文件,直到找到id为 R.id.order_summary_text_view 的一个View,然后把这个View作为一个Java对象返回,然后把这个对象存放在名字为textView 的View类对象中。

注:如果ID为为 R.id.order_summary_text_view 的View是TextView的话,它是无法使用TextView类的方法的,因为findViewById创建的是一个View类型的对象,如果要用TextView的特殊方法,就必须要使用以下的语句

1
TextView textView = (TextView) findViewById(R.id.order_summary_text_view);

向 Android 日志中写消息

注:这个是抄的Udacity上面的

本质上,你是在代码中写出类似于以下内容的 Java 语句:

1
Log.i("eatCookie","Oh my God, You Killed Kenny!!!");

第一个参数是日志语句所来自的类的名称。第二个参数是你想要显示的文字

这里,我们使用了 Log.i(),表示“信息”级别的日志。其他级别的选项如下所示:

它们对应的是不同的日志级别,当你运行应用时可以在下图所示位置进行设置:

当你设置日志级别时,它将显示该日志级别及更高级别的所有日志消息,所以“详情 (verbose)”日志级别显示的消息最多,而“错误”日志级别仅显示最严重的日志。

本地化

在Android中,你可以把所有的字符内容都储存在一个文件里面,每一个字符都有一个唯一的ID。这样的话,当你创建一个想要翻译这个APP是,就只需要改变这个文件里面的东西了,而不用跑到每个文件里更改。这个文件就是 res/values/strings.xml 文件。

看上去是下面这个样子的

1
2
3
4
5
6
7
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="name"> 姓名</string>
<string name="toppings">配料</string>
<string name="order">预定</string>
...
</resources>

其中第一个" " 里的就是id,后面的那个就是翻译的内容。

注:除了编写 string.xml 文件外,还可以使用 Android Studio 自身的 Translations Editor ,用起来很舒服。界面简单易懂,这里就不做介绍了。

调用这个文件的方式还是使用id进行调用,具体实现方式如下

  • Java: getString(R.string.name) ,得到字符串
  • XML: @string/name

Style & Theme

emmmmmm不想写了,有生之年再来填坑吧

到时候看官方文档得了

让你的应用连接到别的应用?

这里是运用 Intent 知识。Intent 是要求其他应用组件完成的一个信息,让我们的应用调用其他的应用,比如说连接到邮箱啊,相机啊日历啊等等。当然必须要确保有应用可以实现这个功能,要不然程序就会崩溃。

一般的 Intent 的里面有动作、数据URI、目录还有一些其他的消息等等

这里 有一个比较基础的介绍。

例如,你想链接到邮件,就可以在 Java 文件中写入下面类似的语句

1
2
3
4
5
6
7
8
9
10
public void composeEmail(String[] addresses, String subject) {
Intent intent = new Intent(Intent.ACTION_SENDTO);
intent.setData(Uri.parse("mailto:")); // only email apps should handle this
intent.putExtra(Intent.EXTRA_EMAIL, addresses);
//收件人地址,不过好像没效果
intent.putExtra(Intent.EXTRA_SUBJECT, subject);//主题
if (intent.resolveActivity(getPackageManager()) != null) {
startActivity(intent);}
//这个是为了防止没有应用可以外链而避免程序的崩溃
}

多屏应用

Android资源文件

这里只说 res 文件夹里的东西。这个里面的一般都是控制程序外观的文件,包括一些XML文件、图片、还有其他媒体文件

  • layout文件夹:这个里面存放着的就是一些 activity 的XML文件,定义了应用的布局
  • mipmap文件夹:放应用图标的文件夹
  • value 文件夹
    • color.xml:定义了应用的颜色,反正是各种颜色
    • dimensions.xml:包括不同的维度,高度,宽度等等,这一系列的
    • strings.xml:放置字符的,让我们很容易的将应用翻译成其他语言,以及更改文字等等
    • style.xml:包含主题和样式

AndroidManifest.xml

每个文件都必须有的一个文件。这个里面存放着应用的一些重要信息,比如java的包名、应用组件、Intent权限等等,以及所有的activity。

在这个里面,有一个 intent-filter 代码。具体长这样:

1
2
3
4
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>

这个Intent是一种代码,用来要求其他应用执行操作;这个Intent-filter就厉害些,它相当于表明程序的入口。当点击应用图标时,Android将会发送一个Intent来启动我们的应用

当然在这里还可以更改每一个 Activity 的 lable 名称

1
android:label="@string/category_about"

使用Intent打开其他Activity

要使用Intent必须首先要创建一个Intent对象。然后传入两个值,一个 context 和一个 class 组件

1
Intent intentName = new Intent(this, ActivityName.class)

其中 this 表示当前 Activity 的 context

然后呢,打开这个Activity

1
startActivity(intentName);

这样的话安卓就会启动我们的Activity,应用也就相对应的切换到 ActivityName 这个里面了。

当然这个与上文 让你的应用连接到别的应用 的Intent是有所不同的。因此Intent可以被分为两类:显式的 intent隐式的 intent

显式的 intent 是指知道执行那个操作的是谁,是十分具体的指向。就是 本块 中的示例

隐式的 intent 是指你不知道执行那个操作的是谁,只要是可以执行的都可以执行操作。到最后是谁执行还不清楚。 让你的应用连接到别的应用 中的就是隐式的 intent

事件监视器Listener

之前点击应用,完成一系列的操作,我们是在 XML 文件中进行的

1
android:onclick = "methodInJava"

下面介绍的这个可以不用 XML 文件执行(其实也就是探究 onclick 的本质)

首先了解一下 过程,在用户点击按钮时(用户输入事件),物理设备会检测到一些数据,然后通知Android发生了这个事件,安卓就会通过点击的位置信息定位到相对应的View上。事件监视器 就是来获取这些信息的,如果有特定的信息传入[比如点击],你知道这个事件发生了,就可以执行一些交互了,如 methodInJava 方法。

注:事件监视器在Java中其实是一个接口类。接口类中,方法全为抽象方法,也没有数据成员。

了解了过程,接下来就是要使用了,使用事件监视器可以按照以下3步走:

  1. 建立一个事件监视器类

    Name.java文件:

    1
    2
    3
    4
    5
    6
    public class ClickTest implements View.OnClickListener {
    @Override
    public void onClick(View view) {
    //做你想做的事情
    }
    }
  2. 创建事件监视器的实例

    1
    ClickTest cickTest = new  ClickTest();
  3. 连接你的事件监视器和对应的 View

    1
    2
    3
    4
    TextView about = (TextView) findViewById(R.id.about);	
    //首先要构造一个TextView的实例才能对它进行操作嘛
    about.setOnClickListener(cickTest)
    //连接你的事件监视器和对应的 View

这样的话,事件监视器就被使用了。当然,为了代码的可读性,还可以进行简化,该文件为 MainActivity.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 将活动的内容设置为使用activity_main.xml布局文件,一般系统会自动生成
// 也就是说下面的内容定义在了 activity_main.xml 中
// 如果注释掉就会使 setOnClickListener 报错:NullPointerException
setContentView(R.layout.activity_main);

//创造出一个about的TextView实例出来,这样就可以对它进行操作了
TextView about = (TextView) findViewById(R.id.about);

//用户点击about这个文字的时候做出一些操作的方法
//使用事件监视器(Listener)需要调用set...Listener方法
//set...Listener方法需要传入一个...Listener对象
//此处本来应该构造一个有OnClickListener接口的aboutOnClickListener类的对象,然后将他示例化,但是本例中把这个简化了
about.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
//下面,创建一个Intent类对象,并直接把这个当做参数传递给startActivity方法
//用来打开AboutActivity
startActivity(new Intent(MainActivity.this, AboutActivity.class));
}
}//直接创建一个OnClickListener的类,然后实例化当做setOnClickListener的参数
);
//以后可以看谁不爽直接 new 一个类出来

ArrayList[数组列表]

其实跟数组差不多。与数组的区别有以下几个方面:

  1. 数组列表的长度是可以改变的,数组列表中有多少元素其长度就是多少
  2. 数组列表是一种类型,数组的话,就比较基本
  3. 既然是一种类型,就可以调用各种各样的方法,你还可以继承它,覆盖一些方法等等(可玩性更高吧)
  4. 数组列表只能包含对象数据类型,向 int 这种就只能使用它们的包装类了

注:一般来说固定长度的使用数组,不固定长度的使用数组列表

ArrayList 的文档在:这里

在 Java 中,ArrayList 继承自AbstractList,实现implements List接口,是一个泛型类

1
2
注:泛型类有主要以下类型参数:
E:元素 K:键 N:数字 T:类型 V:值

下面列举一些常见的ArrayList使用方法

用途 Java
创建数组列表 ArrayList<Word> familyList = new ArrayList<Word>();
增加元素 familyList.add(new Word(getString(R.string.phrase_Where), "minto wuksus"));
去除元素 familyList.remove(new Word(getString(R.string.phrase_Where), "minto wuksus"));
查看元素 familyList.get(0);familyList.get(1);familyList.get(2);
查看元素数量 familyList.size();

内存优化——ListView+ArrayAdapter

我们之前要创建一串列表时,肯定是这样的

1
2
3
4
5
6
7
LinearLayout number_LinearLayout = (LinearLayout) findViewById(R.id.numbers_LinearLayout);//先建立一个LinearLayout
TextView[] textViews = new TextView[restaurantsToTry.size()];
for (int i = 0; i < restaurantsToTry.size(); i++) {
textViews[i] = new TextView(this);
textViews[i].setText(restaurantsToTry.get(i));
number_LinearLayout.addView(textViews[i]);
}//然后填上TextView

但是随着数据的增大,一次显示的东西也曰来越多,所占用的内存也会越来越大,从而导致卡顿。这个是我们很不愿意看到了。为了解决这个问题,有以下的思路:

我们不一次显示所有的啊东西,只是显示屏幕上需要的东西。就是根据屏幕,创建所需要的视图。如果屏幕不需要,我们就不显示,把它抛弃了;如果需要就建立一个。这样成了一个可循环的了,屏幕上不需要的循环到屏幕上需要的。

做到这一步需要 一个可循环的ViewGroup + 一个配适器(ArrayAdapter) 。可循环的ViewGroup有:ListView、GridView、RecylcerView 等等

下面来以ListView为例说原理:

ArrayAdapter会处理数据,将他们调用或传输到ListView上,然后在上面显示

ListView可以看成是用户界面,ArrayAdapter是处理数据的。

ListView首先会向ArrayAdapter询问数据的长度。然后ListView会向ArrayAdapter调用一个方法(相当于一个请求),传入一个position,即用户正在查看的列表的位置。得到了请求之后,ArrayAdapter会查看数据结构,然后创造出一个View出来。当屏幕占满的时候,ListView就会停止请求。当屏幕滚动的时候,不在可见的View就会到一个 Scrap Views 的地方,然后ListView请求新的东西,传入 Scrap Views 的position,然后达到循环利用。

原理部分说明完毕。(其实最后还是有些不清楚。。。)

实现这个还是要三步走:

  1. 构造一个ListView对象

    1
    ListView listview = (ListView) findViewById(R.id.list)

    这样才能对ListView进行操作嘛。当然,为了实现这个必须想要建立一个id为R.id.list的ListView在xml文件中,比如这个

    1
    2
    3
    4
    5
    6
    7
    <ListView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/list"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="@dimen/activity_vertical_margin"/>
  2. 构造一个ArrayAdapter对象

    1
    ArrayAdapter arrayAdapter = new WordAdapter(this, arrayListName);

    第一个参数为context,第二个参数为要传入其中的arrayList,数组啊等等

  3. 将ListView对象与ArrayAdapter对象联系起来

    1
    listView.setAdapter(arrayAdapter);

这样的话,一个列表就形成了。不过目前还有一个问题:ArrayList一次只能传入一个参数。ArrayAdapter只能生成一个TextView。如果想要产生一个比较复杂的列表(比如通讯录既有图片又有文字),采用刚刚那样就会报错。

如果需要解决就必须要自定义一些内容,下面介绍自定义的东西:

  • 数据类

    这是由于ArrayList造成的。ArrayList一次只能传入一个参数。如果一个列有两个项目(比如一个单词的翻译放在List就有中文和英文两项),就必须要自己创造一种类型。这种类型包含两个项目。比如说这里就可以创造一个 Word 类型

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    public class Word {
    private String defaultWord;
    private String anotherWord;

    //获取default语言
    public String getDefaultWord() {return defaultWord;}

    //获取另外一种语言
    public String getAnotherWord() {return anotherWord;}

    //构造函数无返回值
    Word(String defaultWord, String anotherWord) {
    this.defaultWord = defaultWord;
    this.anotherWord = anotherWord;
    }
    }
  • 配适器(Adapter)类

    这回是要创建自己的Adapter,让它能够一次生成多个View出来(改写getView方法)

    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
    public class WordAdapter extends ArrayAdapter<Word> {

    //构造函数,不写这个不给用ArrayAdapter
    WordAdapter(Activity context, ArrayList<Word> wordArrayList) {
    //第二个参数设置,在 getView 方法中会得到,因此可以是任何数字
    super(context, 0, wordArrayList);
    }

    //为 AdapterView 提供(构件)View
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
    // Check if the existing view is being reused, otherwise inflate the view
    View listItemView = convertView;
    if (listItemView == null) {
    listItemView = LayoutInflater.from(getContext()).inflate(
    R.layout.list_item, parent, false);
    }

    // 获取 restaurantsToTry[ArrayList类] 在position这个位置上的值
    // 在这个例子中,这个值是一个 Word 类型的
    Word currentAndroidFlavor = getItem(position);

    // 建立一个指定id的 TextView 的实例,并且命名为 nameTextView
    // 注意:findViewById方法在 View中有,在这里没有
    //因此要通过 listItemView.findViewById调用
    TextView nameTextView = (TextView) listItemView.findViewById(R.id.numbers_translate_TextView);
    nameTextView.setText(currentAndroidFlavor.getDefaultWord());

    TextView numberTextView = (TextView) listItemView.findViewById(R.id.numbers_micwok_TextView);
    numberTextView.setText(currentAndroidFlavor.getMiwokWord());

    return listItemView;
    }
    }

这样的话一些自定义也结束了。


Android入门之旅
https://fu-qingchen.github.io/2018/03/31/WHUT/AndroidOpenDoor/
作者
FU Qingchen
发布于
2018年3月31日
许可协议