学习进度条
今日所花时间:一小时
今日代码量:100行
博客量:1篇
了解到的知识点: 学习APP开发
继续优化学习APP
1.完成学生用户能够查看自己发布的学习记录
在AndroidStudio加上API调用
@GET("/programmingRecord/list")
Call<List<ProgrammingRecord>> getProgrammingRecords(
@Header("Authorization") String token
);
ViewRecordsActivity
package com.example.study0327;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.example.study0327.api.ApiService;
import com.example.study0327.api.RetrofitClient;
import com.example.study0327.modules.ProgrammingRecord;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class ViewRecordsActivity extends AppCompatActivity {
private RecyclerView recyclerView;
private ProgrammingRecordAdapter adapter;
private String token;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_view_records);
// 获取token
SharedPreferences prefs = getSharedPreferences("user_prefs", MODE_PRIVATE);
token = "Bearer " + prefs.getString("auth_token", "").trim();
// 初始化RecyclerView
recyclerView = findViewById(R.id.recyclerViewRecords);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
adapter = new ProgrammingRecordAdapter();
recyclerView.setAdapter(adapter);
// 加载数据
loadProgrammingRecords();
}
private void loadProgrammingRecords() {
ApiService apiService = RetrofitClient.getClient().create(ApiService.class);
Call<List<ProgrammingRecord>> call = apiService.getProgrammingRecords(token);
call.enqueue(new Callback<List<ProgrammingRecord>>() {
@Override
public void onResponse(Call<List<ProgrammingRecord>> call, Response<List<ProgrammingRecord>> response) {
if (response.isSuccessful() && response.body() != null) {
adapter.setRecords(response.body());
} else {
Toast.makeText(ViewRecordsActivity.this, "获取记录失败: " + response.message(), Toast.LENGTH_SHORT).show();
}
}
@Override
public void onFailure(Call<List<ProgrammingRecord>> call, Throwable t) {
Toast.makeText(ViewRecordsActivity.this, "网络错误: " + t.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
}
activity_add_record.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:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp"
tools:context=".AddRecordActivity">
<!-- 标题 -->
<TextView
android:id="@+id/tvTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:text="添加编程记录"
android:textSize="24sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<!-- PSP阶段 -->
<TextView
android:id="@+id/tvPspStage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:text="PSP阶段:"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvTitle" />
<EditText
android:id="@+id/etPspStage"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:hint="输入PSP阶段"
android:inputType="text"
android:minHeight="48dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvPspStage" />
<!-- 内容 -->
<TextView
android:id="@+id/tvContent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="内容:"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/etPspStage" />
<EditText
android:id="@+id/etContent"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:hint="输入内容"
android:inputType="textMultiLine"
android:minLines="3"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvContent" />
<!-- 耗时 -->
<TextView
android:id="@+id/tvTimeSpent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="耗时(分钟):"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/etContent" />
<EditText
android:id="@+id/etTimeSpent"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:hint="输入耗时"
android:inputType="number"
android:minHeight="48dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvTimeSpent" />
<!-- 按钮区域 -->
<LinearLayout
android:id="@+id/buttonContainer"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:orientation="horizontal"
android:weightSum="2"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/etTimeSpent">
<!-- 添加记录按钮 -->
<Button
android:id="@+id/btnAddRecord"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_weight="1"
android:text="添加记录" />
<!-- 新增的查看记录按钮 -->
<Button
android:id="@+id/btnViewRecords"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_weight="1"
android:text="查看记录" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
页面上添加查看记录的按钮,点击即可查看该已经登陆的用户的编程记录
2.学生用户能够查看自己添加的每日总结按钮,并且点击即可跳转到该条总结的博客
DailySummaryAdapter
package com.example.study0327;
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.study0327.modules.DailySummary;
import java.util.List;
public class DailySummaryAdapter extends RecyclerView.Adapter<DailySummaryAdapter.ViewHolder> {
private List<DailySummary> summaries;
public static class ViewHolder extends RecyclerView.ViewHolder {
public TextView tvUsername, tvDate, tvBlogUrl;
public ViewHolder(View itemView) {
super(itemView);
tvUsername = itemView.findViewById(R.id.tvUsername);
tvDate = itemView.findViewById(R.id.tvDate);
tvBlogUrl = itemView.findViewById(R.id.tvBlogUrl);
}
}
public void setSummaries(List<DailySummary> summaries) {
this.summaries = summaries;
notifyDataSetChanged();
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_daily_summary, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
DailySummary summary = summaries.get(position);
holder.tvUsername.setText(summary.getUsername());
holder.tvDate.setText(summary.getSummaryDate());
holder.tvBlogUrl.setText(summary.getBlogUrl());
}
@Override
public int getItemCount() {
return summaries == null ? 0 : summaries.size();
}
}
AddSummaryActivity
package com.example.study0327;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import com.example.study0327.api.ApiService;
import com.example.study0327.api.RetrofitClient;
import com.example.study0327.modules.DailySummary;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class AddSummaryActivity extends AppCompatActivity {
private EditText etBlogUrl;
private Button btnAddSummary;
private LinearLayout summaryListLayout;
private String studentId;
private String authToken;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add_summary);
// 获取用户登录信息
SharedPreferences prefs = getSharedPreferences("user_prefs", MODE_PRIVATE);
studentId = prefs.getString("student_id", "");
authToken = "Bearer " + prefs.getString("auth_token", "");
if (studentId.isEmpty() || authToken.equals("Bearer ")) {
Toast.makeText(this, "请先登录", Toast.LENGTH_SHORT).show();
finish();
return;
}
etBlogUrl = findViewById(R.id.etBlogUrl);
btnAddSummary = findViewById(R.id.btnAddSummary);
summaryListLayout = findViewById(R.id.summaryListLayout);
// 获取当前日期
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
String currentDate = sdf.format(new Date());
// 加载历史记录
loadHistorySummaries();
btnAddSummary.setOnClickListener(v -> {
String blogUrl = etBlogUrl.getText().toString().trim();
if (blogUrl.isEmpty()) {
Toast.makeText(this, "请输入博客链接", Toast.LENGTH_SHORT).show();
return;
}
// 检查URL格式,自动添加http://前缀
if (!blogUrl.startsWith("http://") && !blogUrl.startsWith("https://")) {
blogUrl = "http://" + blogUrl;
}
DailySummary summary = new DailySummary();
summary.setUserId(Long.valueOf(studentId));
summary.setSummaryDate(currentDate);
summary.setBlogUrl(blogUrl);
ApiService apiService = RetrofitClient.getClient().create(ApiService.class);
Call<String> call = apiService.addDailySummary(authToken, summary);
call.enqueue(new Callback<String>() {
@Override
public void onResponse(Call<String> call, Response<String> response) {
if (response.isSuccessful()) {
Toast.makeText(AddSummaryActivity.this, response.body(), Toast.LENGTH_SHORT).show();
loadHistorySummaries(); // 刷新历史记录
etBlogUrl.setText(""); // 清空输入框
} else {
Toast.makeText(AddSummaryActivity.this, "添加失败: " + response.message(), Toast.LENGTH_SHORT).show();
}
}
@Override
public void onFailure(Call<String> call, Throwable t) {
Toast.makeText(AddSummaryActivity.this, "网络错误: " + t.getMessage(), Toast.LENGTH_SHORT).show();
}
});
});
}
private void loadHistorySummaries() {
ApiService apiService = RetrofitClient.getClient().create(ApiService.class);
Call<List<DailySummary>> call = apiService.getDailySummaries(authToken);
call.enqueue(new Callback<List<DailySummary>>() {
@Override
public void onResponse(Call<List<DailySummary>> call, Response<List<DailySummary>> response) {
if (response.isSuccessful() && response.body() != null) {
displaySummaries(response.body());
} else {
Toast.makeText(AddSummaryActivity.this, "获取历史记录失败", Toast.LENGTH_SHORT).show();
}
}
@Override
public void onFailure(Call<List<DailySummary>> call, Throwable t) {
Toast.makeText(AddSummaryActivity.this, "网络错误: " + t.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
private void displaySummaries(List<DailySummary> summaries) {
summaryListLayout.removeAllViews();
if (summaries.isEmpty()) {
TextView emptyView = new TextView(this);
emptyView.setText("暂无历史记录");
emptyView.setTextSize(16);
emptyView.setPadding(0, 32, 0, 0);
summaryListLayout.addView(emptyView);
return;
}
LayoutInflater inflater = LayoutInflater.from(this);
for (DailySummary summary : summaries) {
View summaryView = inflater.inflate(R.layout.item_summary, summaryListLayout, false);
TextView tvDate = summaryView.findViewById(R.id.tvDate);
TextView tvBlogUrl = summaryView.findViewById(R.id.tvBlogUrl);
tvDate.setText(summary.getSummaryDate());
tvBlogUrl.setText(summary.getBlogUrl());
// 为每个总结项添加点击事件
summaryView.setOnClickListener(v -> {
String url = summary.getBlogUrl();
// 检查URL格式
if (!url.startsWith("http://") && !url.startsWith("https://")) {
url = "http://" + url;
}
// 使用浏览器打开链接
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivity(browserIntent);
});
summaryListLayout.addView(summaryView);
}
}
}
activity_add_summary.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp"
tools:context=".AddSummaryActivity">
<TextView
android:id="@+id/tvTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:text="添加每日总结"
android:textSize="20sp"
android:textStyle="bold" />
<EditText
android:id="@+id/etBlogUrl"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:hint="请输入博客链接"
android:inputType="textUri"
android:minHeight="48dp" />
<Button
android:id="@+id/btnAddSummary"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="添加总结" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:text="我的历史总结"
android:textSize="18sp"
android:textStyle="bold" />
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp">
<LinearLayout
android:id="@+id/summaryListLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
</ScrollView>
</LinearLayout>

浙公网安备 33010602011771号