本文通过开发一个应用来学习Android基本概念及构成应用的UI组件。

开发的应用名叫GeoQuiz,它能给出一道道地理知识问题。用户点击true或false按钮回答问题,应用即时做出反馈

第一步请先自行创建一个新项目,目录如下

1. 用户界面设计

  • 在XML文件(activity_quiz.xml)中定义组件
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"> <TextView
android:id="@+id/question_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="24dp" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"> <Button
android:id="@+id/true_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/true_button"/>
<Button
android:id="@+id/false_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/false_button"/>
</LinearLayout>
<Button
android:id="@+id/cheat_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/cheat_button"/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"> <Button
android:id="@+id/pre_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/pre_button"
android:drawableLeft="@drawable/arrow_left"/>
<ImageButton
android:id="@+id/next_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/arrow_right"
android:contentDescription="@string/next_button"/>
</LinearLayout>
</LinearLayout>

activity_quiz.xml 效果图

  • 创建字符串资源

最好不要硬编码设置组件的文本信息,如:android:text="True"。较好的做法是将文字内容放置在独立的字符串资源XML文件中,然后引用它们,如:android:text="@string/true_button"。

找到app/res/values目录,打开string.xml文件

添加字符串资源

<resources>
<string name="app_name">GeoQuiz</string>
<string name="true_button">True</string>
<string name="false_button">False</string>
<string name="pre_button">Pre</string>
<string name="next_button">Next</string>
<string name="correct_toast">Correct!</string>
<string name="incorrect_toast">Incorrect!</string>
<string name="question_oceans">The Pacific Ocean is larger than
the Atlantic Ocean.</string>
<string name="question_mideast">The Suez Canal connects the Red Sea
and the Indian Ocean.</string>
<string name="question_africa">The source of the Nile River is in Egypt.</string>
<string name="question_americas">The Amazon River is the longest river in the Americas.</string>
<string name="question_asia">Lake Baikal is the world\'s oldest and deepest
freshwater lake.</string>
<string name="warning_text">Are you sure you want to do this?</string>
<string name="show_answer_button">SHOW ANSWER</string>
<string name="cheat_button">CHEAT!</string>
<string name="judgment_toast">Cheating is wrong.</string>
<string name="fist_page">This is the first page!</string>
</resources>

2. 从布局XML到视图对象

  • activity子类的实例创建后,onCreate(Bundle)方法会被调用,同时需要获取并管理用户界面,可再调用setContentView(int layoutResID),根据传入的布局资源ID参数,生成指定布局视图并将其放在屏幕上,布局文件包含的组件也随之以各自的属性定义完成实例化。
public class QuizActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_quiz);
}
}
  • 资源和资源ID

    1. 使用资源ID在代码中获取相应的资源。activity_quiz.xml布局的资源ID为R.layout.activity_quiz。
    2. 应用当前所有的资源放置在R.java文件中。切换至Project视图,展开目录app/build/generated/source/r.debug即可看到。R.java文件在Android项目编译过程中自动生成,修改布局或字符串等资源后,需再次运行应用,才会得到更新。
    3. 为需要的组件添加资源ID。如:android:id="@+id/idName"。
  • 组件的应用
    private Button mTrueButton;//在activity_quiz.java添加成员变量
@Override
protected void onCreate(Bundle savedInstanceState) {
......
mTrueButton=(Button)findViewById(R.id.true_button);//引用组件
mTrueButton.setOnClickListener(new View.OnClickListener(){ @Override
public void onClick(View v) {
//设置监听事件
}
});
}

3. 创建提示消息

Android的toast是用来通知用户的简短弹出消息。调用Toast类的以下方法可创建toast:

public static Toast makeText(Context context,int resId,int durattion)
  • Context参数通常是Activity的一个实例(Activity本身就是Context的子类)。
  • 第二个参数是toast要显示字符串消息的资源ID。
  • 第三个参数用来指定toast消息的停留时间。通常是Toast常量中的一个。
