学习进度条

今日所花时间:一小时
今日代码量:100行
博客量:一篇
了解到的知识点: 深入学习androidStudio Android客户端如何与SpringBoot后端进行数据交互 Retrofit RecyclerView WebView

一、项目概述

本次学习实现了基于Android客户端和SpringBoot后端的政策模糊查询系统,主要功能包括:

  • 通过关键字进行政策模糊查询
  • 展示政策列表
  • 查看政策详细信息

二、技术架构

1. 后端技术栈

  • SpringBoot:快速构建RESTful API
  • JPA/Hibernate:ORM框架处理数据库操作
  • MySQL:数据存储
  • MyBatis:SQL映射框架

2. 客户端技术栈

  • Android Studio:开发环境
  • Retrofit:HTTP客户端,用于与后端API交互
  • RecyclerView:高效展示列表数据
  • WebView:展示政策全文HTML内容

三、学习过程中的问题与解决方案

1. 跨平台通信问题

问题:Android客户端如何与SpringBoot后端进行数据交互
解决方案

  • 使用Retrofit库处理HTTP请求
  • 定义统一的API接口规范
  • 使用Gson进行JSON序列化和反序列化
  • 确保手机和开发电脑在同一局域网下测试

2. 数据格式不一致问题

问题:后端返回的JSON数据与Android实体类不匹配
解决方案

  • 创建与后端完全对应的实体类
  • 使用Gson的setLenient()方法处理宽松的JSON解析
  • 确保字段名称和类型完全一致

3. 网络请求超时问题

问题:移动网络不稳定导致请求超时
解决方案

  • 配置OkHttpClient设置合理的超时时间
  • 添加重试机制
  • 提供友好的错误提示

4. 大文本展示问题

问题:政策全文可能包含复杂格式,TextView无法良好展示
解决方案

  • 使用WebView加载HTML内容
  • 后端存储政策内容为HTML格式
  • 使用loadDataWithBaseURL方法确保编码正确

四、涉及的核心知识点

1. 后端开发

  • RESTful API设计:使用SpringBoot创建清晰的API端点
  • 数据库操作:JPA与MyBatis结合使用
  • 事务管理@Transactional注解的使用
  • 跨域处理:虽然未显式配置,但需要了解CORS机制

2. Android开发

  • 网络请求:Retrofit+OkHttp组合
  • 异步处理:Callback机制处理网络响应
  • 列表展示:RecyclerView及其适配器模式
  • 页面跳转:Intent传递数据
  • UI设计:XML布局与动态内容结合

3. 前后端交互

  • JSON数据处理:Gson库的使用
  • HTTP状态码处理:正确解析200、404、500等状态
  • 错误处理:网络异常和业务异常的区别处理

五、扩展学习方向

  1. 安全性增强

    • 添加HTTPS支持
    • 实现JWT认证
    • 参数校验和过滤
  2. 性能优化

    • 后端添加缓存机制(Redis)
    • Android端实现本地缓存
    • 图片和PDF文件的懒加载
  3. 功能扩展

    • 政策分类查询
    • 收藏和历史记录功能
    • 政策关联性分析
    • 用户反馈系统
  4. 架构优化

    • 引入MVVM架构
    • 使用Dagger/Hilt依赖注入
    • 实现模块化开发

六、心得体会

通过这个项目,我深刻理解了移动端与后端分离架构的优势和实现方式。主要收获包括:

  1. 掌握了Retrofit在Android中的实际应用,理解了如何设计良好的API接口
  2. 学会了处理JSON数据在不同平台间的转换和映射
  3. 体验了完整的开发流程,从数据库设计到前端展示
  4. 认识到错误处理和日志记录的重要性
  5. 了解了WebView在展示复杂内容时的优势

相关练习的代码:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="10dp"
    android:background="@color/cardview_light_background"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/tv_1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:ellipsize="end"
        android:maxEms="2"
        android:maxLines="1"
        android:text="@string/hyn"
        android:textColor="#00838F"
        android:textSize="18sp"
        android:gravity="center"/>

<!--    <TextView-->
<!--        android:id="@+id/tv_2"-->
<!--        android:layout_width="100dp"-->
<!--        android:layout_height="wrap_content"-->
<!--        android:text="Hello World!"-->
<!--        android:textColor="#d21015"-->
<!--        android:textSize="20sp"-->
<!--        android:maxEms="10"-->
<!--        android:maxLines="2"-->
<!--        android:ellipsize="end"-->
<!--        />-->
    <EditText
        android:id="@+id/et_1"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:textSize="16sp"
        android:textColor="@android:color/black"
        android:hint="用户名"
        android:maxLines="1"
        android:padding="5dp"
        android:layout_marginTop="10dp"
        />
    <EditText
        android:id="@+id/et_2"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:textSize="16sp"
        android:textColor="@android:color/black"
        android:hint="密码"
        android:maxLines="1"
        android:padding="5dp"
        android:layout_marginTop="5dp"
        android:inputType="textPassword"
        android:background="@drawable/bg_username"
        />
    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:layout_marginTop="20dp"

        >
    <Button
        android:id="@+id/btn_login"
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="wrap_content"
        android:text="登录"
        android:layout_gravity="center"
        android:background="@drawable/btn_left"
        />
        <Button
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="wrap_content"
            android:text="注册"
            android:layout_marginLeft="2dp"
            android:background="@drawable/btn_right"
            />
    </LinearLayout>

</LinearLayout>
package com.example.demo1;

import android.content.Intent;
import android.os.Bundle;
import android.view.Gravity;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import com.example.demo1.util.ToastUtil;

import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;

public class MainActivity extends AppCompatActivity {
    // 声明控件
    private Button mBtnLogin;
    private EditText mEtUser;
    private EditText mEtPassword;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        EdgeToEdge.enable(this);
        // 修正拼写错误
        setContentView(R.layout.activity_main);
        setContentView(R.layout.activity_main);
        // 找到控件
        mBtnLogin = findViewById(R.id.btn_login);
        mEtUser = findViewById(R.id.et_1);
        mEtPassword = findViewById(R.id.et_2);

        // 匹配对应的用户名和密码才能进行跳转操作
        mBtnLogin.setOnClickListener(this::onClick);

        ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
            Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
            v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
            return insets;
        });
    }

    private void onClick(View v) {
        // 需要获取输入的用户名和密码
        String username = mEtUser.getText().toString().trim();
        String password = mEtPassword.getText().toString().trim();

        // 检查输入是否为空
        if (username.isEmpty() || password.isEmpty()) {
            ToastUtil.showMsg(MainActivity.this, "用户名和密码不能为空,请输入!");
            return;
        }

        // 弹出的内容设置
        String ok = "登录成功";
        String fail = "密码或者用户名有误,请重新登录";

        // 假设正确的账号和密码分别是 hyn 123456
        if (username.equals("hyn") && password.equals("123456")) {
            // 登录成功,进行跳转
            ToastUtil.showMsg(MainActivity.this, ok);
            Intent intent = new Intent(MainActivity.this, SlideActivity.class);
            startActivity(intent);
        } else {
            // 登录失败,弹出提示
            ToastUtil.showMsg(MainActivity.this, fail);
        }
    }
}

未来可以在此基础上继续深入学习Android的高级特性,如Jetpack组件、Kotlin协程等,以及后端的微服务架构、分布式系统等知识,构建更加健壮和高效的移动应用系统。

posted @ 2025-03-25 19:36  haoyinuo  阅读(22)  评论(0)    收藏  举报