
简介这是一套基于Java语言开发的智慧化养猪APP完整源码工程聚焦智慧农业与畜禽养殖场景围绕猪舍环境实时监测、猪只档案管理等核心功能展开适合农业信息化研发人员、移动物联网学习者以及相关专业毕业设计参考使用。压缩包内共包含179个文件主要构成包括Java业务逻辑代码、XML界面布局与资源配置、PNG图片素材、SO原生链接库以及Gradle构建脚本等各类文件分别对应功能实现、界面呈现、视觉资源与底层依赖整体包体约20.14MB项目目录划分清晰便于按模块检索和学习。目前已有316人学习/下载。资源中附带地图定位相关依赖库及完整工程配置可直接复用定位能力通过研读源码层次和构建配置能够快速掌握Android智慧养殖应用从工程创建到功能落地的完整思路也可作为论文课题或实际项目的二次开发基座显著减少前期搭建成本。1. 智慧化养猪 App从 Gradle 到百度 LBS一份能直接编译的 Java 工程智慧化养猪 App 不是个新鲜概念但真能拿到一份完整 Java 工程源码、打开就能编译的却不多。这份资源就是一个标准的 Android Studio 工程里面带 gradlew、build.gradle、settings.gradle还集成了 BaiduLBS_Android.jar也就是说位置服务模块是现成的。它可以解决两个问题一是给不想从零搭框架的人当项目脚手架二是给做智慧农业、养殖信息化的人提供一套可扩展的地图定位基础。适合 Java 初级到中级开发者也适合刚接手养猪信息化项目、需要快速出 Demo 的从业者。我拆完第一眼的感觉是这工程没花哨封面但文件层级很干净该有的构建骨架都在接下来我们就从工程结构开始一层层说。2. 工程结构与 Gradle 构建从 gradlew 到 APK把项目跑起来拿到任何一个 Android 项目我都习惯先看根目录文件因为这能快速判断工程是 Android Studio 原生的还是从其他地方拷贝过来甚至改了一半的。这份资源里列出的文件虽然看起来简单但每一个都有特定作用搞懂它们你后面构建 APK 时能省掉至少一个小时的踩坑时间。2.1 文件清单哪些是 Gradle 的“骨骼”哪些是业务代码先看根目录下的几个文件。gradlew 和 gradlew.bat 分别是 Linux/macOS 和 Windows 下的 Gradle 包装器脚本作用是在本机没有安装 Gradle 的情况下自动拉取指定版本的 Gradle 来执行构建。gradle-wrapper.jar 就是 Gradle Wrapper 的具体实现它被 gradlew 调用读取 gradle-wrapper.properties 里的版本号然后下载对应的 Gradle 发行版。这两个东西是 Gradle 项目的骨架。build.gradle 出现了两个这是很正常的根目录下的 build.gradle 一般做全局配置比如插件版本、仓库地址、全局依赖声明app 模块下的 build.gradle 才真正管我们自己的包名、依赖、签名。settings.gradle 则定义了工程包含哪些模块比如 include :app如果你拿到手发现 settings.gradle 内容为空那项目多半是残缺的。这里还要注意 .gitignore 出现了多个说明工程按模块分开了忽略规则比如根目录忽略 .idea 和 build 目录app 目录下忽略 local.properties 和 build 输出这种分层写法在多人协作时很有用不过你如果只是本地编译.gitignore 不用管太多。至于 BaiduLBS_Android.jar它是百度地图 SDK 的地图与定位核心包躺在 app/libs 或者项目某处。这个 jar 的存在说明项目不是纯空壳至少地图定位、线路规划那一层是集成好的。你把这些文件对照一下就能得出一个结论这是一个标准的 Android 应用工程用 Java 编写Gradle 构建具备百度地图定位能力。别小看这份清单我曾经收过一个标称“智慧农业完整项目”的资源结果里面只有几个 Activity 文件没有 Gradle 配置那种东西根本没法跑而这个工程骨架是完整的。2.2 build.gradle 配置要点依赖、签名、BuildConfig我们打开 app 模块下的 build.gradle核心配置一般长下面这样。注意这份资源具体版本号可能和我写的不同但结构是差不多的// app/build.gradle plugins { id com.android.application } android { compileSdkVersion 30 defaultConfig { applicationId com.example.smartpig minSdkVersion 21 targetSdkVersion 30 versionCode 1 versionName 1.0 // 这里的 BuildConfig 字段会被自动编译成 Java 可访问的常量 buildConfigField boolean, USE_BAIDU_LBS, true } signingConfigs { debug { // 调试签名使用 Android 默认的 debug.keystore } release { // 正式签名需要把 keystore 文件放到工程目录 storeFile file(release.jks) storePassword System.env.STORE_PASSWORD ?: changeit keyAlias smartpig keyPassword System.env.KEY_PASSWORD ?: changeit } } buildTypes { release { signingConfig signingConfigs.release minifyEnabled true proguardFiles getDefaultProguardFile(proguard-android-optimize.txt), proguard-rules.pro } } } dependencies { implementation fileTree(dir: libs, include: [*.jar]) implementation androidx.appcompat:appcompat:1.3.1 implementation com.google.android.material:material:1.4.0 }这里的常用坑是 BuildConfig 字段。你看到buildConfigField的时候要注意它只在defaultConfig或buildTypes中声明而 Java 代码里会引用BuildConfig.USE_BAIDU_LBS比如在if (BuildConfig.USE_BAIDU_LBS)里切换地图模块。如果你把字段删了编译时就会报找不到符号这个问题我在不少资源里都见过。签名配置里我用System.env.STORE_PASSWORD这种方式是因为很多开发者把密码硬编码在 build.gradle 里而这份资源如果原样裸露密码很容易导致签名文件泄露。就算你只是自己做着玩也建议至少把密码改成环境变量。如果资源带的 build.gradle 没有签名配置那 release 包就没法打只能打 debug 包测试这个也要留意。2.3 Gradle 命令行构建与 Android Studio 导入我一般会先用命令行验证工程能否独立构建这样能区分是环境问题还是代码问题。在工程根目录执行# 先给 gradlew 赋执行权限仅 Linux/macOS 需要 chmod x gradlew # 编译 Debug 版 APK ./gradlew assembleDebug # 如果你在 Windows cmd 下用 # gradlew.bat assembleDebug执行后Gradle 会先解析 settings.gradle然后加载根 build.gradle再进入 app 模块的 build.gradle。控制台出现BUILD SUCCESSFUL后APK 输出在app/build/outputs/apk/debug/。如果出现FAILURE: Build failed with an exception就要看具体哪一步最常见的失败是 Gradle 版本与插件版本不兼容出现报错说Minimum supported Gradle version is X。这时候不要瞎猜去看根目录下gradle/wrapper/gradle-wrapper.properties里的distributionUrl写的是什么版本对照插件版本调整。Android Studio 导入也很简单File - Open选中工程根目录IDE 会自动读取 Gradle Wrapper 配置然后等待 Gradle sync 完成。但我建议你同步前先看一眼gradle-wrapper.properties里的仓库地址是不是国内可达的如果指向官方仓库下载速度可能很慢届时可以改成国内镜像。不要小看这一步很多新手卡在“Unable to resolve dependency”上其实就是网络问题。如果你在导入后想做二次开发尽量不要直接在 Android Studio 里改包名改 applicationId 后Google 服务配置或者百度地图 AK 都会失效后面会专门讲。3. 百度地图 LBS 接入BaiduLBS_Android.jar 的作用与配置流程这节说的东西是这份资源里最有价值的模块。BaiduLBS_Android.jar 包含地图显示、定位、地理编码等一系列能力。我们做智慧养猪地图不是噱头而是猪场管理的实际抓手。所以这里把接入流程和原理说透。3.1 为什么智慧养猪要用 LBS猪场定位、存栏监测场景很多人第一反应是“养猪要什么地图”但你去过稍微大点的猪场就知道母猪散养区、育肥区、隔离区之间可能隔着几公里山路饲料车、防疫人员、巡检人员的位置如果不用地图标识管理全靠吼。智慧养猪 App 里的 LBS 模块至少做这么几件事第一猪舍分布图。把每一栋猪舍的经纬度录入系统后地图上一眼就能看出厂区布局点击不同标记可以看当前存栏量、温度、湿度。第二猪只定位。给种猪戴定位耳标后App 能实时显示母猪在哪个圈舍避免发情查漏。第三防疫隔离。一旦某区域发生异常地图上画一个隔离圈直观圈定防控范围比口头通知有效得多。所以这里集成 BaiduLBS_Android.jar不是摆样子。它提供的地图显示与定位能力是以上业务功能的基础。如果你拿到资源后准备改造一定要先搞懂 LBS 的初始化流程否则后面所有地图相关功能都是空的。3.2 AndroidManifest 权限与 Key 申请百度地图 SDK 的使用分两步申请密钥AK和配置 AndroidManifest.xml。密钥申请需要你自己的包名加上调试版或正式版的 SHA1 签名指纹。没有 AK地图加载出来全是网格真机定位也只会返回错误码。Open Manifest 后需要添加的权限大致如下!-- AndroidManifest.xml -- uses-permission android:nameandroid.permission.ACCESS_NETWORK_STATE / uses-permission android:nameandroid.permission.INTERNET / uses-permission android:nameandroid.permission.WRITE_EXTERNAL_STORAGE / uses-permission android:nameandroid.permission.ACCESS_COARSE_LOCATION / uses-permission android:nameandroid.permission.ACCESS_FINE_LOCATION / application android:name.App android:allowBackupfalse !-- AK 配置value 改成你在百度地图控制台申请的密钥 -- meta-data android:namecom.baidu.lbsapi.API_KEY android:value你的AK-这里用占位符 / /application注意WRITE_EXTERNAL_STORAGE在 Android 6 需要运行时动态申请而且如果是 Android 11 及以上即使有这条权限也可能没法直接写外部存储。百度地图 SDK 会先尝试把离线地图写到外部存储如果你测试时发现离线地图不可用先检查是不是存储权限没给全。这里有个细节你申请 AK 时填写的包名必须和 applicationId 完全一致如果你改了 build.gradle 里的 applicationIdAK 就失效。3.3 初始化定位与地图显示代码初始化是整套地图功能的入口。传统写法是在Application.onCreate里调用 SDK 初始化或者在MainActivity里初始化。放在 Application 的好处是整个 App 进程内只需要一次初始化不用每次进入地图页再重复。// App.java public class App extends Application { Override public void onCreate() { super.onCreate(); // SDK 初始化第一个参数是 context第二个是之前申请 AK SDKInitializer.initialize(getApplicationContext(), 你的AK, SDKInitializer.SCENE_TYPE_NORMAL); // 设置允许打开/下载离线地图 SDKInitializer.setScanPath(BaiduMap); } }接着在 MainActivity 里操作地图控件// MainActivity.java public class MainActivity extends AppCompatActivity { private MapView mMapView; private BaiduMap mBaiduMap; private LocationClient mLocationClient; Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 地图控件布局文件中 com.baidu.mapapi.map.MapView / mMapView findViewById(R.id.bmapView); mBaiduMap mMapView.getMap(); mBaiduMap.setMapType(BaiduMap.MAP_TYPE_NORMAL); // 打开实时交通图层做养殖场周边道路判断时会用到 mBaiduMap.setTrafficEnabled(true); // 启动定位 startLocation(); } private void startLocation() { LocationClientOption option new LocationClientOption(); option.setLocationMode(LocationClientOption.LocationMode.HIGHT_ACCURACY); option.setCoorType(bd09ll); option.setScanSpan(3000); // 3秒回调一次位置 mLocationClient new LocationClient(this); mLocationClient.setLocOption(option); mLocationClient.registerLocationListener(new BDLocationListener() { Override public void onReceiveLocation(BDLocation location) { if (location.getLocType() BDLocation.TypeGpsLocation || location.getLocType() BDLocation.TypeNetWorkLocation) { double lat location.getLatitude(); double lng location.getLongitude(); // 把当前位置移到屏幕中央 MapStatusUpdate update MapStatusUpdateFactory .newLatLng(new LatLng(lat, lng)); mBaiduMap.animateMapStatus(update); } } }); mLocationClient.start(); } }逻辑说明LocationClientOption.setCoorType(bd09ll)表示使用百度坐标加密算法如果你拿到的是 GCJ02 坐标比如从高德地图获取的经纬度直接传给百度地图会偏移几百米需要在服务端或客户端做坐标转换。setScanSpan(3000)是定位回调间隔数字越小越耗电智慧养猪的巡检场景下 3 秒一次算合理但如果做静止时的猪舍定位建议改成 10 秒以上。参数说明LocationClientOption.LocationMode.HIGHT_ACCURACY模式会同时使用 GPS、Wi-Fi 和基站定位室内也能返回位置但耗电最大如果你是在开阔猪场使用可以改成BATTERY_SAVING优先网络定位。这些参数在资源里很可能已经调整过但你要根据自己猪场的网络环境微调。4. 核心功能模块把地图参数接到业务数据上工程里光有地图还不够智慧养猪 App 一定要有业务数据。这一章讲怎样利用地图模块做三个典型功能。因为资源原始内容里没有列出具体业务代码所以我按该场景下最常见的实现方案来写你可以对照自己的需求调整。4.1 猪舍标注与圈舍管理猪舍标注是地图业务里最基础的一步。我们把猪舍的编号、栋数、存栏量等数据存到本地数据库然后在地图上添加 Marker。百度的 Marker 支持自定义图标和交互。// PigstyMarkerManager.java public class PigstyMarkerManager { private BaiduMap mBaiduMap; private MapString, Marker mMarkerMap new HashMap(); public void addPigstyMarker(Pigsty info, OnMarkerClickListener listener) { LatLng ll new LatLng(info.getLatitude(), info.getLongitude()); // 生成图标可以根据存栏量切换不同颜色 BitmapDescriptor icon BitmapDescriptorFactory .fromAsset(icon_pigsty_normal.png); MarkerOptions options new MarkerOptions() .position(ll) .icon(icon) .title(info.getName()) .draggable(false) // 确保点击 Marker 能触发回调 .zIndex(10); Marker marker (Marker) mBaiduMap.addOverlay(options); // 用猪舍 ID 关联方便后续点击时拿数据 marker.setExtraInfo(info.getBundle()); marker.setOnMarkerClickListener(listener); mMarkerMap.put(info.getId(), marker); } }逻辑说明这里把 Marker 存进HashMap是为了后续刷新或删除时能精确定位。setExtraInfo可以把猪舍 ID、存栏量这些额外数据放到 Bundle 里点击事件里再取出来不用另外维护数据映射。fromAsset读取 assets 下的图片文件如果你从资源里换图标记得文件名不要用中文。参数说明zIndex(10)控制多个 Marker 叠加的显示顺序值越大越在上层。在实际猪场中如果把隔离舍和正常舍放在同一区域建议给隔离舍一个更高的 zIndex并设置红色图标防止正常舍把隔离舍挡住。4.2 猪只位置回传与轨迹显示给种猪佩戴 GNSS 定位耳标耳标将经纬度通过服务端 API 转发到 App。App 端需要显示当前猪只位置并连接 24 小时内的移动轨迹。// TrackFragment.java public void showTrack(ListLatLng points) { if (points null || points.size() 2) { return; } PolylineOptions polylineOptions new PolylineOptions() .color(0xFF00FF00) // 绿色轨迹 .width(6) .dottedLine(true) .points(points) .visible(true); // 在百度地图上添加轨迹线 mBaiduMap.addOverlay(polylineOptions); // 把视野对准最终点方便查看猪只当前停在哪 LatLng last points.get(points.size() - 1); MapStatusUpdate update MapStatusUpdateFactory.newLatLngZoom(last, 18); mBaiduMap.animateMapStatus(update); }逻辑说明轨迹绘制是个纯展示层工作但要注意时序。后台收到的定位点往往不是严格按时间顺序排列的建议在传给前端前先按定位时间排序否则画出来的线会乱成一团。dottedLine(true)在低版本百度地图客户端上可能渲染失败如果你测试时发现线变成实线可以去掉这行。参数说明width(6)表示线宽单位是像素在平板或电视展示大屏时宽度要放宽到 10 以上才看得清。color(0xFF00FF00)是 ARGB 颜色值前两位是透明度后面是 RGB。绿色适合正常猪只如果要做病猪跟踪可以把这个颜色函数化传入状态参数动态改变颜色这个在防疫场景里很实用。4.3 环境传感器数据的联动展示猪场里温度、湿度传感器数据一般通过 MQTT 协议接收。收到一条数据后除了更新界面上的 TextView最好直接在地图的 Marker 信息窗里显示。这里用百度地图的 InfoWindow 自定义 View// EnvironmentOverlayActivity.java public void showEnvInfo(Pigsty pigsty, EnvData env) { View infoView LayoutInflater.from(this).inflate(R.layout.view_env_info, null); TextView tTemp infoView.findViewById(R.id.tv_temp); TextView tHumidity infoView.findViewById(R.id.tv_humidity); tTemp.setText(String.format(温度%.1f℃, env.getTemp())); tHumidity.setText(String.format(湿度%.1f%%, env.getHumidity())); LatLng ll new LatLng(pigsty.getLatitude(), pigsty.getLongitude()); InfoWindow infoWindow new InfoWindow(infoView, ll, -50); mBaiduMap.showInfoWindow(infoWindow); }逻辑说明InfoWindow 本质上是一个贴在 Marker 上方的 View。-50是垂直偏移量通常用来避免信息窗遮挡 Marker 图标。这里我直接把温度湿度拼成一个自定义 View数据接收更新后调用showInfoWindow重新显示即可。注意 InfoWindow 只能同时显示一个你连续点击两个 Marker 时后一个会把前一个顶掉这是正常现象。参数说明InfoWindow 没有设置背景透明度的 API所以自定义 View 的背景一定要带边框或纯色否则文字会直接堆在地图图层上很难看。还有一点showInfoWindow触发时机要在onPageFinish之后否则地图尚未加载完成信息窗可能无法定位到正确坐标。这个问题我初次接触时折腾了两天后面在代码里加了mBaiduMap.setOnMapLoadedCallback来确保地图加载完再显示。5. 避坑指南从构建失败到定位漂移五个血泪教训每个项目都有坑这份工程也不例外。以下五条是我拆类似资源时反复踩过的你自己操作时可以参考。5.1 现象Gradle sync 一直停在“Building models”然后报错找不到依赖原因这本资源里 build.gradle 依赖的 AndroidX 库版本较新而你本地 Gradle 版本偏低或者 gradle-wrapper.properties 指定的 distributionUrl 下载不完整。解决先跑一次./gradlew assembleDebug看控制台具体报错。如果提示依赖 resolve 失败就把阿里的公共镜像仓库加到 settings.gradle 的pluginManagement里。常见做法是在根 settings.gradle 中加pluginManagement { repositories { maven { url https://maven.aliyun.com/repository/google } maven { url https://maven.aliyun.com/repository/public } gradlePluginPortal() } }5.2 现象地图显示空白只有网格或灰色背景原因十有八九是百度地图 AK 配错了。AK 需要在控制台申请并且包名要和 applicationId 一致。我试过直接在AndroidManifest.xml里塞了一个假 AK地图就白屏真机上还定位失败。解决去百度地图控制台重新申请包名检查 app/build.gradle 中的applicationId指纹检查 debug/release 签名。注意 debug 和 release 的 SHA1 可能不一样如果你打 debug 包要用 debug 签名对应的 AK。5.3 现象定位点在百度地图上偏移几十到几百米原因你可能把其他地图软件出的经纬度直接传给了百度地图 SDK。不同坐标系不通用高德用的是 GCJ-02百度用的是 bd09ll不转换肯定会偏移。解决用百度的坐标转换工具类CoordinateConverter把 GCJ-02 转成 bd09ll。这个 jar 里就有实现不用另找。硬件设备回传的数据如果是 WGS84也要转换否则一旦跨地图叠加必乱。5.4 现象Eclipse 和 Android Studio 下的 jar 重复导致冲突原因这份资源里 BaiduLBS_Android.jar 可能在 libs 目录下而你又为了其他功能添加了com.baidu.mapapi的 Maven 依赖同一套 SDK 存在两个版本。解决优先以 jar 文件为准删除重复的远程依赖。在 app/build.gradle 里用exclude去掉传递依赖或者干脆不引远程库。我经常用implementation fileTree(dir: libs, include: [*.jar])这种方式其它远程库还是以 gradle 依赖为主。5.5 现象Windows 下执行 gradlew.bat 后提示“找不到或无法加载主类”原因JAVA_HOME 没有配置到 JDK 安装目录或者 cmd 里运行的是 32 位 JDK 但系统是 64 位。解决在系统环境变量里设置 JAVA_HOME并且 PATH 里加上%JAVA_HOME%\bin重新打开 cmd。另外建议不要在 PowerShell 里直接跑 gradlew.batPowerShell 执行.bat文件时偶发路径转义问题用cmd /c gradlew.bat assembleDebug更保险。除此之外还有一种比较隐蔽的问题本地 Gradle 缓存中存了旧版 jar导致新工程大量报错。这时删掉~/.gradle/caches下对应模块的缓存再同步往往就好了这招我称之为“后悔药”。6. 进阶让地图模块更实用的几个技术细节基础能跑起来之后想让这份智慧养猪 App 真正变得好用下面三个细节值得改一改。6.1 自定义 Marker 图标与聚合显示猪场猪舍可能多到二三十栋地图放大了还好缩小后 Marker 挤成一团点击体验很差。百度地图提供聚合算法通过MarkerCluster实现。如果 jar 里没有你可以手动把距离较近的 Marker 合并成一个显示“12栋”这样的数字。我自己一般用图标生成器把数字直接画到 Bitmap 上稍微复杂但视觉效果不错。// ClusterBitmap.java public static BitmapDescriptor createClusterBitmap(int count, Context context) { Bitmap base BitmapFactory.decodeResource(context.getResources(), R.drawable.ic_cluster); Bitmap mutable base.copy(Bitmap.Config.ARGB_8888, true); Canvas canvas new Canvas(mutable); Paint paint new Paint(Paint.ANTI_ALIAS_FLAG); paint.setTextSize(24); paint.setColor(Color.WHITE); // 把数字放在圆点中心注意居中计算 canvas.drawText(String.valueOf(count), (mutable.getWidth() - paint.measureText(String.valueOf(count))) / 2, mutable.getHeight() / 2 10, paint); return BitmapDescriptorFactory.fromBitmap(mutable); }6.2 定位频率与省电策略我见过很多人在猪场测试时把setScanSpan设成 500 毫秒结果一个上午手机发烫而且定位并没有更准。养猪场的定位设备一般不会告诉后台自己卡在哪个栏位你要的是长期轨迹不是高速漂移。建议把定位频率降到 510 秒一次并且结合getNetworkType()做判断在 WiFi 覆盖区域可以增加频率在室外 4G/5G 区域降低频率。Android 后台运行时要留意 Doze 模式如果必须每 5 秒上报最好配合前台服务。6.3 数据绑定与调试技巧我一般会在MainApplication里写一个全局的EnvDataCache因为猪舍传感器数据更新频率高模糊数据如果直接刷新 MapView 上的 InfoWindow频繁创建 View 会导致卡顿。改用 HandlerThread 定时批量更新界面秒开。另一个直接有效的调试办法在 release 包里开启日志开关。百度地图 SDK 的日志默认是关闭的你把BuildConfig.USE_BAIDU_LBS开成 true 时也可以让定位回调打印location.getLocation()这样能快速定位到底是没收到坐标还是坐标处理出错。最后说一句我自己的习惯从那以后我每次拿到一份带 Gradle Wrapper 的工程都会先强制走一遍./gradlew assembleDebug确认它在命令行下能过再考虑做功能扩展。这个习惯帮我筛掉了不少“能打开但跑不起来”的假完整项目也少走了许多弯路。希望这篇拆解对你也有用祝这个智慧养猪项目能够顺利落地。本文还有配套的精品资源点击获取