//举个例子来说
Toast.makeText(QuizActivity.this,R.string.incorrect_toast,Toast.LENGTH_SHORT).show();

4. Android与MVC设计模式

  • 应用对象按模型、控制器和视图的类别分为三部分。Android应用基于模型-

    控制器-视图(Model-View-Controller,MVC)的架构模式进行设计。MVC设计模式表明,应用的任何对象,归根结底都属于模型对象、视图对象以及控制对象中的一种。

  • 我们使用 QuizActivity 创建 Question 数组对象。继而通过与 TextView 以及三个 Button 的交互,在屏幕上显示地理知识问题,并根据用户的回答作出反馈,如图2-4所示。

  • 模型层 Question类代码
public class Question {
private int mTextResId;//保存地理知识问题字符串的资源ID。资源ID总是int类型
private boolean mAnswerTrue;//问题答案 public Question(int textResId,boolean answerTrue){
mTextResId=textResId;
mAnswerTrue=answerTrue;
} public int getTextResId() {
return mTextResId;
} public void setTextResId(int textResId) {
mTextResId = textResId;
} public boolean isAnswerTrue() {
return mAnswerTrue;
} public void setAnswerTrue(boolean answerTrue) {
mAnswerTrue = answerTrue;
}
}

对于有前缀m的成员变量生成getter与setter方法

首先,配置Android Studio识别成员变量的 m 前缀。

打开Android Studio首选项对话框(Mac用户选择Android Studio菜单,Windows用户选择File →

Settings菜单)。分别展开Editor和Code Style选项,在Java选项下选择CodeGeneration选项页。在Naming表单中,选择Fields行,添加m作为fields的前缀。若要添加静态变量前缀s,则添加 s 作为Static Fields的前缀。如下图。

  • 控制器层QuizActivity.java
public class QuizActivity extends AppCompatActivity {
private ImageButton mNextButton; private TextView mQuestionTextView; private Question[] mQuestionBank=new Question[]{
new Question(R.string.question_oceans,true),
new Question(R.string.question_mideast,false),
new Question(R.string.question_africa,false),
new Question(R.string.question_americas,true),
new Question(R.string.question_asia,true)
}; private int mCurrentIndex=0; }

5. 添加图片资源

1.将图片添加到drawable对应目录中,后缀名为.png、.jpg、.gif的文件都会自动获得资源ID
  • mdpi:中等像素密度屏幕(约160dpi)
  • hdpi:高等像素密度屏幕(约240dpi)
    • xhdpi:超高像素密度屏幕(约320dpi)
    • xxdpi:超超高像素密度屏幕(约480dpi)
2. 在XML文件中引用资源
  • 为next按钮增加图片(activity_quiz.xml)
 <Button
android:id="@+id/next_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/next_button"
android:drawableLeft="@drawable/arrow_righ
android:drawablePadding="4dp"/>

以@string/开头的定义是引用字符串资源

以@drawable/开头的定义是引用drawable资源

ImageButton组件继承自ImageView。Button组件则继承自TextView。ImageView和TextView继承自View

也可以ImageButton组件替换Button组件。删除next按钮的text以及drawable属性定义,并添加ImageView属性。

 <ImageButton
android:id="@+id/next_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/arrow_right"
android:contentDescription="@string/next_button"/>

6. activity的生命周期

设备旋转时,系统会销毁当前QuizActivity实例,然后创建一个新的QuizActivity实例。所以每次旋转设备用户每次都会从第一题开始,现在来修正这个缺陷。

  • 创建水平模式布局

右键单击res目录选择New->Android resource directory。资源类型选择layout,保持Source set的main选项不变,选择待选资源列表中的Orientation,然后单击>>按钮将其移动到已选资源特征区域。

最后,确认选中Screen orientation下拉列表中的Landscape选项,并确保目录名显示为layout-land

这里的-land后缀名是配置修饰符的另一个使用例子。Android依靠res子目录的配置修饰符定位最佳资源以匹配当前设备配置。设备处于水平方向时,Android会找到并使用res/layout-land目录下的布局资源。其它情况下,它会默认使用res/layout目录下的布局资源。

  • 将res/layout目录下的activity_quiz.xml文件复制到res/layout-land目录。

