基于AndroidStudio+Java+SQLite开发的背单词APP系统

本文详细介绍了开发一个结合艾宾浩斯遗忘曲线的背单词App的过程,包括需求分析、系统设计、数据库构建和功能模块。App旨在通过用户熟识度和遗忘曲线优化单词复习策略,提供用户学习进度统计和个性化设置,以提高背诵效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目  录

第一章 绪论 1
1.1 选题设计开发的应用背景及价值 1
1.2 选题的研究现状 1
1.3 关于本课题 2
第二章 开发环境与主要技术 3
2.1 开发平台 3
2.2 主要技术 4
2.3 术语及相关缩写解释 7
第三章 系统分析 8
3.1 系统构建需求分析 8
3.2 系统构建目标分析 10
3.3 系统构建功能分析 10
第四章 系统设计 14
4.1 前台背单词展示子系统详细设计 14
4.2 后台数据管理子系统详细设计 22
4.3 数据库设计 26
第五章 应用编码、跨设备安装及测试 29
5.1 文件结构 29
5.2 典型编码 30
5.3 应用跨设备安装 35
5.4 应用测试及总结 35
第六章 结束语 37
6.1 毕业设计的难点与创新 37
6.2 毕业设计的收获 37
致 谢 38
参考文献 39
3.2 系统构建目标分析
背单词App的开发,需要用户能够随时地操作用户数据以及对每日任务和各单词出现的词频率自动做出调整,以满足用户高效率背诵单词的需要;因而在安排用户复习时对应单词本中的词频计算尤为重要,本系统目标是按艾宾浩斯遗忘曲线和用户熟识度相结合安排复习的方法来实现用户单词背诵效率最大化[20]。此外,应用还需要实时给出直观的用户熟识度统计和完成情况图:
(1)实现熟识度计算词频
对各个单词的熟识度应由用户在复习单词时来自主选择;熟识度包括熟记,认识,模糊和忘记四个选项,每个熟识度将由系统判断在保证今日任务的情况下再次安排复习。保证用户在当天背诵记忆能够更加巩固,牢靠。
(2)实现艾宾浩斯遗忘曲线计算词频
本应用充分利用艾宾浩斯遗忘曲线,使用户对非今日任务做一个合理的复习;艾宾浩斯遗忘曲线计算方法只依赖与系统时间戳;被由于艾宾浩斯遗忘曲线而安排用户复习的单词将刷新该单词的遗忘率(这与用户熟识度无关);从而保证用户对过去已学单词的背诵记忆够更加巩固,牢靠。
(3)实现学习情况统计
通过数据库统计数据并且利用API以图的形式直观地展现给用户。统计图包括当前词本学习进度统计图,艾宾浩斯遗忘曲线图和学习情况统计图;其中学习情况统计图提供用户明确的用户熟识度情况,剩余计划和单词收藏情况。
(4)实现用户数据操作
通过用户界面设置达到用户自定义每日任务量,用户学习任务管理和系统主题等目的,进一步提高用户的使用体验和学习效率。
3.3 系统构建功能分析
3.3.1 系统的总体架构
该系统由两个子系统构成:前台展示背单词子系统和后台数据管理子系统。同时主要包含两种Json数据解析和一种XML数据解析过程:幽灵背单词API词汇本和词汇数据解析,爱词霸词典API数据解析。其中幽灵背单词API数据解析是关键部分,是全部相关词汇的数据来源。
3.3.2 系统功能模块
3.3.2.1前台展示背单词子系统
前台展示背单词子系统简述
1.复习模块:背单词App的主要功能,安排用户背诵相应单词,更新用户信息和词汇信息数据库;
2.统计模块:显示用户学习进度扇形统计图,用户学习情况柱状统计图和艾宾浩斯遗忘数据折线统计图;
3.词本模块:变更当前所学习的英语词本,查看收藏词汇和搜索单词;
4.设置模块:设置背单词App的主题,每日背诵的单词任务量和操作用户数据;
5.导航栏模块:帮助用户快速切换到对应的功能模块,展示模块切换风格;

