基于 Android 的校园信息管理系统源码

摘要:本文以一个面向高校的 Android 校园信息管理系统(campusInfoApp)为案例,从架构设计、核心模块实现、关键技术选型三个维度展开分析,详细阐述 MVP 分层、角色路由、主题换肤、网络封装等工程化实践,为同类校园移动应用开发提供参考。


一、项目概述

1.1 项目背景

随着高校信息化建设的推进,学生和管理员对校园信息服务的需求日益多元化------新闻公告浏览、选课操作、请假审批、通知发布等功能分散在不同系统中,用户体验割裂。本项目旨在构建一款一站式校园信息管理 Android 应用,将多场景业务整合至统一入口。

1.2 功能矩阵

功能模块 学生端 管理员端
用户体系 注册 / 登录 / 个人信息 / 修改密码 同左
新闻公告 浏览列表 + 查看详情 发布 / 编辑 / 删除
通知公告 浏览列表 + 查看详情 发布 / 管理
请假管理 提交请假申请(含图片附件) 审批 / 查看列表
选课系统 课程查询 / 选课 / 已选课程查看 添加课程 / 管理课程列表
主题换肤 三套皮肤切换(经典/养眼/流行) 同左

1.3 应用截图

图 1 --- 学生首页功能入口

首页采用卡片式布局,以图标+文字的形式展示六大功能入口:校园新闻、查询课表、请假、选课、发班级通知、微信订阅号。底部为自定义 RadioButton 导航栏(首页/学生管理/我的),管理员登录后自动显示"学生管理"Tab。

图 2 --- 注册页面

注册页面支持头像上传(通过 PictureSelector 选择相机或相册)、用户名/昵称/性别/手机号/专业/密码等字段录入,表单校验在客户端完成。

图 3 --- 课表查询页面

课表查询以班级为单位展示(软工1班~4班),点击进入对应班级的课程详情,数据来源于本地 SQLite 预置 + 远程服务端同步。


二、技术栈与依赖

2.1 基础配置

配置项
Application ID com.mmsx.campush
compileSdkVersion 30
targetSdkVersion 29
minSdkVersion 21(覆盖 Android 5.0+)
源文件规模 58 个 Java 文件 + 32 个布局 XML

2.2 核心依赖

groovy 复制代码
// build.gradle 核心依赖
implementation 'com.squareup.okhttp3:okhttp:4.4.0'           // HTTP 客户端
implementation 'com.google.code.gson:gson:2.8.6'             // JSON 序列化
implementation 'com.github.bumptech.glide:glide:4.11.0'      // 图片加载
implementation 'jp.wasabeef:glide-transformations:3.3.0'    // 图片变换(圆角等)
implementation 'com.github.LuckSiege.PictureSelector:picture_library:v2.6.0' // 图片选择器
implementation 'skin.support:skin-support:4.0.5'              // 换肤框架
implementation 'androidx.recyclerview:recyclerview:1.1.0'    // 列表组件

说明build.gradle 中声明了 Retrofit 和 RxJava 依赖,但实际代码中网络层采用 OkHttp 原生封装Okhttp.java 单例工具类),未使用 Retrofit/RxJava 组合。这属于开发过程中的技术决策调整------对于接口数量有限的中型应用,直接使用 OkHttp 足够简洁高效。


三、架构设计

3.1 整体架构

项目采用经典的 Activity + Fragment 主从结构,辅以工具层和数据层的分层组织:

复制代码
┌─────────────────────────────────────────────┐
│                  UI 层                       │
│  Activity (容器)  →  Fragment (内容页)       │
│  BaseActivity     →  具体业务 Activity        │
├─────────────────────────────────────────────┤
│                  适配器层                     │
│  NewsAdapter / LeaveAdapter / SelectionAdapter ...
├─────────────────────────────────────────────┤
│                  工具层                       │
│  Okhttp (网络) / SPUtils (持久化)            │
│  GlideEngine (图片) / JsonUtils (解析)       │
├─────────────────────────────────────────────┤
│                  数据层                       │
│  MySqliteOpenHelper (SQLite)                 │
│  Bean (数据实体)                             │
└─────────────────────────────────────────────┘