注意:两个布局文件的文件名必须相同,这样它们才能以同一个资源ID被引用

  • 水平模式布局修改(layout-land/activity_quiz.xml)

FrameLayout替换了最上层的LinearLayout。FrameLayout是最简单的ViewGroup组件,它一概不管如何安排其子视图的位置。FrameLayout子视图的位置排列取决于它们各自的android:layout_gravity属性

<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"> <TextView
android:id="@+id/question_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:padding="24dp" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|center_horizontal"
android:orientation="horizontal"> <Button
android:id="@+id/true_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/true_button"/>
<Button
android:id="@+id/false_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/false_button"/>
</LinearLayout>
<Button
android:id="@+id/cheat_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center"
android:text="@string/cheat_button"/> <Button
android:id="@+id/pre_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|left"
android:text="@string/pre_button"
android:drawableLeft="@drawable/arrow_left"
android:drawablePadding="4dp"/>
<ImageButton
android:id="@+id/next_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|right"
android:src="@drawable/arrow_right"
android:contentDescription="@string/next_button"/>
</FrameLayout>
  • 保存数据以应对设备旋转

覆盖以下Activity方法

protected void onSaveInstanceState(Bundle outState)
  • 该方法通常在onStop()方法之前由系统调用,除非用户按后退键。
  • 该方法的默认实现要求所有activity视图将自身数据状态保存在Bundle对象中。Bundle是存储字符串键与限定类型值之间映射关系(键值对)的一种结构。
public class QuizActivity extends AppCompatActivity {
......
private int mCurrentIndex=0;
private static final String KEY_INDEX="index";
@Override
protected void onSaveInstanceState(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState); savedInstanceState.putInt(KEY_INDEX,mCurrentIndex);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_quiz); if(savedInstanceState!=null){
mCurrentIndex=savedInstanceState.getInt(KEY_INDEX,0);
}
......
}
......
}

7. 日志

public static int d(String tag,String msg)//输出日志信息d:debug

方法的第一个参数通常是以类名为值的TAG常量传入

public class QuizActivity extends AppCompatActivity {
private static final String TAG="QuizActivity";
......
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); Log.d(TAG,"onCreate(Bundle) called"); setContentView(R.layout.activity_quiz); ......
}
}
日志级别 方法 说明
ERROR Log.e(...) 错误
WARNING Log.w(...) 警告
INFO Log.i(...) 信息型消息
DEBUG Log.w(...) 调试输出
VERBOSE Log.v(...) 仅用于开发

所有的日志记录方法都有两种参数签名:string类型的tag参数和msg参数;除tag和msg参数外再加上Throwable实例参数

9. 第二个activity

新activity将带来第二个用户界面,方便用户偷看问题的答案

第二个activity的布局组件的定义(activity_cheat.xml)

<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
tools:context="com.example.mdx.studyworks.CheatActivity"> <TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="24dp"
android:text="@string/warning_text"/>
<TextView
android:id="@+id/answer_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="24dp"
tools:text="Answer"/>
<Button
android:id="@+id/show_answer_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/show_answer_button"/> </LinearLayout>

activity_cheat.xml 效果图

  • 注意用于显示答案的TextView组件,它的tools和tools:text属性的命名空间比较特别。该命名空间可以覆盖某个组件的任何属性。这样,可在预览中看到效果,而在运行时Answer文字不会显现出来。
  • 应用的所有activity都必须在manifest配置文件中声明,这样操作系统才能找到它们。
//在manifest配置文件中声明CheatActivity
<activity android:name=".CheatActivity">
</activity>

启动activity

public void startActivity(Intent intent)

activity调用startActivity(Intent)方法时,调用请求实际发给了操作系统的ActivityManager。ActivityManager负责创建Activity实例并调用其onCreate(Bundle)方法

public Intent(Context pageContext,Class<?> cls)