后台数据管理子系统简述
1.用户数据初始化:初始化当前用户信息数据库,包括用户ID,用户所用词本ID,用户任务量,用户今日任务进度,时间戳等信息;
2. 词汇本数据初始化:初始化全部词汇本信息数据库,包括词汇本数据请求信息,词汇本ID,词汇本词汇数量,是否存有词汇数据等信息;
3. 词汇数据初始化:初始化全部词汇信息数据库,包括词汇ID,词汇数据请求信息,词汇本ID,词汇音标,词汇发音地址,词汇名,词汇释义,词汇是否被收藏,词汇时间戳,词汇记忆程度,词汇熟识度和词汇例句等信息;
4. 词汇例句初始化:借助爱词霸API查询对应词汇的单词例句并更新词汇信息数据库;

package com.example.test0_debug.book_list;

import android.annotation.SuppressLint;
import android.app.ProgressDialog;
import android.content.Context;

import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;

import androidx.recyclerview.widget.RecyclerView;

import com.example.test0_debug.R;

import com.example.test0_debug.tools.httpHelper.HttpUtil;
import com.example.test0_debug.tools.httpHelper.jsonParse.WordList;
import com.example.test0_debug.tools.db.DBHelper;
import com.example.test0_debug.tools.httpHelper.ApiAddress;
import com.google.gson.Gson;

import org.jetbrains.annotations.NotNull;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

