学习进度条
今日所花时间:一小时
今日代码量:100行
博客量:一篇
了解到的知识点:深入学习androidStudio 继续优化完成课程管理系统
创建Empty Views Activity项目
在build.gradle.kts添加依赖
// Retrofit 依赖
implementation("com.squareup.retrofit2:retrofit:2.9.0")
implementation("com.squareup.retrofit2:converter-gson:2.9.0")
// RecyclerView 依赖
implementation("androidx.recyclerview:recyclerview:1.3.2")
implementation(libs.recyclerview)
在文件夹下创建adapters软件包
创建CourseAdapter
package com.example.demo0314.adapters;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.example.demo0314.models.Course;
import com.example.demo0314.R;
import java.util.List;
//CourseAdapter是适配器,用来绑定课程数据到RecyclerView
public class CourseAdapter extends RecyclerView.Adapter<CourseAdapter.CourseViewHolder> {
private List<Course> courseList;//课程数据列表
// 构造函数,传入课程列表
public CourseAdapter(List<Course> courseList) {
this.courseList = courseList;
}
// 创建ViewHolder
@NonNull
@Override
public CourseViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
// 加载布局文件 item_course.xml
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_course, parent, false);
return new CourseViewHolder(view);//返回ViewHolder实例
}
// 绑定数据到ViewHolder
@Override
public void onBindViewHolder(@NonNull CourseViewHolder holder, int position) {
Course course = courseList.get(position);//获取当前项的数据
holder.bind(course);//将数据绑定到ViewHolder
}
// 返回数据项的数量
@Override
public int getItemCount() {
return courseList.size();
}
// ViewHolder类,用于缓存视图
public static class CourseViewHolder extends RecyclerView.ViewHolder {
private TextView textCourseName, textTeacher, textLocation;// 视图组件
public CourseViewHolder(@NonNull View itemView) {
super(itemView);
// 初始化视图
textCourseName = itemView.findViewById(R.id.textCourseName);
textTeacher = itemView.findViewById(R.id.textTeacher);
textLocation = itemView.findViewById(R.id.textLocation);
}
// 绑定数据到视图
public void bind(Course course) {
textCourseName.setText(course.getCourseName());
textTeacher.setText("教师: " + course.getTeacher());
textLocation.setText("地点: " + course.getLocation());
}
}
}
创建api软件包
创建ApiService接口
package com.example.demo0314.api;
import com.example.demo0314.models.Course;
import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.GET;
import retrofit2.http.POST;
import java.util.List;
//定义与后端API的交互方法
public interface ApiService {
@GET("courses/all")//与后端保持一致
Call<List<Course>> getAllCourses();
@POST("courses/add")
Call<String> addCourse(@Body Course course);
}
创建RetrofitClient
package com.example.demo0314.api;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import okhttp3.OkHttpClient;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
import java.util.concurrent.TimeUnit;
//配置Retrofit客户端
public class RetrofitClient {
private static final String BASE_URL = "http://192.168.188.118:8080/";
private static Retrofit retrofit = null;
public static ApiService getApiService() {
if (retrofit == null) {
// 创建 Gson 实例,设置为 lenient 模式
Gson gson = new GsonBuilder()
.setLenient() // 允许解析非标准 JSON
.create();
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
.build();
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create(gson)) // 使用自定义的 Gson 实例
.build();
}
return retrofit.create(ApiService.class);
}
}
创建models包
Course实体类
package com.example.demo0314.models;
//课程数据模型
public class Course {
private Long id;
private String courseName;
private String teacher;
private String location;
// Getters and Setters
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getCourseName() {
return courseName;
}
public void setCourseName(String courseName) {
this.courseName = courseName;
}
public String getTeacher() {
return teacher;
}
public void setTeacher(String teacher) {
this.teacher = teacher;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
}
在MainActivity书写以下代码
package com.example.demo0314;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.example.demo0314.adapters.CourseAdapter;
import com.example.demo0314.api.ApiService;
import com.example.demo0314.api.RetrofitClient;
import com.example.demo0314.models.Course;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private RecyclerView recyclerView;
private CourseAdapter adapter;
private List<Course> courseList = new ArrayList<>();
private EditText editCourseName, editTeacher, editLocation;
private Button btnAddCourse;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 初始化UI
recyclerView = findViewById(R.id.recyclerView);
editCourseName = findViewById(R.id.editCourseName);
editTeacher = findViewById(R.id.editTeacher);
editLocation = findViewById(R.id.editLocation);
btnAddCourse = findViewById(R.id.btnAddCourse);
// 设置RecyclerView
recyclerView.setLayoutManager(new LinearLayoutManager(this));
adapter = new CourseAdapter(courseList);
recyclerView.setAdapter(adapter);
// 加载课程列表
loadCourses();
// 添加课程按钮点击事件
btnAddCourse.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
addCourse();
}
});
}
// 加载课程列表
private void loadCourses() {
ApiService apiService = RetrofitClient.getApiService();
apiService.getAllCourses().enqueue(new Callback<List<Course>>() {
@Override
public void onResponse(Call<List<Course>> call, Response<List<Course>> response) {
if (response.isSuccessful() && response.body() != null) {
courseList.clear();
if (response.body().isEmpty()) {
Toast.makeText(MainActivity.this, "没有课程数据", Toast.LENGTH_SHORT).show();
} else {
courseList.addAll(response.body());
}
adapter.notifyDataSetChanged();
} else {
Toast.makeText(MainActivity.this, "数据加载失败: " + response.message(), Toast.LENGTH_SHORT).show();
}
}
@Override
public void onFailure(Call<List<Course>> call, Throwable t) {
Log.e("Error", t.getMessage());
Toast.makeText(MainActivity.this, "网络请求失败,请检查网络连接", Toast.LENGTH_SHORT).show();
}
});
}
// 添加新课程
private void addCourse() {
String courseName = editCourseName.getText().toString().trim();
String teacher = editTeacher.getText().toString().trim();
String location = editLocation.getText().toString().trim();
if (courseName.isEmpty() || teacher.isEmpty() || location.isEmpty()) {
Toast.makeText(this, "请填写所有字段", Toast.LENGTH_SHORT).show();
return;
}
Course newCourse = new Course();
newCourse.setCourseName(courseName);
newCourse.setTeacher(teacher);
newCourse.setLocation(location);
Log.d("Request", "Sending: " + newCourse.toString());
ApiService apiService = RetrofitClient.getApiService();
apiService.addCourse(newCourse).enqueue(new Callback<String>() {
@Override
public void onResponse(Call<String> call, Response<String> response) {
if (response.isSuccessful()) {
Log.d("Response", "Success: " + response.body());
Toast.makeText(MainActivity.this, response.body(), Toast.LENGTH_SHORT).show();
editCourseName.setText("");
editTeacher.setText("");
editLocation.setText("");
loadCourses(); // 刷新课程列表
} else {
try {
// 打印错误信息
String errorBody = response.errorBody().string();
Log.e("Response", "Failed: " + errorBody);
Toast.makeText(MainActivity.this, "添加课程失败: " + errorBody, Toast.LENGTH_SHORT).show();
} catch (Exception e) {
e.printStackTrace();
}
}
}
@Override
public void onFailure(Call<String> call, Throwable t) {
Log.e("Error", t.getMessage());
Toast.makeText(MainActivity.this, "网络请求失败,请检查网络连接", Toast.LENGTH_SHORT).show();
}
});
}
}
在layout包下创建item_course.xml书写以下代码
<?xml version="1.0" encoding="utf-8"?>
<!--课程列表布局文件-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="8dp">
<TextView
android:id="@+id/textCourseName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="课程名称"
android:textSize="18sp" />
<TextView
android:id="@+id/textTeacher"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="任课教师" />
<TextView
android:id="@+id/textLocation"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="上课地点" />
</LinearLayout>
在activity_main.xml中写如下代码
<?xml version="1.0" encoding="utf-8"?>
<!--主活动布局文件-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp">
<EditText
android:id="@+id/editCourseName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="课程名称"
android:minHeight="48dp" />
<EditText
android:id="@+id/editTeacher"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="48dp"
android:hint="任课教师" />
<EditText
android:id="@+id/editLocation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="48dp"
android:hint="上课地点" />
<Button
android:id="@+id/btnAddCourse"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="48dp"
android:text="添加课程" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp" />
</LinearLayout>
在xml包下创建network_security_config.xml保证能够访问本地开发服务器
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<!-- 允许访问本地开发服务器 -->
<!--网络安全配置文件-->
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">10.0.2.2</domain>
<domain includeSubdomains="true">192.168.188.118</domain>
</domain-config>
</network-security-config>
通过以上代码的编写可以连接springboot完成的后端程序代码完成手机端的功能实现。

浙公网安备 33010602011771号