3.2 应用启动流程

应用启动时经历以下关键链路:

复制代码
Application.onCreate()
  └─ SkinCompatManager 初始化换肤框架
      ↓
OpenActivity (欢迎页)
  ├─ CountDownTimer 5秒倒计时
  ├─ 检查 SPUtils.AUTO_LOGIN 是否启用
  │   ├─ 是 → Okhttp.byAccount() 验证有效性 → MainActivity
  │   └─ 否 → LoginActivity
  ↓
LoginActivity
  ├─ 验证码生成(随机4位字母数字)
  ├─ 记住密码 / 自动登录(SPUtils 持久化)
  └─ Okhttp.byAccount() 远程验证 → 写入用户角色 → MainActivity
      ↓
MainActivity (主框架)
  ├─ 读取 SPUtils.USER_TYPE 判断角色
  ├─ 学生 → [StudentHomeFragment, UserFragment]
  └─ 管理员 → [AdminHomeFragment, UserManageFragment, UserFragment]

3.3 角色路由机制

这是本项目的核心设计之一。MainActivity 通过 SharedPreferences 中存储的 USER_TYPE 字段决定加载哪套 Fragment 组合:

java 复制代码
// MainActivity.java - 角色判断逻辑
userType = ConverterUtils.toInt(SPUtils.get(myActivity, SPUtils.USER_TYPE, ""));

// 管理员隐藏"学生管理"Tab(学生不显示)
rbManege.setVisibility(userType == UserTypeEnum.User.getCode() ? View.GONE : View.VISIBLE);

// "我的"Tab 根据角色映射到不同索引
switchFragment(userType == UserTypeEnum.User.getCode() ? 1 : 2);

UserTypeEnum 定义了三种角色类型:

枚举值 含义 导航 Tab 数量
User (0) 普通学生 2 个(首页 + 我的)
Admin (1) 管理员 3 个(首页 + 学生管理 + 我的)
Dean (2) 教学院长 3 个(同管理员)

Fragment 采用懒加载 + show/hide 模式,避免重复创建:

java 复制代码
private void switchFragment(int fragmentIndex) {
    FragmentTransaction transaction = getFragmentManager().beginTransaction();
    if (fragments[fragmentIndex] == null) {
        // 按角色创建对应 Fragment 实例
        fragments[fragmentIndex] = userType == UserTypeEnum.User.getCode()
            ? new StudentHomeFragment() / new UserFragment()
            : new AdminHomeFragment() / new UserManageFragment() / new UserFragment();
        transaction.add(R.id.ll_main_content, fragments[fragmentIndex]);
    }
    for (int i = 0; i < fragments.length; i++) {
        if (fragmentIndex != i && fragments[i] != null)
            transaction.hide(fragments[i]);  // 隐藏其他 Fragment
    }
    transaction.show(fragments[fragmentIndex]);
    transaction.commit();
}

四、核心模块技术实现

4.1 网络层封装:OkHttp 工具类

项目将 OkHttp 封装为单例工具类 Okhttp.java,统一管理所有 HTTP 交互:

java 复制代码
public class Okhttp {
    private String http = "http://192.168.3.6:8080/camplus/"; // 服务端基础地址
    private static Okhttp netokhttp;
    public final OkHttpClient client;

    private Okhttp() {
        client = new OkHttpClient.Builder()
            .readTimeout(2000, TimeUnit.MILLISECONDS)   // 读超时 2s
            .connectTimeout(3000, TimeUnit.MILLISECONDS) // 连接超时 3s
            .build();
    }

    // 单例获取
    public static Okhttp postNetokhttp() { ... }
}

提供五种标准 REST 操作方法:

方法 HTTP 动词 用途
postJson(url, json, callback) POST 新增数据(JSON Body)
putJson(url, json, callback) PUT 更新数据
getJson(url, callback) GET 查询列表
deleteJson(url, id, callback) DELETE 按 ID 删除
uploadFile(path, callback) POST (Multipart) 图片文件上传
byAccount(account, callback) GET 按账号查询用户

