写在开始之前,从本篇开始我们用具体的小项目例子来进行我们的Android学习之旅。
希望通过这一篇文章对于没有接触过
Android开发的朋友有所帮助,有过知识储备的请跳过,因为这是对你们没有什么作用的。
从本篇文章开始到后面几篇都是基于一个程序员常见面试题的答题程序为例来进行学习。
开发工具我们使用Android Studio,下载地址:https://developer.android.google.cn/studio
目前最新版本为3.5.2,大家可以根据具体的需要进行安装。
创建Android项目
接着选择我们项目模板,一般都会选择‘Empty Activity’:
上面还有选项能够选择设备类型,这里选择手机和平板设备,其他设备我们不做了解。
首先来看下我们的Android 项目创建完成后是什么样子
我们今天要实现的很简单,就是实现一个能够显示题目和选择答案的页面。
在Android中,布局和页面的实现逻辑是分开的,为什么这么做,这里没必要深究。
大家可以从创建好的项目中可以看到,Android Studio已经默认为我们创建好了一个名为MainActivity.java和activity_main.xml的文件。
activity_main.xml就是以后我们经常会提到的布局文件,MainActivity.java是布局文件具体逻辑的实现。
在Android Studio中我们有两种选择进行用户界面设计:
- 通过修改布局文件,也就是上面的activity_main.xml这样的文件。
- 通过图形化设计工具
打开activity_main.xml文件,大家会看到design和text两个选项
Text模式就是我们通过编辑xml文件来构建用户界面。
Design模式就是通过图形化的设计工具来进行设计,打开看看:
我们可以通过拖拽的方式将控件摆放在合适的位置进行页面设计。
具体选用哪种方式看自己喜欢了,这里我们选择Text模式。
接下来实现我们今天的页面布局,修改activity_main.xml文件为如下内容:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
tools:context=".MainActivity">
<TextView
android:id="@+id/tv_question"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/question_content"
android:textSize="20sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.2" />
<TextView
android:id="@+id/tv_answerA"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:text="@string/question_answerA"
android:textSize="18sp"
app:layout_constraintStart_toStartOf="@id/tv_question"
app:layout_constraintTop_toBottomOf="@id/tv_question" />
<TextView
android:id="@+id/tv_answerB"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:text="@string/question_answerB"
android:textSize="18sp"
app:layout_constraintStart_toStartOf="@id/tv_question"
app:layout_constraintTop_toBottomOf="@id/tv_answerA" />
<TextView
android:id="@+id/tv_answerC"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:text="@string/question_answerC"
android:textSize="18sp"
app:layout_constraintStart_toStartOf="@id/tv_question"
app:layout_constraintTop_toBottomOf="@id/tv_answerB" />
<TextView
android:id="@+id/tv_answerD"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:text="@string/question_answerD"
android:textSize="18sp"
app:layout_constraintStart_toStartOf="@id/tv_question"
app:layout_constraintTop_toBottomOf="@id/tv_answerC" />
<TextView
android:id="@+id/tv_confirm_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="25dp"
android:text="@string/question_confirm_title"
android:textSize="18sp"
app:layout_constraintStart_toStartOf="@id/tv_question"
app:layout_constraintTop_toBottomOf="@id/tv_answerD" />
<EditText
android:id="@+id/et_confirm_answer"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:singleLine="true"
android:text=""
android:textSize="18sp"
android:maxLength="1"
app:layout_constraintTop_toTopOf="@id/tv_confirm_title"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/tv_confirm_title" />
<Button
android:id="@+id/bt_confirm"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:minWidth="200dp"
android:text="@string/question_ok"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/et_confirm_answer" />
</androidx.constraintlayout.widget.ConstraintLayout>
最终实现的效果如下:
这里我们总结一下要注意的知识点:
组件属性
在上面的代码中,类似下面这种格式的其实都是组件属性的设置方式,每个组件都有许多属性,这里没办法全部列出。
app:layout_constraintEnd_toEndOf="parent"
最常见的控件属性:
android:layout_width
android:layout_height
可选值如下:
match_parent: 视图和父视图大小相同
wrap_parent: 视图根据其内容大小自动调整
TextView
用来显示静态文字的控件,这里就说两个属性:
android:text="@string/question_confirm_title"
android:textSize="18sp"
android:maxLength="1"
text:用来设置显示的文字内容
textSize: 用来设置字体的大小。sp作为字体大小单位,会随着系统的字体大小改变。
maxLength: 限制可输入字符数
上面的代码大家也看到了,在设置文字的时候,我们使用了:
android:text="@string/question_confirm_title"
@string/question_confirm_title
到底是什么东西呢?在Android中专业术语我们将之称之为字符串资源(string resources).
字符串资源(string resources)
在Android中,字符串文件默认被命名为strings.xml,该文件位于res/values目录下,当然了,文件的名字我们可以按照个人喜好命名。
一个项目可以有多个字符串文件,只要这些文件处在正确的目录下,即res/values目录,只要字符串文件含有一个resources根元素以及多个string子元素,那么字符串定义就能被我们找到,使用方式如上。
在Android Studio中,我们可以通过下面的方式生成字符串资源:
将鼠标定位到我们要添加的文字上,使用Alt+Enter组合键,此时会出现如下的菜单:
选择:Extract string resources后,在下面的界面中输入名称确定即可。
布局文件到这里我们就简单完成了,此时的页面并不具备和用户进行交互的能力。
要完成和用户交互逻辑,我们就得看看Android Studio为我们默认生成的MainActivity.java文件。默认生成好的文件如下:
代码很简洁,MainActivity类中只有一个重写的onCreate方法。onCreate方法是做什么的,我们可以简单的认为这个方法就是创建我们刚才写好的布局的,当然了还有其他的事情可以做。
在onCreate方法中,有这么一句代码:
setContentView(R.layout.activity_main);
它会将指定id的布局的视图生成并且将其显示在屏幕上。 R.layout.activity_main
就是我们上面编写的activity_main.xml的id,我们可以理解为id就是该资源的一个别名,通过这个名词,程序可以找到对应的资源。
资源和资源id
什么是资源呢?我们可以将一切非代码形式的内容,比如图片,视频以及xml文件等等统统称之为资源。
所以我们上面编写的activity_main.xml也是一种资源。项目的资源文件全部存放在res目录下。
那么不同名字的目录代表什么,可参考官方网站的图表:
我们这里要了解的是R.layout.activity_main
,很显然,我们的布局文件能够在一个名为R.java的文件下面找到对应的定义,所以程序才能够找到。
R.java文件是Android项目在编译的过程中自动生成的。Android会为所有的布局文件以及各个字符串生成资源id。
为控件指定id的方法在上面的布局文件中也有体现:
android:id="@+id/控件id"
在以后的代码学习过程中,我们可能还会遇到这中写法:
@id/控件id
那么这两种方式有什么区别呢?
@+id/some_value: 如果R.java中没有some_value, 则在R.java中生成一个some_value值;如果有则直接使用已经存在的值.
@id/some_value: 如果R.java中存在some_value, 则使用此值。否则会造成编译错误.
R.java文件可以在下面的目录下找到:
看看关于我们控件的内容:
获取视图控件
前面提到了,布局文件是一种资源,那么其中的控件自然也可以通过id获取到,然后进行相关的操作,修改MainActivity代码如下:
package com.qiushangge.androidstudy;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.Button;
import android.widget.EditText;
public class MainActivity extends AppCompatActivity {
private EditText et_confirm_answer;
private Button bt_confirm;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
et_confirm_answer = findViewById(R.id.et_confirm_answer);
bt_confirm = findViewById(R.id.bt_confirm);
}
}
在Android Studio中会自动为我们导入相关的类包,这里就不在做介绍。
findViewById
在上面的代码中我们使用了findViewById方法,它用来引用已经生成的组件。该方法接受组件的资源id作为参数,返回一个视图对象。
或许大家也会看到类似这样的写法:
bt_confirm = (Button)findViewById(R.id.bt_confirm);
在获取到视图对象后,需要进行强制类型转化为对应的组件,在新一点的版本中,该方法不需要进行类型转化。
获取到组件之后,我们给Button按钮绑定点击事件,当用户点击的时候,我们给出回答正确还是错误的提示。
bt_confirm.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
}
});
关于监听器推荐使用内部匿名类的方式实现,也就是上面的格式。具体的概念如果不太清楚,那应该去查阅下java文档。
接下来我们先修改下string.xml,存入我们问题的答案以及回答结果,同时修改下字符串资源的名称。
接下来我们实现答题的逻辑:
bt_confirm.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String answer = et_confirm_answer.getText().toString().trim();
if (answer.toUpperCase().equals(getString(R.string.Q1_S))) {
Toast.makeText(MainActivity.this, R.string.question_correct, Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(MainActivity.this, R.string.question_incorrect, Toast.LENGTH_SHORT).show();
}
}
});
首先我们通过EditView的getText方法获取到用户输入,然后和存储在字符串资源文件中的值进行比较,如果相同,告知用户答对了,反之亦然。
注意点:在android和java中,使用==比较字符串其实比较的是字符串的内存地址,如果要想比较两个值是否相等,那么请使用equals方法
,小坑一个请留意。
Toast
我们通常使用Toast来显示一些提示信息,格式如下:
Toast.makeText( context , text , duration).show();
context: 传入Activity本身,即类名.class的形式,这里就是MainActivity.this
text: 要显示的提示信息文字
duration: 显示时间的长短,可选值:
Toast.LENGTH_SHORT(短时间提示)
Toast.LENGTH_LONG (长时间提示)。
show()方法最终显示提示组件。
最后一步就是使用我们的模拟器运行应用了。
如果你没有安装模拟器,那么可以按照下面的步骤创建一个模拟器:
- 打开avd管理器
- 因为我已经创建了一个模拟器,所以打开后界面或没有创建的不同,找到下图的按钮点击开始创建。
创建完成后运行我们的模拟器:
在Android Studio中运行程序:
运行结果:
输入答案:
好了,今天就到这里,我们通过一个最简单的应用程序,把开发过程中遇到的问题点做了简单的介绍,如果需要更多地了解相关知识,参考官方文档。