传入该方法的Class类型参数告诉ActivityManager应该启动哪个activity

Context参数告诉ActivityManager在哪里可以找到它

    mCheatButton=(Button)findViewById(R.id.cheat_button);
mCheatButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//从QuizActivity启动CheatActivity
Intent i=new Intent(QuizActivity.this,CheatActivity.class);
startActivity(i);
}
});

activity间数据传递

  • 使用 intent extra

将extra数据信息添加给intent,调用Intent.putExtra(...)方法

public Intent putExtra(String name,boolean value)
 Intent i=new Intent(QuizActivity.this,CheatActivity.class);
i.putExtra(EXTRA_ANSWER_IS_TRUE,answerIsTrue);
startActivity(i)

从extra获取数据

public boolean getBooleanExtra(String name,boolean defaultValue)
 mAnswerIsTrue=getIntent().getBooleanExtra(EXTRA_ANSWER_IS_TRUE,false);

Activity.getIntent()方法返回了由startActivity(Intent)方法转发的Intent对象

  • 从子activity获取返回结果
//父activity
/*第二个参数是请求码,*/
public void startActivityForResult(Intent intent,int requestCode) //子activity发送返回信息给父activity,有2种方法
public final void setResult(int resultCode)
public final void setResult(int resultCode,Intent data)

resultCode可以是以下任意一个预定义常量

  • Activity.RESULT_OK ,即1
  • Activity.RESULT_CANCELED ,即0

如需自定义结果代码,还可使用另一个常量:RESULT_FIRST_USER

//父,QuizActivity
private static final int REQUEST_CODE_CHEAT=0; mCheatButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
boolean answerIsTrue=mQuestionBank[mCurrentIndex].isAnswerTrue(); Intent i=new Intent(QuizActivity.this,CheatActivity.class);
i.putExtra(EXTRA_ANSWER_IS_TRUE,answerIsTrue);
startActivityForResult(i,REQUEST_CODE_CHEAT);
}
});
//处理返回结果
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
//super.onActivityResult(requestCode, resultCode, data);
//结果码不一致
if (resultCode!= Activity.RESULT_OK){
return;
}
//结果码一致
if (requestCode==REQUEST_CODE_CHEAT){
if (data==null){
return;
}
//解析结果intent
mIsCheater=data.getBooleanExtra(EXTRA_ANSWER_SHOW,false); }
}
//子,CheatActivity
Intent data=new Intent();
data.putExtra(EXTRA_ANSWER_SHOW,isAnswerShown);
setResult(RESULT_OK,data);//设置返回结果

10. activity的使用与管理

被指定为应用的第一个activity

<!--指定第一个activity是QuizActivity-->
<activity android:name=".QuizActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>

Android开发初体验的更多相关文章

  1. Xamarin.iOS开发初体验

    aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKwAAAA+CAIAAAA5/WfHAAAJrklEQVR4nO2c/VdTRxrH+wfdU84pW0

  2. Microsoft IoT Starter Kit 开发初体验-反馈控制与数据存储

    在上一篇文章<Microsoft IoT Starter Kit 开发初体验>中,讲述了微软中国发布的Microsoft IoT Starter Kit所包含的硬件介绍.开发环境搭建.硬件 ...

  3. IOS开发初体验

    IOS开发初体验 搭建开发环境 不多说什么了,开发环境的搭建太简单了,上App Store搜索XCode下载就行了,说多了都是眼泪 创建第一个IOS项目--HolleIOS 创建工程 选择工程创建位置 ...

  4. 中文代码示例之NW.js桌面应用开发初体验

    先看到了NW.js(应该是前身node-webkit的缩写? 觉得该起个更讲究的名字, 如果是NorthWest之意的话, logo(见下)里的指南针好像也没指着西北啊)和Electron的比较文章: ...

  5. Online开发初体验——Jeecg-Boot 在线配置图表

    Online开发——初体验(在线配置图表) 01 通过JSON数据,快速配置图形报表 02 通过SQL数据,快速配置图形报表 03 图表模板配置,实现不同数据源图表合并展示 04 图表布局,支持单排. ...

  6. Apache Beam入门及Java SDK开发初体验

    1 什么是Apache Beam Apache Beam是一个开源的统一的大数据编程模型,它本身并不提供执行引擎,而是支持各种平台如GCP Dataflow.Spark.Flink等.通过Apache ...

  7. Visual Studio 2015 移动跨平台开发初体验

    微软换了新 CEO 后变化很大,对我们团队最有利的消息就是 Visual Studio 2015 支持移动应用跨平台开发. 还记不记得很早之前,Xamarin 宣布与微软成为合作伙伴的消息.显然,Xa ...

  8. Microsoft IoT Starter Kit 开发初体验

    1. 引子 今年6月底,在上海举办的中国国际物联网大会上,微软中国面向中国物联网社区推出了Microsoft IoT Starter Kit ,并且免费开放1000套的申请.申请地址为:http:// ...

  9. ThinkPHP -- 开发初体验及其几个配置文件的介绍

    ThinkPHP是一款不错的轻量级的PHP+MVC框架,它吸取了Ruby On Rails的特性,不仅将Model.View.Controller分开,而且实现了ORM.模板标签等高级特性.    开 ...