public class BookListAdapter extends RecyclerView.Adapter<BookListAdapter.ViewHolder> {
    private static final String TAG = "wordUrl";
    private static final int GET_WORD_SUCCESS = 1;
    private static final int GET_WORD_FAIL = 0;
    private final List<BookListDatas> mHistoryList;
    private int position;//数目列表点击位置
    private final Context context;
    private final TextView bookTitle;
    private final DBHelper dbHelper;
    private final ProgressDialog progressDialog;
    private Message message;
    private boolean isUpdated = false;
    private boolean netAvailable = false;
    @SuppressLint("HandlerLeak")
    final Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if (msg.what == GET_WORD_SUCCESS) {
                Log.e(TAG, "start :" + msg.arg1 + "  total: " + msg.arg2);
                String sql = (String) msg.obj;
                SQLiteDatabase db = dbHelper.getReadableDatabase();
                db.execSQL(sql);
                double done = msg.arg1;
                double total = msg.arg2;
                int progress = (int) ((done / total) * 100);
                Log.e(TAG, "done :" + msg.arg1 + "  total: " + msg.arg2 + " progress: " + progress);

                progressDialog.setProgress(progress);
                if (msg.arg1 == msg.arg2) {
                    db.close();
                    progressDialog.dismiss();
                    Toast.makeText(context, "选择成功!", Toast.LENGTH_SHORT).show();
                    //如果更换了书本则会重置今日进度,书本名,书本位置
                    if (!mHistoryList.get(position).getClass_id().equals(DBHelper.getBookClassId(context, 1))) {
                        DBHelper.setBookClassId(context, 1, mHistoryList.get(position).getClass_id());
                        DBHelper.setTodayProgress(context, 1, 1);
                        DBHelper.setWordPosition(context, 0, 1);
                        DBHelper.setExistence_item(context, mHistoryList.get(position).getClass_id(), DBHelper.EXISTENCE);
                        bookTitle.setText(mHistoryList.get(position).getTitle());
                    }
                }
            }
            if (msg.what == GET_WORD_FAIL) {
                Toast.makeText(context, "网络异常", Toast.LENGTH_SHORT).show();
                progressDialog.dismiss();
            }
        }
    };

    public BookListAdapter(Context context, List<BookListDatas> mHistoryList, TextView bookTitle) {
        this.mHistoryList = mHistoryList;
        this.context = context;
        this.bookTitle = bookTitle;
        netAvailable = HttpUtil.networkAvailable(context);
        dbHelper = new DBHelper(context, "Users.db", null, 1);
        progressDialog = new ProgressDialog(context);
        progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
        progressDialog.setIcon(R.drawable.book);
        progressDialog.setCancelable(false);
        progressDialog.setCanceledOnTouchOutside(false);
    }

    @NotNull
    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_item, parent, false);
        final ViewHolder holder = new ViewHolder(view);
        holder.recordView.setOnClickListener(v -> {
        });
        holder.content.setOnClickListener(v -> {
            if (!netAvailable) {
                Toast.makeText(context, "当前网络不可用", Toast.LENGTH_SHORT).show();
                return;
            }

            position = holder.getAdapterPosition();
            BookListDatas bookListDatas = mHistoryList.get(position);
            progressDialog.setTitle(bookListDatas.getTitle());
            progressDialog.setMessage("正在初始化...");
            /*if it have had word data in the database, we load it directly. if not, we get data from api*/
            if (!DBHelper.getExistence_item(context, bookListDatas.getClass_id())) {
                progressDialog.show();
                isUpdated = false;
                ExecutorService executorService = new ThreadPoolExecutor(1, 200, 120,
                        TimeUnit.SECONDS, new LinkedBlockingDeque<>());
                int total = Integer.parseInt(bookListDatas.getCourse_num());
                for (int i = 1; i <= total; i++) {
                    String finalUrl = new ApiAddress(context).getWordListAddress(bookListDatas.getClass_id(), i + "");
                    int finalI = i;
                    executorService.execute(new Runnable() {
                        @Override
                        public void run() {
                            message = Message.obtain();
                            message.arg1 = finalI;
                            message.arg2 = total;
                            int what = GET_WORD_FAIL;
                            ;
                            String obj = null;
                            String result;
                            OkHttpClient client = new OkHttpClient();
                            Request request = new Request.Builder().url(finalUrl).build();
                            try {
                                Response response = client.newCall(request).execute();
                                result = Objects.requireNonNull(response.body()).string();
                                what = GET_WORD_SUCCESS;
                            } catch (IOException e) {
                                result = obj = e.getMessage();
                            }
                            if (what == GET_WORD_SUCCESS) {
                                Gson gson = new Gson();
                                WordList wordList;
                                wordList = gson.fromJson(result, WordList.class);
                                if (wordList.getCode().equals("202")) {
                                    try {
                                        executorService.awaitTermination(3, TimeUnit.SECONDS);
                                    } catch (InterruptedException e) {
                                        e.printStackTrace();
                                    }
                                    return;
                                }
                                if (wordList.getCode().equals("206")) {
                                    /*api访问过于频繁*/
                                    alterUser();
                                }
                                ArrayList<com.example.test0_debug.tools.httpHelper.jsonParse.WordListData> dataList_word = wordList.getDatas();
                                StringBuilder sql = new StringBuilder(
                                        "insert into wordlist (msg,class_id,course_num,symbol,sound,name,class_title,desc_) values ");
                                for (int i = 0; i < dataList_word.size(); i++) {
                                    sql.append("('").append(wordList.getMsg()).append("',").
                                            append("'").append(wordList.getDatas().get(i).getClass_id()).append("',").
                                            append("'").append(wordList.getDatas().get(i).getCourse()).append("',").
                                            append("'").append(wordList.getDatas().get(i).getSymbol()).append("',").
                                            append("'").append(wordList.getDatas().get(i).getSound()).append("',").
                                            append("'").append(wordList.getDatas().get(i).getName()).append("',").
                                            append("'").append(wordList.getDatas().get(i).getClass_title()).append("',").
                                            append("'").append(wordList.getDatas().get(i).getDesc()).append("'),");
                                }
                                sql.deleteCharAt(sql.length() - 1).append(";");
                                obj = sql.toString();
                            }
                            message.what = what;
                            message.obj = obj;
                            handler.sendMessage(message);
                        }
                    });
                }
            }else{
                DBHelper.setBookClassId(context, 1, mHistoryList.get(position).getClass_id());
                DBHelper.setTodayProgress(context, 1, 1);
                DBHelper.setWordPosition(context, 0, 1);
                bookTitle.setText( mHistoryList.get(position).getTitle());
                Toast.makeText(context, "更换成功", Toast.LENGTH_SHORT).show();
            }
        });
        return holder;
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        BookListDatas bookListDatas = mHistoryList.get(position);
        holder.content.setText(bookListDatas.getTitle());
    }

    @Override
    public int getItemCount() {
        return mHistoryList.size();
    }

    static class ViewHolder extends RecyclerView.ViewHolder {
        TextView content;
        View recordView;

        public ViewHolder(View itemView) {
            super(itemView);
            recordView = itemView;
            content = itemView.findViewById(R.id.record_content);
        }
    }

    private void alterUser() {
        SQLiteDatabase db = dbHelper.getReadableDatabase();
        db.execSQL("update users set user='11590',appkey= 'fd9a685a09cefb3c3833b6a4b1171392' where appkey='62cb32159c84a2e6566eebcc9893b3a5'");
        db.close();
    }


}



在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值