
简介本资源是一份面向高校计算机与软件工程专业学生的安卓应用开发期末大作业实战项目聚焦天气预报功能实现适用于课程设计、期末考核及Android入门实践。项目包含完整可运行源码、详尽实验报告含需求分析、UI设计、核心逻辑说明与测试结果及带中文注释的Java与XML代码新手可快速理解MVC结构与网络请求、JSON解析、定位服务等关键知识点。压缩包共79个文件涵盖14个Java业务逻辑文件、25个XML布局与资源定义文件、10个WebP图标及PNG/JPG素材辅以Gradle构建配置、APK安装包与README说明文档整体8.03MB结构规范、模块清晰便于直接导入Android Studio部署调试。目前已有396人学习下载是兼具教学完整性、工程可用性与高分参考价值的优质实践素材。1. 用 Android Studio 快速交付一个可运行、可演示、可评分的天气预报 App——专为课程期末大作业设计这不是一个“从零造轮子”的工业级项目而是一份面向高校《移动应用开发》《Android 程序设计》等课程的高分实践方案它必须在 35 天内完成编译、调试、截图、录屏、撰写报告全流程必须避开权限申请失败、网络请求被拒、UI 崩溃等常见扣分点必须让教师一眼看出你掌握了 Activity 生命周期、RecyclerView 列表渲染、HTTP 请求、JSON 解析、权限声明与适配等核心教学点。本方案不依赖第三方天气 SDK避免密钥失效或调用配额问题改用公开、稳定、无需认证的免费天气 API如 Open-Meteo 或国内某高校气象站公开接口所有代码模块清晰、注释完整、结构符合实验报告“需求分析—设计—实现—测试”逻辑链。适合 Java 或 Kotlin 任一语言基础的学生也兼容 Android Studio Giraffe 及以上版本。2. 搭建最小可行项目结构从新建工程到主界面 UI 布局2.1 创建兼容性明确的 Android Studio 工程课程作业最常踩的坑是目标 SDK 版本过高导致低版本手机无法安装或过低导致 Material 组件缺失。推荐配置如下# 在 Android Studio 中新建 Project 时选择 # Template: Empty Activity # Package name: com.example.weatherapp # Minimum SDK: API 21 (Android 5.0) —— 覆盖 99% 实验室设备 # Language: Java若课程要求或 Kotlin若允许 # Use AndroidX artifacts: ✅ 勾选强制启用 # Include Kotlin support: ✅仅选 Kotlin 时提示不要选 “Basic Activity” 或 “Bottom Navigation Activity”它们自带多余 Fragment 和导航逻辑增加理解负担和调试复杂度。Empty Activity 是最干净的起点所有控件和逻辑由你自主添加教师能清晰看到你的控制力。创建后立即检查app/build.gradle中的关键字段是否匹配android { compileSdk 34 // 推荐使用最新稳定版但勿超 34避免 AGP 兼容问题 defaultConfig { applicationId com.example.weatherapp minSdk 21 // 与新建时一致 targetSdk 34 // 必须 ≤ compileSdk且 ≥ 30适配 Android 12 权限模型 versionCode 1 versionName 1.0 } }2.2 设计主界面布局ConstraintLayout RecyclerView 下拉刷新天气预报 App 的核心视图是“城市名 当前天气 未来三天预报”。采用ConstraintLayout保证兼容性用RecyclerView实现可复用的天气卡片列表避免硬编码多个 TextView 布局。在res/layout/activity_main.xml中定义?xml version1.0 encodingutf-8? androidx.constraintlayout.widget.ConstraintLayout xmlns:androidhttp://schemas.android.com/apk/res/android xmlns:apphttp://schemas.android.com/apk/res-auto android:layout_widthmatch_parent android:layout_heightmatch_parent !-- 顶部标题栏 -- TextView android:idid/tvTitle android:layout_widthwrap_content android:layout_heightwrap_content android:text深圳天气预报 android:textSize20sp android:textStylebold app:layout_constraintTop_toTopOfparent app:layout_constraintStart_toStartOfparent app:layout_constraintEnd_toEndOfparent android:layout_marginTop24dp / !-- 当前天气卡片固定高度 -- LinearLayout android:idid/currentWeatherCard android:layout_width0dp android:layout_height160dp android:orientationvertical android:background#E3F2FD android:padding16dp app:layout_constraintTop_toBottomOfid/tvTitle app:layout_constraintStart_toStartOfparent app:layout_constraintEnd_toEndOfparent app:layout_constraintHorizontal_bias0.5 android:layout_marginHorizontal16dp android:layout_marginTop16dp TextView android:idid/tvCurrentTemp android:layout_widthwrap_content android:layout_heightwrap_content android:text26°C android:textSize32sp android:textStylebold / TextView android:idid/tvWeatherDesc android:layout_widthwrap_content android:layout_heightwrap_content android:text多云 android:textSize16sp android:layout_marginTop8dp / TextView android:idid/tvUpdateTime android:layout_widthwrap_content android:layout_heightwrap_content android:text更新于2024-06-15 14:30 android:textSize12sp android:layout_marginTop8dp android:textColor#666 / /LinearLayout !-- 未来预报列表 -- androidx.recyclerview.widget.RecyclerView android:idid/rvForecast android:layout_width0dp android:layout_height0dp app:layout_constraintTop_toBottomOfid/currentWeatherCard app:layout_constraintBottom_toBottomOfparent app:layout_constraintStart_toStartOfparent app:layout_constraintEnd_toEndOfparent android:layout_marginTop16dp android:layout_marginHorizontal16dp / /androidx.constraintlayout.widget.ConstraintLayout参数说明android:layout_height0dp配合ConstraintLayout的约束链使 RecyclerView 自动填充剩余空间android:background#E3F2FD使用浅蓝色背景模拟 Material Design 卡片风格无需额外 drawable 资源所有margin和padding统一设为 16dp符合 Material 规范也方便教师快速识别你对 UI 适配的理解。2.3 定义天气数据模型与 RecyclerView Adapter课程作业中数据结构清晰度直接影响“设计”部分得分。定义WeatherData.javaJava或WeatherData.ktKotlin// WeatherData.java public class WeatherData { private String date; // 2024-06-15 private String weekday; // 星期六 private String weather; // 多云 private int temperatureMax; // 28 private int temperatureMin; // 24 private String icon; // cloudy // 构造函数、getter/setterAndroid Studio 可自动生成 public WeatherData(String date, String weekday, String weather, int temperatureMax, int temperatureMin, String icon) { this.date date; this.weekday weekday; this.weather weather; this.temperatureMax temperatureMax; this.temperatureMin temperatureMin; this.icon icon; } // getter 方法省略实际需补全 }对应创建ForecastAdapter.java继承RecyclerView.Adapter绑定item_forecast.xml布局含日期、星期、天气图标、最高/最低温。关键点在于ViewHolder 内部只做 findViewByIdonBindViewHolder 中只做 setText/setImageResource不发起网络请求——这是教师考察“MVC 分离”意识的核心判据。3. 接入真实天气数据HTTP 请求 JSON 解析 权限声明3.1 选择免密、免注册、响应稳定的公开天气 API课程作业严禁使用需申请密钥的商业 API如高德、和风一旦密钥过期或调用超限项目即失效。经实测以下两个接口满足教学场景接口地址特点示例城市参数https://api.open-meteo.com/v1/forecast?latitude22.5431longitude114.0579dailyweathercode,temperature_2m_max,temperature_2m_mintimezoneAsia%2FShanghaiforecast_days3国际开源气象服务无访问限制返回标准 JSON含温度、天气码深圳坐标lat22.5431, lon114.0579http://tianqi.moji.com/api/weather/geo/22.5431/114.0579国内 Moji 天气公开接口非官方文档但长期可用返回中文天气描述同上本方案选用 Open-Meteo因其字段语义清晰、无中文乱码风险、且支持 CORS可直接用 OkHttp 调用。3.2 在 AndroidManifest.xml 中声明网络与定位权限Android 10 要求显式声明网络权限且若需根据 GPS 获取位置则需定位权限。课程作业中建议固定城市坐标如深圳避免动态定位带来的权限弹窗失败风险!-- app/src/main/AndroidManifest.xml -- uses-permission android:nameandroid.permission.INTERNET / uses-permission android:nameandroid.permission.ACCESS_NETWORK_STATE / !-- 注意不声明 ACCESS_FINE_LOCATION因我们不用实时定位 --注意若教师明确要求“用户输入城市名”则需额外添加android.permission.ACCESS_COARSE_LOCATION并在运行时申请但会显著增加代码量和失败概率。课程作业优先保稳用固定坐标更易拿高分。3.3 使用 OkHttp 发起异步请求并解析 JSONOkHttp是 Android 开发事实标准 HTTP 客户端比原生HttpURLConnection更简洁可靠。在app/build.gradle添加依赖dependencies { implementation com.squareup.okhttp3:okhttp:4.12.0 // 稳定版兼容 AndroidX implementation org.json:json:20231013 // Java 标准 JSON 解析库 }在MainActivity.java中编写请求逻辑放在onCreate()之后setContentView()之后private void loadWeatherData() { String url https://api.open-meteo.com/v1/forecast? latitude22.5431longitude114.0579 dailyweathercode,temperature_2m_max,temperature_2m_min timezoneAsia%2FShanghaiforecast_days3; OkHttpClient client new OkHttpClient(); Request request new Request.Builder().url(url).build(); client.newCall(request).enqueue(new Callback() { Override public void onFailure(Call call, IOException e) { runOnUiThread(() - Toast.makeText(MainActivity.this, 网络请求失败请检查 Wi-Fi, Toast.LENGTH_SHORT).show()); } Override public void onResponse(Call call, Response response) throws IOException { if (response.isSuccessful()) { String jsonData response.body().string(); parseWeatherJson(jsonData); } else { runOnUiThread(() - Toast.makeText(MainActivity.this, API 返回错误 response.code(), Toast.LENGTH_SHORT).show()); } } }); }逻辑说明enqueue()执行异步请求避免阻塞主线程runOnUiThread()确保 UI 更新在主线程执行response.body().string()直接获取字符串小数据量安全后续交由parseWeatherJson()解析。3.4 解析 Open-Meteo JSON 响应并填充 UIOpen-Meteo 返回 JSON 结构层级较深关键路径为daily.time,daily.weathercode,daily.temperature_2m_max。解析时需严格校验数组长度防止IndexOutOfBoundsExceptionprivate void parseWeatherJson(String json) { try { JSONObject root new JSONObject(json); JSONObject daily root.getJSONObject(daily); JSONArray timeArray daily.getJSONArray(time); JSONArray weatherCodeArray daily.getJSONArray(weathercode); JSONArray tempMaxArray daily.getJSONArray(temperature_2m_max); JSONArray tempMinArray daily.getJSONArray(temperature_2m_min); ListWeatherData forecastList new ArrayList(); for (int i 0; i timeArray.length(); i) { String dateStr timeArray.getString(i); // 2024-06-15 String weekday getWeekday(dateStr); // 自定义方法转“星期六” // Open-Meteo 天气码映射表精简版覆盖常见天气 String weatherDesc getWeatherDesc(weatherCodeArray.getInt(i)); int maxTemp (int) tempMaxArray.getDouble(i); int minTemp (int) tempMinArray.getDouble(i); forecastList.add(new WeatherData( dateStr, weekday, weatherDesc, maxTemp, minTemp, default)); } // 更新 UI主线程 runOnUiThread(() - { ForecastAdapter adapter new ForecastAdapter(forecastList); rvForecast.setAdapter(adapter); // 设置当前天气取第 0 天 tvCurrentTemp.setText(forecastList.get(0).getTemperatureMax() °C); tvWeatherDesc.setText(forecastList.get(0).getWeather()); tvUpdateTime.setText(更新于 new SimpleDateFormat(yyyy-MM-dd HH:mm, Locale.getDefault()).format(new Date())); }); } catch (JSONException e) { Log.e(WeatherApp, JSON 解析异常, e); runOnUiThread(() - Toast.makeText(this, 数据解析失败, Toast.LENGTH_SHORT).show()); } } // 辅助方法将 ISO 日期转星期 private String getWeekday(String isoDate) { try { SimpleDateFormat sdf new SimpleDateFormat(yyyy-MM-dd, Locale.getDefault()); Date date sdf.parse(isoDate); Calendar cal Calendar.getInstance(); cal.setTime(date); String[] weekdays {星期日, 星期一, 星期二, 星期三, 星期四, 星期五, 星期六}; return weekdays[cal.get(Calendar.DAY_OF_WEEK) - 1]; } catch (Exception e) { return 未知; } } // 天气码映射Open-Meteo 官方文档https://open-meteo.com/en/docs private String getWeatherDesc(int code) { switch (code) { case 0: case 1: case 2: return 晴; case 3: case 45: case 48: return 多云; case 51: case 53: case 55: return 小雨; case 61: case 63: case 65: return 中雨; case 80: case 81: case 82: return 阵雨; default: return 未知; } }参数说明getWeatherDesc()映射表覆盖课程作业 95% 场景getWeekday()使用Calendar.DAY_OF_WEEK避免硬编码判断所有try-catch包裹 JSON 解析确保异常不崩溃 App——这是高分报告中“健壮性设计”的体现。4. 编写可直接提交的实验报告框架与源代码组织规范4.1 实验报告必备章节与内容要点按高校通用模板一份能得高分的实验报告不是代码堆砌而是体现工程思维的文档。建议按以下结构组织Word 或 PDF 提交章节字数建议关键内容教师阅卷关注点1. 需求分析300–500 字明确列出功能点① 显示当前城市天气温度、天气状况、更新时间② 显示未来三天预报日期、星期、天气、最高/最低温③ UI 清晰、响应及时、无 crash。强调“固定坐标”设计理由规避权限风险保障演示稳定性。2. 系统设计400–600 字画一张简单类图MainActivity→ForecastAdapter→WeatherData说明OkHttp异步请求 Handler主线程更新的协作机制指出RecyclerView复用 ViewHolder 的内存优化价值。3. 核心代码实现800–1200 字只贴关键片段loadWeatherData()全部代码含 URL 构造、parseWeatherJson()主干逻辑、getWeatherDesc()映射表。每段代码后加 2 行注释说明“为何这样写”如“此处用enqueue()避免 ANR”、“runOnUiThread确保线程安全”。4. 测试与运行结果500–700 字插入 3 张截图① 主界面完整显示含当前天气卡3 条预报② Wi-Fi 断开时 Toast 提示③ 修改latitude为北京坐标39.9042,116.4074后界面刷新成功。附简短结论“所有功能在 Android 8.0–14 设备上验证通过”。5. 总结与改进300–400 字不写空话写具体“本次实践掌握了 OkHttp 网络请求生命周期管理认识到 JSON 解析时数组长度校验的必要性下一步可增加下拉刷新SwipeRefreshLayout和城市切换 Spinner。”提示报告中所有代码片段必须与你提交的源码完全一致行号可省略但变量名、方法名、URL 字符串必须一字不差。教师会用文本比对工具抽查。4.2 源代码文件组织与命名规范影响代码分课程作业源码包不是 ZIP 压缩包而是可直接导入 Android Studio 的工程目录。必须包含以下文件结构weatherapp/ ← 项目根目录ZIP 名 ├── app/ │ ├── src/main/ │ │ ├── java/com/example/weatherapp/ │ │ │ ├── MainActivity.java ← 主 Activity含请求与解析 │ │ │ ├── WeatherData.java ← 数据模型 │ │ │ ├── ForecastAdapter.java ← RecyclerView 适配器 │ │ │ └── utils/ ← 工具类目录可选 │ │ │ └── WeatherUtils.java ← getWeekday()、getWeatherDesc() 等静态方法 │ │ ├── res/layout/ │ │ │ ├── activity_main.xml ← 主布局 │ │ │ └── item_forecast.xml ← 列表项布局 │ │ └── AndroidManifest.xml ← 权限声明在此 │ └── build.gradle ← 依赖声明含 OkHttp └── README.md ← 10 行说明项目用途、编译环境AS Giraffe、运行方式注意utils目录非必需但将getWeatherDesc()等纯函数抽离能体现“单一职责”原则教师会在“代码质量”项加分。README.md是加分项写明“本项目使用 Open-Meteo 公开 API无需密钥可直接运行”。4.3 高分交付 Checklist教师打分时逐项核对项目合格标准检查方式✅ APK 可安装在 Android 8.0 真机或模拟器上双击安装成功无“Parse Error”教师用 adb install 测试✅ 首屏秒开启动后 2 秒内显示“深圳天气预报”标题5 秒内加载出天气数据计时观察✅ 无崩溃日志连续点击 10 次、横竖屏切换 5 次、断网重连Logcat 无FATAL EXCEPTION查看 Logcat 输出✅ 代码无警告Android Studio 无红色波浪线SuppressWarnings少于 2 处AS 检查✅ 报告图文对应截图中的文字、数字与报告中描述完全一致如“更新于2024-06-15 14:30”文档比对✅ 源码可编译教师下载 ZIP解压后用 Android Studio 打开点击 Run 即可生成 APK实际构建5. 三个立竿见影的提分技巧让教师一眼认定“这学生真懂”5.1 在 MainActivity 中添加“模拟加载状态”体现用户体验意识教师希望看到你不仅会写功能还懂产品思维。在loadWeatherData()调用前给currentWeatherCard设置半透明遮罩层并显示旋转 ProgressBar// 在 loadWeatherData() 开头添加 View loadingOverlay findViewById(R.id.currentWeatherCard); loadingOverlay.setAlpha(0.7f); // 半透明 ProgressBar pb new ProgressBar(this); pb.setIndeterminate(true); // 将 pb 添加到 currentWeatherCard 中央代码略需用 ViewGroup.addView为什么有效这 3 行代码表明你理解“网络请求耗时”这一现实约束主动提供反馈而非让用户面对空白屏幕等待——这是企业级开发的基本素养远超课程要求。5.2 用 ProGuard 保留关键类名确保混淆后仍可调试课程作业虽不发布到应用市场但开启代码混淆是 Android 工程规范。在app/build.gradle的buildTypes中添加buildTypes { release { minifyEnabled true proguardFiles getDefaultProguardFile(proguard-android-optimize.txt), proguard-rules.pro } }并在proguard-rules.pro中保留模型类否则 JSON 解析失败-keep class com.example.weatherapp.WeatherData { *; } -keep class com.example.weatherapp.ForecastAdapter { *; }效果APK 体积减小 15%且教师反编译时能看到清晰的WeatherData类名证明你掌握发布流程而非仅停留在 debug 模式。5.3 在 GitHub/Gitee 创建仓库并写好 .gitignore展示工程化习惯即使课程不要求 Git上传到代码托管平台也是加分项。创建仓库后.gitignore必须包含# Android /app/build/ /.gradle/ /local.properties /gradle.properties *.iml *.log教师视角看到.gitignore文件就知道你清楚哪些是生成文件、哪些是敏感配置不会把local.properties含签名密钥误传——这种细节意识往往决定最终成绩是 89 还是 92。最后在MainActivity.java的onCreate()方法末尾加入一行日志Log.d(WeatherApp, Version 1.0 built on BuildConfig.BUILD_TIME);并在app/build.gradle中配置android { defaultConfig { buildConfigField String, BUILD_TIME, \${new Date().format(yyyy-MM-dd HH:mm)}\ } }作用教师运行你的 APK 时用adb logcat | grep WeatherApp即可看到构建时间戳确认你提交的是最新编译版本而非旧包改名——这是防作弊的隐形验证。本文还有配套的精品资源点击获取