所有请求均采用异步回调模式 (enqueue(callback)),在 onResponse 回调中通过 JsonUtils 将响应字符串反序列化为对应的 Bean 对象:

java 复制代码
// 典型的调用模式
Okhttp.postNetokhttp().byAccount(account, new Callback() {
    @Override public void onResponse(Call call, Response response) throws IOException {
        String res = response.body().string();
        UserResult result = (UserResult) JsonUtils.fromJson(res, UserResult.class);
        if (result != null && result.getCode() == 0 && result.getData() != null) {
            // UI 操作需切回主线程
            runOnUiThread(() -> { ... });
        }
    }
});

4.2 本地数据库:SQLite 持久化

通过 MySqliteOpenHelper 管理 6 张数据表:

sql 复制代码
-- 用户表
CREATE TABLE user(id INTEGER PRIMARY KEY, account, password, name,
                  sex, phone, room, photo, userType);

-- 请假记录表
CREATE TABLE leave(id INTEGER PRIMARY KEY, userId, note, date, statue, path);

-- 新闻表(含已读/未读标记)
CREATE TABLE news(id INTEGER PRIMARY KEY, title, content, date, path, new, read);

-- 通知表
CREATE TABLE notice(id INTEGER PRIMARY KEY, title, content, date);

-- 管理员课程表
CREATE TABLE adminCourse(id INTEGER PRIMARY KEY, number, name, credits, type);

-- 学生已选课程表
CREATE TABLE studentCourse(id INTEGER PRIMARY KEY, userId, number, name, credits, type);

数据库初始化时预置了:

  • 两个默认管理员账号(admin/123,教学院长/123)
  • 3 条示例校园新闻(黄冈师范学院相关内容)
  • 2 条班级通知
  • 6 门示例课程(大学语文、大学美术、中国近代史等)

静态变量 mUser 作为全局当前用户缓存,登录成功后赋值,各 Activity/Fragment 直接读取。

4.3 主题换肤机制

基于 Android-SkinSupport 开源框架实现运行时换肤,分为三步:

第一步:Application 初始化

java 复制代码
// MyApplication.java
SkinCompatManager.withoutActivity(this)
    .addInflater(new SkinAppCompatViewInflater())      // 基础控件拦截
    .addInflater(new SkinMaterialViewInflater())         // Material Design 控件拦截
    .setSkinStatusBarColorEnable(false)                 // 关闭状态栏换肤
    .setSkinWindowBackgroundEnable(false)               // 关闭 WindowBackground 换肤
    .loadSkin();

第二步:主题选择与保存

java 复制代码
// ThemeActivity.java - Spinner 选择主题
ArrayList<String> list = new ArrayList<>();
list.add("经典主题");  // index 0
list.add("养眼主题");  // index 1
list.add("流行主题");  // index 2

spinner.setOnItemSelectedListener(new OnItemSelectedListener() {
    @Override
    public void onItemSelected(...) {
        selectedType = position;
        SPUtils.put(activity, SPUtils.STUDENT_THEME, selectedType);  // 持久化选择
        setTheme();  // 应用主题
    }
});

第三步:资源映射

三套主题通过不同的 drawable 资源实现视觉差异(如按钮背景 btn_border_fill / btn_border_fill_1 / btn_border_fill_2),换肤框架根据当前选中索引动态加载对应资源。这种方式无需重启 Activity 即可生效。

4.4 图片处理体系

项目构建了一套完整的图片处理流水线:

复制代码
PictureSelector (选择)
    ↓
GlideEngine (加载引擎实现 PictureSelector 的 ImageEngine 接口)
    ├── loadImage()          → 普通/网络图片加载
    ├── loadFolderImage()    → 相册目录缩略图(圆角 R=8dp)
    ├── loadGridImage()      → 网格图片(200x200 centerCrop)
    ├── loadAsGifImage()     → GIF 动图支持
    └── 长图智能识别         → MediaUtils.isLongImg() 判断
                                ├─ 长图 → SubsamplingScaleImageView(支持缩放/双击)
                                └─ 普通图 → ImageView
    ↓
Okhttp.uploadFile() (上传至服务端)
    → MultipartBody FORM 表单上传

