问题背景

作者最近在写安卓大作业,需要实现android studio和后端连接,尝试了一下django的后端,一直连不上,等之后作者探索出来再来写一篇博客,后来换成spring boot的后端,资料确实是更多,在连接过程也遇到了一些小问题,查阅了些资料得到解决,于是做个记录,方便遇到相同问题的读者能够顺利解决。

前后端连接实例

这里直接列举一个简单的前后端连接实例,方便大家学习参考

实例概述

本次实例使用android studio完成app的前端,使用spring boot完成app的后端,前端当中写一个按钮,点击后把”hello”传递给后端,后端接收到”hello”后把”hi”传递回前端,并显示在按钮上,其中使用OkHttp的前后端通信方式。

实例的实现流程

1、环境配置

  • 前端作者是用android studio来制作的,所以直接上官网下载就行;
  • 后端spring boot是基于intellj idea的,可以上官网下载intellj idea
  • 语言这里使用的是java8

2、spring boot后端项目创建

需要注意,intellj idea专业版和社区版在这里应该是会有所不同,作者使用的是专业版(学生认证的,可能需要几天)

intellj idea左上角点击文件->新建->项目,左侧选择Spring Initializr,自己设定项目名称、选择项目位置创建git仓库按需点击,语言这里选择java(Kotlin和Groovy作者都不认识hhh),类型(包管理)选择Maven组名、工件、软件包名称会按照项目名称自动修改,JDKjava语言的版本需要适配,作者这里选的是jdk1.8和java8如果选错了可以创建后在文件->项目结构当中修改,打包这里选择jar(如果有部署到专门的应用服务器的需求,可以选择WAR,这个后期也是可以修改的,这里不赘述)。完成后点击下一步

上面的spring boot选择2版本里面不带SNAPSHOT的最新版,作者这里是2.7.10。随后在依赖项当中搜索Spring Web或者点击Web展开即可看见Sping Web,点击勾选。点击右下角创建即可。

3、spring boot后端项目编写

这里使用spring boot的好处就是啥都不需要额外配置,直接实现功能代码就完事。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//在 项目根目录下 src->main->java->com.example.xx 右键 新建-> java类,命名为MessageController,代码如下
// 注意文件原有代码的第一行的包别给删了 一般格式为 package com.example.xx

import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController // 这个是一个注解,使其可以被主类自动识别和注册,不需要在主类当中调用就可以直接被使用
public class MessageController {

@PostMapping("/message")
public String receiveMessage(@RequestParam String message) {
if ("hello".equalsIgnoreCase(message)) {
return "hi";
} else {
return "unknown message";
}
}
}

4、spring boot后端项目运行

打开后端项目根目录下src/main/java/com.example.xx,在这里,有一个土著java文件,其名称和项目名称有关系,我这里是backendapplication,打开后点击工具栏的运行符号就是一个三角形。

5、android studio前端项目创建

打开android studio后,new project,选择一个empty activity,自己设定项目名称、选择项目位置,语言为javaminimum SDK选择默认是Android 7.0,点击finish即可创建项目

6、android studio前端代码编写

这里主要涉及okhttp的引入,前后端环境的相关配置,okhttp的调用,目标url设置等关键问题

1
2
3
4
5
// 首先在app项目下的build.gradle引入okhttp依赖
dependencies{
...
implementation 'com.squareup.okhttp3:okhttp:4.9.3'
}
1
2
3
4
5
6
7
8
9
10
11
<!-- 其次是在AndroidManifest.xml当中实现前后端环境相关的配置 -->
<manifest ...>

<uses-permission android:name="android.permission.INTERNET" /> <!-- 这里是设置internet权限 -->

<application ...
android:usesCleartextTraffic="true"> <!-- 这里是设置允许明文传输 -->
...
</application>

</manifest>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!-- 这里是实现app/src/main/res/layout/activity_main.xml当中的按钮 -->
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">

<Button
android:id="@+id/button_send"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Send" />

</androidx.constraintlayout.widget.ConstraintLayout>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
// 这里是在app/src/main/java/com.example.xx/MainActivity实现okhttp的调用以及目标url设置
// 注意文件原有代码的第一行的包别给删了 一般格式为 package com.example.xx

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.View;
import android.widget.Button;

import java.io.IOException;