随机推荐

  1. image url to base64

    image url to base64 https://www.base64-image.de/ https://www.browserling.com/tools/image-to-base64 h ...

  2. 如何将jsp后缀重写为html

    公司有时候要写一些小的项目,而用java搭建web的一个缺(特)陷(征)就是动态网页的后缀名.jsp.没办法啊,就是不能以.jsp结尾,原因有几个:隐藏服务端技术:吸引爬虫:对用户更友好:等等.如果全 ...

  3. codevs3411 洪水

    题目描述 Description 小浣熊松松和朋友到野外露营,没想到遇上了π年一次的大洪水,好在松松是一只爱观察的小浣熊,他发现露营地的地形和洪水有如下性质: ①露营地可以被看做是一个N*M的矩形方阵 ...

  4. IT领域的罗马帝国——微软公司

    微软公司从做软件开始,起步很小.但是盖茨确是一直深耕于战略布局,像一个棋局高手,每一步棋都是看了后面几步. 盖茨居然用9年的时间憋出一个win3.0,成功击败了apple. 而这9年拖住apple的居 ...

  5. Oracle RAC load blance

    首先声明 本文基本是阅读 大话RAC 后的笔记.OK, 进入正题. Oracle 10g RAC中采取两种方式提供负载均衡.第一种是connection blance.在用户连接的时候,根据随机算法把 ...

  6. 交换机是干嘛的!!交换机如何学习MAC地址过程?

    1.它收到一个帧的时候,先检查源MAC地址,看看自己维护的一个地址表中有没有这个地址.如果有,则2:如果没有,则将这个MAC地址.进入的端口.进入的时间放入这个表中: 2.检查目的MAC地址,然后到该 ...

  7. Rsync命令的使用

    Rsync的命令格式能够为下面六种: rsync [OPTION]- SRC DEST rsync [OPTION]- SRC [USER@]HOST:DEST rsync [OPTION]- [US ...

  8. 【翻译自mos文章】rman 标准版和企业版的兼容性

    rman 标准版和企业版的兼容性 来源于: RMAN Standard and Enterprise Edition Compatibility (文档 ID 730193.1) 适用于: Oracl ...

  9. Android开发系列(二十四):Notification的功能与使用方法

    关于消息的提示有两种:一种是Toast,一种就是Notification.前者维持的时间比較短暂.后者维持的时间比較长. 并且我们寻常手机的应用比方网易.贴吧等等都有非常多的推送消息,就是用Notif ...

  10. LinearLayout (线性布局)的分析

    android提供了5中布局,线性布局,相对布局,帧布局.表格布局和绝对布局 线性和相对布局用的是最多的 以下要说的是线性布局 提到线性布局 一定要记住.它里面的全部组件一定不会重叠的, 切不会换行. ...