
💎【行业认证·权威头衔】
✔ 华为云天团核心成员:特约编辑/云享专家/开发者专家/产品云测专家
✔ 开发者社区全满贯:CSDN博客&商业化双料专家/阿里云签约作者/腾讯云内容共创官/掘金&亚马逊&51CTO顶级博主
✔ 技术生态共建先锋:横跨鸿蒙、云计算、AI等前沿领域的技术布道者
🏆【荣誉殿堂】
🎖 连续三年蝉联"华为云十佳博主"(2022-2024)
🎖 双冠加冕CSDN"年度博客之星TOP2"(2022&2023)
🎖 十余个技术社区年度杰出贡献奖得主
📚【知识宝库】
覆盖全栈技术矩阵:
◾ 编程语言:.NET/Java/Python/Go/Node...
◾ 移动生态:HarmonyOS/iOS/Android/小程序
◾ 前沿领域:物联网/网络安全/大数据/AI/元宇宙
◾ 游戏开发:Unity3D引擎深度解析
文章目录
🚀前言
本章将介绍的是Android应用程序掌上杭州的开发。掌上杭州主要有首页、搜索、设置3大主项,其中首页包含美食、景点、住宿、医疗、娱乐、购物,设置中包含了设置字体、关于和帮助,搜索中可方便地搜索当前应用中的信息。接下来将对掌上杭州进行详细的介绍。
🚀一、辅助工具类的开发
前面已经介绍了掌上杭州功能的预览以及总体架构,下面将介绍项目所需要的工具类。工具类被项目其他 Java 文件多次调用,避免重复性开发,同时提高了程序的可维护性,可谓是一劳永逸。工具类在这个项目中十分常用,请读者仔细阅读。
🔎1.常量类的开发
本小节将向读者介绍掌上杭州中的常量类 Constant 的开发。软件内有许多地方需要重复调用的常量,为了避免重复在 Java 文件中定义常量,于是我们将多处需要的常量放在了 Constant.java 文件中方便开发者的管理和修改,其具体代码如下所示。
代码位置 :见随书源代码/第3章/HangZhou/app/src/main/java/com/cn/util 目录下的 Constant.java。
java
package com.cn.util;
public class Constant {
public static final String ADD_PRE = "/sdcard/zshz/"; // 文件路径
public static final int WAIT_DIALOG_REPAINT = 0; // 等待对话框刷新消息编号
public static final int WAIT_DIALOG = 0; // 等待对话框编号
public static final int INFO_MYSQL = 1; // 编号
public static int TEXT_SIZE = 16; // 文字的大小
public static String snzy = "zhongn"; // 中文文本
public static int COLOR = R.color.black; // 字体颜色
public static final int PHOTOHRAPH = 1; // 拍照调用系统照相机时使用
public static Location myLocation; // 游客当前的经纬度位置
public static final int SHOWMOREDIALOG = 1; // 显示更多对话框
public static final int EXIT_DIALOG = 2; // 询问是否退出对话框
public static String curSMP = null; // 记录当前正在播报的景点名
public static String curScenicId = null; // 记录当前显示景点的编号
public static final int DISTANCE_SCENIC = 200; // 景点范围的阈值
public static final int DISTANCE_USER = 100; // 用户移动范围的阈值
public static final double EARTH_RADIUS = 6378137.0; // 地球半径
}
说明:常量类的开发是高效完成项目的一项十分必要的准备工作,这样可以避免在不同的 Java 文件中定义常量的重复性工作,提高了代码的可维护性。如果读者在下面的类或方法中有不明白具体含义的常量,可以在本类中查找。
🔎2.图片获取类的开发
上一小节中介绍了掌上杭州常量类的开发,本小节将介绍图片获取类的开发。软件中需要加载大量的图片,于是我们开发了从 SD 卡中加载指定的图片的 BitmapIOUtil 类。BitmapIOUtil 类供其他 Java 文件调用,提高了程序的可读性和可维护性,具体代码如下。
代码位置 :见随书源代码/第3章/HangZhou/app/src/main/java/com/cn/util 目录下的 BitmapIOUtil.java。
java
package com.cn.util;
// 此处省略了本类中导入类的代码,读者可自行查阅随书的源代码
public class BitmapIOUtil { // 图片获取类
static Bitmap bp = null; // Bitmap对象
public static Bitmap getSBitmap(String subPath) {
String path = Constant.ADD_PRE + subPath; // 获取路径字符串
try {
bp = BitmapFactory.decodeFile(path); // 实例化Bitmap
} catch (Exception e) {
System.out.println("出现异常!"); // 打印字符串
}
return bp; // 返回Bitmap对象
}
}
说明 :上述代码表示利用 BitmapFactory 类的 decodeFile(String path) 方法来加载指定路径的位图,显示原图。path 表示要解码的文件路径名的完整路径名,最后返回获得的解码的位图。如果指定的文件名称 path 为 null,则不能被解码成位图,该函数返回 null。
🔎3.解压文件类的开发
上一小节中介绍了图片获取类的开发,本小节将继续给大家介绍本应用的第 3 个工具类 ZipUtil,该类为解压文件类。程序在初次运行时将调用该类,用于将 HangZhou/assets 中的 .zip 文件解压到 SD 卡中供程序中获取资源使用,具体代码如下。
代码位置 :见随书源代码/第3章/HangZhou/app/src/main/java/com/cn/util 目录下的 ZipUtil.java。
java
package com.cn.util;
// 此处省略了导入类的代码,读者可自行查阅随书的源代码
public class ZipUtil {
// 解压.zip压缩文件方法
public static void unZip(Context context, String assetName, String outputDirectory) throws IOException {
File file = new File(outputDirectory); // 创建解压目标目录
if (!file.exists()) { // 如果目标目录不存在,则创建
file.mkdirs(); // 创建目录
}
InputStream inputStream = null;
inputStream = context.getAssets().open(assetName); // 打开压缩文件
ZipInputStream zipInputStream = new ZipInputStream(inputStream);
ZipEntry zipEntry = zipInputStream.getNextEntry(); // 读取一个条目
byte[] buffer = new byte[1024 * 1024]; // 使用1M buffer
int count = 0; // 解压时字节计数
while (zipEntry != null) { // 如果条目为空说明已经遍历完所有压缩包中文件和目录
// 如果是一个目录
if (zipEntry.isDirectory()) {
file = new File(outputDirectory + File.separator + zipEntry.getName());
file.mkdir(); // 创建文件
} else { // 如果是文件
file = new File(outputDirectory + File.separator + zipEntry.getName());
file.createNewFile(); // 创建该文件
FileOutputStream fileOutputStream = new FileOutputStream(file);
while ((count = zipInputStream.read(buffer)) > 0) {
fileOutputStream.write(buffer, 0, count);
}
fileOutputStream.close(); // 关闭文件输出流
}
zipEntry = zipInputStream.getNextEntry(); // 定位到下一个文件入口
}
zipInputStream.close(); // 关闭流
}
}
- 第6~9行:用于创建解压目标目录,并且判断目标目录是否存在,不存在则创建。
- 第11~13行 :用于打开压缩文件,创建
ZipInputStream对象,并读取.zip文件中的内容。 - 第14~15行:用于设置读取文本的 Byte 值和解压时字节计数。
- 第16~30行:用于判断进入点是否为空,若为空,说明已经遍历完所有压缩包中文件和目录,则开始进行解压文本文件。
- 第31行 :用于关闭
ZipInputStream流。
🔎4.读取文件类的开发
上一小节中介绍了解压文件类的开发,本小节将继续介绍本应用的第 4 个工具类 PubMethod,该类为读取文件类。该类在程序中将多次被调用,用于获取各个界面中所需要的文本信息,极大地提高了程序的可读性和可维护性,具体实现代码如下。
代码位置 :见随书源代码/第3章/HangZhou/app/src/main/java/com/cn/util 目录下的 PubMethod.java。
java
package com.cn.util; // 声明包
// 此处省略了导入类的代码,读者可自行查阅随书的源代码
public class PubMethod {
Activity activity; // 创建Activity对象
// 无参构造器
public PubMethod() {
}
public PubMethod(Activity activity) {
this.activity = activity; // 赋值
}
// 获取文件信息
public String loadFromFile(String fileName) {
String result = null;
try {
File file = new File(Constant.ADD_PRE + fileName); // 创建File类对象
int length = (int) file.length(); // 获取文件长度
byte[] buff = new byte[length]; // 创建byte数组
FileInputStream fin = new FileInputStream(file); // 创建FileInputStream流对象
fin.read(buff); // 读取文本文件
fin.close(); // 关闭文件流
result = new String(buff, "UTF-8"); // 文本字体设置为汉字
result = result.replaceAll("\\r\\n", "\n"); // 替换转行字符
} catch (Exception e) { // 捕获异常
Toast.makeText(activity, "对不起,没有找到该文件!", Toast.LENGTH_SHORT).show();
}
return result; // 返回数据
}
}
- 第6~8行 :为构造函数,用于获得
Activity对象。 - 第12~14行:用于打开文本文件,获得文本文件的长度,设置读取文本的 Byte 数组值。
- 第15~17行 :创建
FileInputStream对象,并读取文本文件,读完文本文件后则关闭文件流。 - 第18~19行 :用于将字体转换成汉字,并且将
\r\n换成\n。 - 第21~22行:提示用户该文件不存在。
🔎5.自定义字体类的开发
上一小节中介绍了读取文件类的开发,本小节将继续介绍本应用中用到的第 5 个工具类 FontManager,该类为自定义字体类。该类在程序中多次被调用,用来将各个界面中的字体设置为各种用户所需的字体,使界面更具艺术性,具体实现代码如下。
代码位置 :见随书源代码/第3章/HangZhou/app/src/main/java/com/cn/util 目录下的 FontManager.java。
java
package com.cn.util; // 声明包
// 此处省略了导入类的代码,读者可自行查阅随书的源代码
public class FontManager {
public static Typeface tf = null; // 声明字体变量
// 初始化字体
public static void init(Activity act, String xx) {
if (tf == null) {
tf = Typeface.createFromAsset(act.getAssets(), "fonts/kaiti.ttf");
} else {
if (xx.equals("kaiti")) {
// 设置楷体
}
// 此处省略了字体的多种类型,读者可自行查阅随书的源代码
}
}
// 转换字体
public static void changeFonts(ViewGroup root, Activity act) {
for (int i = 0; i < root.getChildCount(); i++) {
View v = root.getChildAt(i); // 获取控件
if (v instanceof TextView) {
((TextView) v).setTypeface(tf); // 转换TextView控件中的字体
} else if (v instanceof Button) {
((Button) v).setTypeface(tf); // 转换Button控件中的字体
} else if (v instanceof EditText) {
((EditText) v).setTypeface(tf); // 转换EditText控件中的字体
} else if (v instanceof ViewGroup) {
changeFonts((ViewGroup) v, act); // 重新调用changeFonts()方法
}
}
}
// 获取控件的方法
public static ViewGroup getContentView(Activity act) {
ViewGroup systemContent = (ViewGroup) act.getWindow().getDecorView().findViewById(android.R.id.content); // 创建ViewGroup
ViewGroup content = null;
if (systemContent.getChildCount() > 0 && systemContent.getChildAt(0) instanceof ViewGroup) {
content = (ViewGroup) systemContent.getChildAt(0); // 给content赋值
}
return content; // 返回获取的控件
}
}
- 第3~14行 :初始化
Typeface。第一次调用FontManager类时,调用init()方法,若Typeface为空,则创建Typeface对象。 - 第15~26行:用于转换界面中的字体。用循环遍历界面中的各个控件,并将控件中的所有字体转换为卡通字体。
- 第27~36行 :用于获得传过来的
Activity,若该Activity的内容大于 0 并且其中的控件属于ViewGroup,则获取该控件并返回。