import okhttp3.*;
public class MainActivity extends AppCompatActivity {
private Button buttonSend;
private OkHttpClient client;
// 这里的url设置是比较有讲究的,在Android模拟器上运行应用,需要使用特殊的IP地址 10.0.2.2,因为模拟器使用了虚拟网络,这个特殊IP地址会将请求转发到宿主机(运行模拟器的电脑)。当然这里的url可以设置为电脑当前的ip地址,不过存在一个小缺陷就是别人打开这个项目时候,如果ip发生了变化,那么就无法运行
// 如果是在实际的手机上测试这个应用,需要这里的url需要设置为spring boot所在设备的ip
private static final String URL = "http://10.0.2.2:8080/message";

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
client = new OkHttpClient(); // 创建okhttp客户端
buttonSend = findViewById(R.id.button_send);

buttonSend.setOnClickListener(new View.OnClickListener() { // 点击函数
@Override
public void onClick(View v) {
sendMessage("hello");
}
});
}

private void sendMessage(String message) {
RequestBody body = new FormBody.Builder()
.add("message", message)
.build(); // 创建信号体,装入需要传输的信息

Request request = new Request.Builder()
.url(URL)
.post(body)
.build(); // 创建信号传输的对象,这里指定了目标url和携带的内容

client.newCall(request).enqueue(new Callback() { // 使用okhttp客户端发送消息
@Override
public void onFailure(Call call, IOException e) { // 消息传输失败
e.printStackTrace();
}

@Override
public void onResponse(Call call, Response response) throws IOException { // 获取返回信息
if (response.isSuccessful()) {
final String responseText = response.body().string();
runOnUiThread(new Runnable() {
@Override
public void run() {
buttonSend.setText(responseText);
}
});
}
}
});
}

}

7、android studio前端项目运行

在android studio右上角选择虚拟设备(如果没有可以直接创建,读者可以自行搜索,这里不再赘述),设备的选择并不重要,有就行,随后点击运行的三角形符号

8、实例效果描述

运行出来之后会有一个send的按钮,点击之后会给后端传一个hello,后端如果识别到hello会给前端传hi,然后会把hi显示在按钮上,按钮上的文字从send变为hi

相关问题与解决

  • intellj idea新建spring boot项目后编译报错,报错信息如下:
    1
    2
    报错1:无法访问org.springframework.boot.springapplication错误的类文件:/c:/users/lxt13/.m2/repository/org/springframework/boot/spring-boot/3.0.5/spring-boot-3.0.5.jar!/org/springframework/boot/springapplication.class 类文件具有错误的版本 61.0, 应为 52.0 请删除该文件或确保该文件位于正确的类路径子目录中。
    报错2:java: 警告: 源发行版 17 需要目标发行版 17
    • 原因解释:这是因为使用了2023年的最新版的spring boot3不兼容的java版本造成,spring boot3全面支持java17,版本小于17的java不能够支持其运行
    • 解决方式: 在前面的实例的实现流程2、spring boot后端项目创建当中提到,选用spring boot2的最新版即可解决。或者读者考虑配置java17的相关环境,从而体验比较新的spring boot3
  • android studio对于拒绝连接http这种不安全协议,报错信息为java.net.UnknownServiceException: CLEARTEXT communication not supported
    • 原因解释: android studio当中的一个默认设置的,在android 7.0以后,为了手机操作系统的安全,android studio默认拒绝使用http这种通过明文传输的不安全协议
    • 解决方式: 在前面的实例的实现流程6、android studio前端代码编写当中提到,在AndroidManifest.xml当中,给application的属性增加一条android:usesCleartextTraffic="true"即可
  • android studio缺少internet权限,报错信息为java.net.SocketException: socket failed: EPERM (Operation not permitted)
    • 原因解释: 使用okhttp实现前后端连接需要赋予android studio网络权限
    • 解决方式: 在前面的实例的实现流程6、android studio前端代码编写当中提到,在AndroidManifest.xml当中,在manifest标签下,与application同级位置添加上<uses-permission android:name="android.permission.INTERNET" /> 即可
  • android studio中baseurl的选择:
    • 需要注意,这里的android studio的程序是在andorid虚拟设备上运行,与spring boot并不在同一个设备上,这里的url不能使用127.0.0.1或者localhost,这里的url设置是比较有讲究的,在Android模拟器上运行应用,需要使用特殊的IP地址 10.0.2.2,因为模拟器使用了虚拟网络,这个特殊IP地址会将请求转发到宿主机(运行模拟器的电脑)。当然这里的url可以设置为电脑当前的ip地址,不过存在一个小缺陷就是别人打开这个项目时候,如果ip发生了变化,那么就无法运行。如果是在实际的手机上测试这个应用,需要这里的url需要设置为spring boot所在设备的ip