关键设计点:

  • 长图自适应 :通过判断宽高比自动切换到 SubsamplingScaleImageView,支持双击缩放和手势拖拽,避免 OOM
  • 圆角缩略图 :相册目录页使用 RoundedBitmapDrawableFactory 设置 8dp 圆角
  • 头像上传 :请假申请时可附加图片证据,通过 MultipartBody 上传至服务端 /file/upload 接口

4.5 数据持久化:SPUtils 工具类

基于 SharedPreferences 封装的通用键值存储工具,管理以下持久化项:

Key 类型 用途
is_first Boolean 是否首次启动
user_type Integer 用户角色(0学生/1管理员/2院长)
user_id String 当前登录账号
last_name String 上次输入的用户名(记住密码)
last_psw String 上次输入的密码
auto_login Boolean 自动登录开关
remember_password Boolean 记住密码开关
student_theme Integer 当前主题索引

内部通过反射调用 apply() 方法实现异步提交,并做了兼容性降级(apply 不可用时回退到 commit)。


五、UI/UX 设计亮点

5.1 自定义导航栏

底部导航未使用 BottomNavigationView,而是采用 RadioGroup + RadioButton 自定义方案:

  • 每个 RadioButton 通过 setCompoundDrawables() 设置图标(68x68 dp)
  • 使用 Selector 资源实现选中/未选中状态切换(颜色+图标变化)
  • 根据角色动态控制 rbManege(学生管理)可见性

这种方案的灵活性在于可以完全控制图标大小、间距和样式,适合需要高度定制导航栏的场景。

5.2 欢迎页倒计时

OpenActivity 实现 5 秒倒计时自动跳转,同时支持点击"跳过"立即进入:

java 复制代码
CountDownTimer timer = new CountDownTimer(5000, 1000) {
    public void onTick(long millisUntilFinished) {
        in.setText(millisUntilFinished / 1000 + "秒");
    }
    public void onFinish() {
        finishView();  // 时间到自动跳转
    }
};

跳转前会检查自动登录状态:若之前勾选了自动登录且本地存有 userId,则静默验证并直接进入主页;否则进入登录页。

5.3 双击退出

MainActivity 重写 onKeyDown,监听返回键实现双击退出(间隔 < 2 秒):

java 复制代码
public void exit() {
    if (System.currentTimeMillis() - time > 2000) {
        time = System.currentTimeMillis();
        Toast.makeText(myActivity, "再点击一次退出应用程序", Toast.LENGTH_LONG).show();
    } else {
        finish();
    }
}

5.4 登录安全增强

  • 图形验证码 :每次进入 LoginActivityonStart)随机生成 4 位字母数字验证码,纯客户端校验
  • 密码本地比对 :先远程拉取用户信息,再在客户端做密码 equalsIgnoreCase 比较
  • 记住密码:通过 SPUtils 持久化上次登录凭据,复用 CheckBox 状态

六、项目结构与代码组织

6.1 包结构

复制代码
com.example.campus/
├── MyApplication.java                    # Application 入口(换肤初始化)
├── bean/                                 # 数据实体
│   ├── User / News / Leave / CourseSelection / StudentCourse
│   └── *Result                           # 统一响应包装(code + data)
├── enums/                                # 枚举定义
│   ├── UserTypeEnum                      # 用户角色
│   ├── ComeTypeEnum                      # 请假去向类型
│   └── RepairsStatusEnum                 # 报修状态
├── util/                                 # 工具类
│   ├── Okhttp.java                       # 网络请求封装(单例)
│   ├── SPUtils.java                      # SharedPreferences 封装
│   ├── MySqliteOpenHelper.java           # 数据库管理
│   ├── JsonUtils.java                    # JSON 解析工具
│   ├── ConverterUtils.java               # 类型转换工具
│   ├── GlideEngine.java                  # Glide 图片引擎
│   └── KeyBoardUtil.java                 # 键盘控制工具
├── widget/                               # 自定义控件
│   └── ActionBar.java                    # 统一标题栏组件
├── adapter/                              # RecyclerView 适配器
│   ├── NewsAdapter / NoticeAdapter
│   ├── LeaveAdapter / CourseSelectionAdapter
│   └── UserAdapter
└── ui/
    ├── activity/                         # Activity 页面(32个)
    │   ├── BaseActivity.java             # 基类
    │   ├── OpenActivity / LoginActivity / RegisterActivity
    │   ├── MainActivity                   # 主框架(Fragment 容器)
    │   ├── ThemeActivity                 # 主题设置
    │   ├── *News*Activity                # 新闻相关(学生浏览 + 管理员管理)
    │   ├── *Notice*Activity              # 通知相关
    │   ├── *Leave*Activity               # 请假相关
    │   ├── *Selection*Activity           # 选课相关
    │   └── PersonActivity / PasswordActivity
    └── fragment/                         # Fragment 内容页
        ├── StudentHomeFragment           # 学生首页
        ├── AdminHomeFragment             # 管理员首页
        ├── UserFragment                  # 个人中心
        └── UserManageFragment            # 用户管理(管理员)

