资讯动态

Android天气预报APP毕设:从源码跑通到答辩亮点的完整指南

发布时间:2026/10/13 22:06:16 来源:尧图企业网站定制
简介面向计算机专业毕业生与安卓开发学习者的天气预报完整项目基于Android Studio构建适用于毕业设计、课程设计或期末大作业。项目曾获98分高分评价源码经严格调试可本地编译运行并附有文档说明。资源共666个文件包括一百多个Java源代码、近两百个XML布局与配置、数十张界面图片、多个JAR依赖库以及Gradle构建脚本和APK安装包压缩包约23.93MB目录结构清晰其中XML覆盖界面布局与资源定义Java源码实现核心业务逻辑图片资源用于视觉展示Gradle与JAR负责依赖管理和构建。已有185人学习。读者可获得可直接运行的源码、项目文档以及第三方库集成配置帮助理解Android网络请求、JSON解析、列表展示和自定义界面开发流程。项目采用分层设计将数据获取与界面更新分离文档还包含项目介绍、环境配置和关键代码解析既能支撑答辩展示也适合后续二次开发或课程设计参考。1. 天气预报APP毕设源码拿到手怎么让它变成你的高分项目很多计算机专业同学拿着Android毕业设计基于AndroidStudio的天气预报APP源码文档说明这种标着高分项目的源码包以为直接打开Android Studio点运行就能交付。现实是光一个Gradle同步就能让新手卡一整晚更别提接口Key失效、AndroidX迁移、明文流量拦截这些后续问题。这个题目本身不难核心就三件事网络请求、JSON解析和界面展示数据用现成的天气接口就能拿到。但正因为简单老师反而更看重你能否讲清原理、能否处理异常。这篇笔记按我带毕设项目的顺序把功能边界、技术选型、跑通步骤、解析缓存和踩坑现场一次讲透让新手能照着复现熟手也能看清哪些参数值得调。2. 先想清楚再打开代码天气预报项目的功能边界与技术选型毕业设计最怕的不是难而是假熟悉。天气预报方向一搜一大把源码可老师看的不是你在哪下载的而是你能否把每个文件存在的理由说清楚。所以打开源码前我建议你花半小时做两件事划功能边界、定技术选型。这两件事决定了后面改代码时会不会反复返工也决定了答辩时能不能讲出设计思路。2.1 天气预报这个题目为什么能拿高分评分点与功能边界一个天气预报APP能拿高分通常不因为查得准而是因为功能链路覆盖了Android课程的考核点。按我参与答辩的印象评分点大致是界面整洁稳定、网络请求做了回调和异常处理、列表正常滑动并复用ViewHolder、无网和空数据状态有兜底、文档里包含架构图和测试记录、演示时一次成功。功能数量反而排在后边数据是公开接口提供的谁都能调出来。因此功能边界最好控制在一条完整闭环启动App、定位到当前城市、展示今天天气和未来多日预报、点击城市搜索切换、下拉刷新、再次启动时读缓存。这六步串起来就是毕业论文需求分析和系统设计两章的全部素材。超出这个闭环的推送、语音播报、桌面小组件是加分项但前提是你自己能把逻辑讲清。源码里如果有你读不懂的额外功能我建议暂时注释掉等核心链路稳定后再一个个加回来。贪多必翻车这是我从几个学生身上总结的血泪经验。2.2 技术选型网络库、JSON 解析、UI 图表怎么搭配技术选型第一原则是答辩时你答得出原理。OkHttp配Gson是最常见的组合OkHttp负责把城市名拼成URL拿到JSON字符串Gson把JSON映射成Java Bean。为什么不选RetrofitRetrofit在注解和适配器上封装太多代码确实少但老师一旦追问Retrofit的原理你要现场把动态代理讲清楚风险高。网络库选OkHttp、解析库选Gson、列表用RecyclerView、下拉刷新用SwipeRefreshLayout这套组合资料最多踩坑答案也最多适合毕业设计。图表是普通项目迈向高分的一个跳跃点。未来三到五天的温度折线图用MPAndroidChart的同学一抓一大把但用Canvas自绘一条温度曲线反而更容易证明你懂自定义View。我的建议是如果源码里已经有图表库沿用并调好样式如果没有时间充裕再插MPAndroidChart不要在最开始阶段引入因为它会让依赖数量和Gradle同步复杂度一起变大。依赖库用途版本策略OkHttp网络请求3.12 或 4.x 均可不必追最新GsonJSON解析2.8.x 稳定版AndroidX RecyclerView列表跟随 compileSdk 自动适配SwipeRefreshLayout下拉刷新注意新旧包名迁移MPAndroidChart温度折线图3.1.0 或新发布版还有一个常见的选型盲区天气图标。如果源码用Glide加载网络图标你要考虑网络失败时图标缺失的问题。如果直接把图标做成drawable资源按天气代码用一条switch语句映射加载快也不会受网络影响。对天气这种低图片依赖场景我倾向用资源映射少一个依赖就少一个坑。2.3 源码阅读路线按包名分层先看哪几个文件拿到源码包后别急着点Run。先看包结构常见的是model或bean、adapter、utils、activity、service规范一点的还有base目录放基类。阅读顺序我一般这样定先开AndroidManifest.xml确认入口Activity和权限接着打开入口Activity看它在onCreate里初始化了哪些控件和对象然后找到布局文件对照屏幕上的ListView或RecyclerView最后沿刷新按钮或onResume找到数据加载方法再跳到网络请求和解析回调。按这个顺序读你基本能回答App启动后发生了什么。建议准备一张纸上或一个Markdown文件把类之间的依赖画出来。例如MainActivity的mAdapter是WeatherAdapter实例WeatherAdapter需要WeatherBean列表WeatherBean由Gson从JSON生成JSON字符串来自WeatherApi。这张依赖图答辩时能画出来比背代码有效得多。读源码时只看主线、忽略分支网络失败、缓存过期这些逻辑先用TODO标记不要逐行读。主线跑通后再看分支这样不会被细节淹没。3. 用 Android Studio 跑通源码导入、Gradle 同步与最小可运行骨架好多同学卡在代码跑不起来这一步其实不是代码问题是导入方式和Gradle配置问题。这一章先把导入流程写清楚再给一套最小可运行骨架。这套骨架不是最终项目但它是验证环境能否可用的最快路径——新项目能跑源码大概率也能跑。3.1 Android Studio 导入源码的完整流程与 Gradle 同步处理正确的导入方式是从Android Studio主界面选File - Open然后定位到包含settings.gradle或settings.gradle.kts和build.gradle的根目录而不是直接选App模块。老版本项目可能只有build.gradle那就选那个文件所在目录。Open之后Android Studio会提示Gradle Sync这个同步会下载Gradle发行版和依赖包耗时取决于网络和版本。不要一看到Unresolved dependency就慌先看Build窗口里具体缺的是哪个库。如果同步卡在gradle发行版下载常见做法是改gradle-wrapper.properties里的distributionUrl到国内镜像地址。另一个常用招是在项目根目录的settings.gradle里配阿里云镜像。下面是一份常见的配置注意仓库顺序很重要pluginManagement { repositories { maven { url https://maven.aliyun.com/repository/public } maven { url https://maven.aliyun.com/repository/google } maven { url https://maven.aliyun.com/repository/gradle-plugin } google() mavenCentral() } } dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.PREFER_SETTINGS) repositories { maven { url https://maven.aliyun.com/repository/public } google() mavenCentral() } }这段逻辑是让Gradle优先从国内镜像拉插件和依赖。如果你的Android Studio版本较旧可能需要在根build.gradle的allprojects里写仓库格式类似。如果镜像连不上现象是依赖解析超时把官方仓库顺序放前面也是一种兜底。这里有个容易忽略的问题Android Studio版本升级后老项目可能触发AndroidX迁移建议。旧代码里大量import com.android.support.*迁移后要全改成androidx.*。如果不想迁移就关闭AndroidX如果迁移就一次性把support包名改完否则会在编译期看到成百个找不到类错误。另一个高频问题是SDK版本不匹配。错误形如compileSdkVersion XX requires XX or higher。打开app/build.gradle把compileSdk、targetSdk、minSdk改成本机已安装的平台版本。在Settings - SDK Manager里勾选对应API即可。注意minSdk不要一下提太高因为依赖库的最低版本要求可能变高你硬要降低反而冲突。常见做法是维持源码默认除非必须改。3.2 最小可运行骨架权限、布局、网络请求与 Toast 验证环境同步好后先用一个最小工程验证网络。如果你拿的旧源码改起来麻烦不如新建一个HelloWeather模块跑通再逐步替换成源码里的功能。骨架分三部分AndroidManifest申请权限、一个布局、一个MainActivity。先看权限配置uses-permission android:nameandroid.permission.INTERNET / uses-permission android:nameandroid.permission.ACCESS_NETWORK_STATE / uses-permission android:nameandroid.permission.ACCESS_COARSE_LOCATION / application android:usesCleartextTraffictrue android:labelWeatherDemo ... /application要注意usesCleartextTraffic放在application节点上作用是允许Android 9及以上版本访问http明文地址。如果天气API是https这个属性可不写但很多免费接口仍然保留http所以demo里先打开它。定位权限后面定位功能时用网络权限是即时必需的。如果你的minSdk在23以上定位权限还需要在代码里动态申请骨架里先不管。布局文件用Button加TextView够用了?xml version1.0 encodingutf-8? LinearLayout android:orientationvertical android:layout_widthmatch_parent android:layout_heightmatch_parent TextView android:idid/tv_weather android:layout_widthmatch_parent android:layout_height0dp android:layout_weight1 android:text点击按钮加载天气/ Button android:idid/btn_load android:layout_widthmatch_parent android:layout_heightwrap_content android:text加载天气/ /LinearLayout主Activity里用OkHttp发一个最简单请求并setText到TextViewpublic class MainActivity extends AppCompatActivity { private TextView tvWeather; private final String API_URL https://restapi.amap.com/v3/weather/weatherInfo?city110101key你的key; Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tvWeather findViewById(R.id.tv_weather); findViewById(R.id.btn_load).setOnClickListener(v - loadWeather()); } private void loadWeather() { new Thread(() - { try { OkHttpClient client new OkHttpClient(); Request request new Request.Builder().url(API_URL).build(); try (Response response client.newCall(request).execute()) { if (response.body() ! null) { String text response.body().string(); runOnUiThread(() - tvWeather.setText(text.substring(0, Math.min(200, text.length())))); } } } catch (IOException e) { runOnUiThread(() - tvWeather.setText(请求失败: e.getMessage())); } }).start(); } }这里API_URL是示例真正做项目时需要替换域名、key和city参数。代码用了子线程执行execute同步调用然后runOnUiThread切回主线程更新UI。如果你看到NetworkOnMainThreadException说明请求跑在主线程了。OkHttp的execute必须放子线程enqueue异步回调虽然本身在子线程更新UI时也要再切一次。很多老源码用AsyncTask现在不推荐但如果继承的源码是AsyncTask先跑通再重构不要一开始就动。这套骨架的价值在于能显示原始JSON说明网络通、依赖没问题如果崩优先查SDK版本、依赖和权限。3.3 必调参数超时时间、刷新间隔、城市名称编码骨架跑通后把参数调整到适合天气预报场景。OkHttp默认超时10秒我一般设连接20秒、读取15秒。城市搜索框输入中文时URL参数要编码否则接口可能返回空。这段配置可以直接抄OkHttpClient client new OkHttpClient.Builder() .connectTimeout(20, TimeUnit.SECONDS) .readTimeout(15, TimeUnit.SECONDS) .writeTimeout(15, TimeUnit.SECONDS) .retryOnConnectionFailure(true) .build(); String encodeCity URLEncoder.encode(cityName, UTF-8); String url https://api.example.com/weather?city encodeCity;connectTimeout是连接TCP的时间上限readTimeout是读取数据时的最大间隔不是总时长retryOnConnectionFailure会让连接不上时自动重试。URL编码很重要北京如果不编码在一些网关上会被拦。调试时打Log确认最终URL。刷新间隔也要控制常见做法是保存上次成功请求的时间戳超过30分钟才允许自动刷新手动下拉刷新不受限避免免费接口被限流。4. 核心功能落地天气接口解析、图标映射与本地缓存骨架只证明环境能跑要让老师认可得把原始JSON变成好看的界面。天气接口返回结构相对固定难点在字段null、多日预报数组嵌套、温度类型是字符串还是数字。这一章就讲解析、图标映射和缓存。4.1 天气接口返回结构用 Gson 解析多日预报常见天气接口会返回一个大JSON对象含实时天气和未来几日预报。字段大致有城市名、当前温度、天气现象、风力风向、空气湿度、发布日期以及一个forecasts数组每个元素代表一天。先用Gson定义Beanpublic class WeatherBean { private String city; private String weather; private String temperature; private String windDirection; private String windPower; private String humidity; private String reportTime; private ListForecast forecasts; public static class Forecast { private String date; private String dayWeather; private String nightWeather; private String dayTemp; private String nightTemp; private String dayWind; // getter/setter 省略 } } public static WeatherBean parseWeather(String json) { Gson gson new Gson(); WeatherBean bean gson.fromJson(json, WeatherBean.class); return bean null ? new WeatherBean() : bean; }Gson容易踩的坑是字段名不一致。接口返回的是tempBean里是temperature不加SerializedName(temp)就拿不到值。另外温度字段建议声明为String不要用int否则接口返回null时Gson会抛异常或填默认0。更稳妥的方式是直接用Android自带JSONObject逐层取兜底默认值JSONObject obj new JSONObject(json); String city obj.optString(city, 未知城市); JSONArray casts obj.optJSONArray(casts); if (casts ! null casts.length() 0) { JSONObject first casts.optJSONObject(0); String dayTemp first.optString(daytemp, --); }optString与getString的区别字段不存在或为null时optString返回默认值而不是抛异常。我改造源码时会把Bean的统一getter清洗一遍让所有文本显示不会有null。4.2 天气代码到图标的映射UI 绑定与资源复用解析完天气现象代码后界面要显示图标。不同天气接口的代码体系不同但映射逻辑一致。常见做法是写一个工具类public class WeatherIconMapper { public static int getIconRes(String weatherCode) { switch (weatherCode) { case 晴: case 100: case 00: return R.drawable.ic_sunny; case 多云: case 101: return R.drawable.ic_cloudy; case 阴: case 102: return R.drawable.ic_overcast; case 阵雨: case 103: case 04: return R.drawable.ic_shower; case 雪: case 140: case 14: return R.drawable.ic_snow; default: return R.drawable.ic_unknown; } } }这段硬编码清晰可读、零依赖。你需要根据源项目实际接口确认代码值如果接口变了只调switch里的判断值。UI层调用时ImageView icon holder.findViewById(R.id.iv_weather); icon.setImageResource(WeatherIconMapper.getIconRes(bean.getWeather()));ic_sunny等是drawable资源名建议使用VectorDrawable尺寸小且不会按像素拉伸。在部分国产机型上如果图标是位图记得按密度切资源否则会锯齿。天气代码可能既有数字也有汉字映射方法入参用String而不是int更安全。4.3 本地缓存与启动定位SharedPreferences 与 LocationManager天气预报短时间内变化不大首屏可以先读缓存再拉新数据。缓存用SharedPreferences足够不必上数据库。我通常存城市名、JSON字符串、保存时间戳三项public void saveWeatherCache(String city, String json) { getSharedPreferences(weather_cache, MODE_PRIVATE) .edit() .putString(city, city) .putString(json, json) .putLong(time, System.currentTimeMillis()) .apply(); } public String readWeatherCache(String city) { SharedPreferences sp getSharedPreferences(weather_cache, MODE_PRIVATE); long lastTime sp.getLong(time, 0); long now System.currentTimeMillis(); if (now - lastTime 30 * 60 * 1000) { // 超过30分钟 return null; } String cachedCity sp.getString(city, ); if (!cachedCity.equals(city)) { return null; } return sp.getString(json, null); }缓存策略是同一城市且30分钟内才使用缓存否则返回null让网络层拉新。apply和commit的区别在于apply异步写入速度快但失败不报告commit同步写入适合必须立刻落盘的场景。日常刷新用apply足够了。定位是很多项目的痛点。我的建议是不要把Geocoder逆编码作为唯一方案模拟器经常解析失败。实际做法是先尝试LocationManager获取经纬度失败就默认北京获取成功后用一个逆地理编码Web接口换成cityId再请求天气。第三方定位SDK集成简单但会增大体积且需要申请Key。如果毕设重点不是地图手动选择城市就够用把定位做成可选增强很多评分标准里并不强制。5. 避坑排查从同步失败到 API 返回空数据的 5 个现场这个项目我前后带过几届学生遇到的坑高度重复。下面按现象、原因、解决三个顺序写五条都是拿到源码后最常碰到的。5.1 现象Android Studio 打不开项目或同步一直卡在 Loading现象是启动后一直转圈或者Gradle Sync卡在下载boundbarBuild窗口报Could not resolve。原因通常是默认仓库源连接超时、依赖版本号不存在、Gradle版本与当前Android Studio插件版本不匹配。解决分三步先复制Build窗口具体报错再在settings.gradle或根build.gradle加阿里云镜像镜像加了还失败就查依赖版本是否存在。如果Android Studio本身打不开先检查JDK版本和安装包完整性不要直接重装。Gradle的发行版也可以手动放到本地~/.gradle/wrapper/dists这样即使镜像慢也能离线同步。5.2 现象Android 9 及以上版本请求 HTTP 明文地址被拦截现象是Logcat打印Cleartext HTTP traffic to xxx not permitted页面一直是加载失败。原因是targetSdkVersion不低于28时系统默认禁止HTTP明文。解决方式接口是HTTP就在application标签加android:usesCleartextTraffictrue接口是HTTPS但个别子域名还是HTTP就配networkSecurityConfig按域名放行。最干净的方案是接口全切HTTPS但这不是学生能决定的。我排查时先看URL是http还是httpshttp的话一行属性就能解决。注意这个属性上线前要评估风险毕设使用没有太大问题。5.3 现象模拟器能联网但请求本机或局域网服务失败现象是模拟器页面空白Logcat报连接超时同样代码换真机却正常。原因是模拟器里宿主机不是127.0.0.1而是10.0.2.2真机访问开发机时又必须用开发机的局域网IP。解决方式是把地址做成可配置用BuildConfig区分debug和releaseString host BuildConfig.DEBUG ? http://10.0.2.2:8080 : https://api.example.com;模拟器用10.0.2.2真机调试时临时改成开发机IP。还有一种情况是免费天气接口动态限流模拟器里多次快速刷新触发了风控表现为超时而非地址错误。5.4 现象JSON 解析偶尔空指针或者界面显示null现象是列表某个item天气现象不显示温度显示null崩溃日志指向Model层getter。原因是接口字段缺失或值为nullGson把Bean字段置空UI层直接调用。解决方法是Bean里的基础类型统一改String解析时用SerializedName保证字段匹配。更稳妥的是在拿到Bean后做一层清洗把所有null换成空串或--private static String safe(String s) { return s null || s.equals(null) ? -- : s; }在adapter显示时每一个文本都调用safe()。这个习惯能干掉绝大多数界面显示null的尴尬。5.5 现象下拉刷新转圈完成后列表内容没变化现象是SwipeRefreshLayout动画停了但RecyclerView还是旧数据。原因有两个请求回调在子线程你直接改了List但没有切回主线程调用notifyDataSetChanged或者刷新后重新new了一个List赋给某个变量但adapter仍引用旧List实例。解决方式明确回调里先用runOnUiThread切回主线程再修改List最后对adapter调notifyDataSetChanged。如果是重新赋值List记得同时调用adapter.setData(newList)。notifyDataSetChanged只是告诉RecyclerView数据变了它不会自动帮你把新List绑定到adapter上。这也是RecyclerView项目中最常见的维护性错误。6. 把 80 分项目做成 90 分答辩亮点与验证技巧代码跑通只是及格真正拉分的是让老师看到你的设计思考。这里三个技巧是我验证过最有效的。6.1 加一张温度趋势折线图成本不高但老师爱看用MPAndroidChart给未来三天或五天加一张折线图视觉复杂度立刻上一个台阶。关键是配置X轴日期格式和Y轴数据范围不要在每一张图里重复初始化把配置封装成一个BaseChartActivity或工具方法。没有时间的话自己写Canvas也够用但如果你在答辩里说我用MPAndroidChart因为它稳定比说我自己画的更稳妥——只要文档里把依赖和绘制步骤写清楚。6.2 文档说明里必须有架构图和时序图很多高分项目代码一般但文档的架构图非常清楚。至少包含一张系统架构图模块关系和一张时序图用户点击刷新按钮到UI更新的消息顺序。用draw.io画就行画完导出图片嵌进文档。再把各模块职责写成表格附上一页遇到的问题与解决方法把第5章的三四个坑放进去这样文档说明就像你真实做过调试而不是只抄了一份项目说明书。6.3 答辩演示脚本2 分钟内讲清我做了什么最好的演示不是罗列功能而是演示一个场景打开App自动定位北京显示今天天气下拉刷新展示未来三日切换城市到上海数据变化断网重启出现缓存数据。这串动作自然把功能、网络、缓存、异常处理全带出来了。脚本控制在2分钟之后等老师提问。重要的一点答辩前一周不要改任何核心代码把接口Key换成可用配额把模拟器网络调好避免现场翻车。这些年我带过的学生里翻车的不是技术不行多半是最后一周换主题、换库、换接口。我的习惯是功能冻结前把缓存和异常处理做完答辩前只调参数不动架构。希望这个思路帮到你至少让你少走我当年走过的弯路。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