6.2 BaseActivity 基类

所有 Activity 继承自 BaseActivity,统一处理公共逻辑(如换肤兼容、ActionBar 绑定等),保证各页面行为一致性。


七、总结与展望

7.1 技术亮点总结

维度 实践 效果
架构 Activity + Fragment 主从结构 + 角色路由 一套代码适配学生/管理员双角色
网络 OkHttp 单例封装 + 异步回调 统一接口风格,超时可控
存储 SQLite 本地持久化 + SharedPreferences 配置存储 离线可用 + 用户偏好保留
换肤 Android-SkinSupport 运行时换肤 无需重启即时生效
图片 PictureSelector + Glide + 长图智能识别 全链路图片处理能力
体验 欢迎倒计时 / 双击退出 / 记住密码 / 自动登录 符合移动端交互习惯

7.2 可优化方向

  1. 网络层升级:可引入 Retrofit + RxJava(依赖已声明)实现更优雅的链式调用和线程切换;考虑添加拦截器统一处理 Token、日志、错误码
  2. 架构现代化:迁移至 Jetpack Component(ViewModel + LiveData / Navigation Component),替代手动 Fragment 管理和show/hide 模式
  3. 数据库 ORM:引入 Room 替代原生 SQLiteOpenHelper,获得编译期 SQL 检查、LiveData 观察等能力
  4. 模块化拆分:按功能域(news / notice / course / leave)拆分为独立模块,降低耦合度
  5. 图片缓存策略:结合 Glide 磁盘缓存与服务端 CDN,优化图片加载性能
  6. 安全加固:密码传输加密(HTTPS)、Token 机制替代明文密码比对、服务端验证码替代客户端生成

7.3 适用场景

本项目的技术方案适用于以下类型的中小型 Android 应用开发:

  • 企业/校园内部管理工具
  • 多角色权限的信息展示平台
  • 以列表浏览 + 表单提交为主的应用
  • 需要主题定制能力的 C 端产品

本文基于 campusInfoApp 项目源码撰写,截图来源于应用实际运行效果。

相关推荐
Buke..1 小时前
【APP 逆向】哔哩哔哩 sign 参数逆向(上):Frida 反调试绕过与 unidbg 调用
java·开发语言·爬虫·python·安卓
竹枝溪1 小时前
Tomcat与Servlet全套小白教程
java·servlet·tomcat·cookie·filter·session·listener
YF02112 小时前
如何进入Android工程模式
android
UseLessQQ2 小时前
云计算k8s集群部署
java·kubernetes·云计算
我命由我123452 小时前
人脸识别 - 人脸识别选帧
java·人工智能·python·算法·安全·java-ee·人脸识别
宠友信息2 小时前
IM系统开发技术路线分析,即时通讯源码助力快速搭建聊天应用
java·spring boot·redis·websocket·mysql·uni-app·vue
long3163 小时前
封装(Encapsulation)
java·人工智能·ai·ai编程
yaoxin5211233 小时前
502. Java 反射 - 编写 MessageInterceptor 类
java·开发语言
Kevin Coding3 小时前
JsonConvert:适用于 Android、鸿蒙与 Flutter 的 JSON 转 Model 插件
android·flutter·harmonyos