一、 设计思路
1.1设计目标
1.2设计思路
1.3设计内容
1.3.1界面设计
1.3.2功能模块设计
1.3.3功能流程图
1.3.4数据库设计(如果没有数据库这部分删除)
1.4工具设备要求
1.5技术方案
二、设计过程与说明
2.1技术路线
2.2实现方案
2.3实现原理
2.3.1 欢迎页面功能
2.3.2首页功能
2.3.3搜索
2.3.4单词生词本查看
2.3.5我的页面
2.4功能描述
2.5系统测试方案
2.6遇到的问题及解决措施
三、设计成果简介
3.1作品特点
3.1.1技术指标
3.1.2性能特点
3.1.3创新之处
3.2毕业设计总结
3.2.1归纳总结
3.2.2待解决的问题
3.2.3改进意见
3.3详细设计成果
3.3.1欢迎页面
3.3.2首页
3.3.3背单词详情
3.3.4单词管理
四、致谢
五、参考文献
当代大部分学生都致力于通过大学英语四、六级考试,社会对应英语的应用也是越来越广泛,结合实际情况。众所周知,单词量的积累直接影响到英语考试成绩和工作需要。随着智能手机的普及,基于手机一类的移动终端软件越来越多。建立在Android操作系统上的一系列英语学习软件也都举不胜举。但是随手的应用英语小助手较难找到,结合实际使用和应用的情况需要有一款符合大众使用的Android 英语应用助手。
本软件是一个基于Android技术的学习软件,是在Windows8.1操作系统、Android studio 3.0编译环境下,使用Java编程语言,结合Android中自带的微小但功能强大的SQLite3.0数据库,实现了词库管理、学习模式、复习模式、测试模式、生疏词汇库、以及电子词典等功能。简洁清晰的操作界面,使用起来更加舒适、便捷。全新的拼读功能,发音更加标准。这款大学生英语四、六级学习软件非常有针对性的满足了即将参加大学英语四、六级考试的用户对单词记忆的需求;
很多人在学习英语的时候总是找不到合适的方法,而我自己也是处在漫游学英语的过程当中。有人曾经告诉过我,英语不是死学就能学好的,尤其对于脱离英语这么多年的情况下。要想有效学好英语,用对英语学习工具才是关键。很多人不知道我说的是什么意思,需要选择合适的学习工具,开发了这款应用英语学习助手软件,本程序是通过Android studio 开发,对于平时移动应用课程学习的实践展示。
[1,为什么要做这个项目,描述一下现状; 2,项目要完成的功能]
学习英语是非常常态化的一种以前的模式都是过分依赖人或者是通过授课的方式学习英语,那样对时间和学习的成本有很高的要求,如今信息化覆盖几乎是百分之80/90的情况下,大部分都会通过智能设备的方式获取有效资料或者学习有,通过信息化手段快速、精准的安排时间,随时随地都可以学习的英语辅助软件。
第一步:通过应用市场查找和身边学习的状态观察,常见需求:
第二步:学习是记录自己的学习情况,需要通过数据库记录学习单词情况,另外需要了解一些学习的资讯信息:
图1-1 思维导图
界面主要为主页面,页面设计简洁大方。页面有搜索页面,首页,菜单详情页面,背单词查看页面,生词本介绍页面,词汇页面,个人信息展示页面等。
系统功能结构图如图1-3所示。
图1-3 功能结构图
App功能流程如图1-4示。
图1-4 启动流程图
本系统涉及到3张表,分别是单词信息表、生词表(stuinfo)、学习进度表(tinfo)、各表的表结构如下。
表名称:单词表 |
||
字段名称 |
字段类型(长度) |
字段说明 |
Id |
Int |
主键 |
content |
String |
单词 |
Day |
String |
日期 |
definition |
String |
中文意思 |
pron |
string |
发音 |
Isflag |
String |
是否记住 |
Ext |
String |
扩展字段 |
表名称:发布跑腿 |
||
字段名称 |
字段类型(长度) |
字段说明 |
Id |
Int |
主键 |
Content |
String |
单词 |
definition |
String |
中文意思 |
Type |
String |
类型 |
Pron |
string |
发音 |
Isflag |
String |
是否生词本 |
Ext |
String |
扩展字段 |
开发工具:Android studio;
操作系统:Windows10操作系统;
首页,主要是三个部分,头部是搜索入口,可以查询英文信息,跳转到新的界面,展示查询的单词信息;接下来是展示功能菜单,外刊阅读、高中听力、英语写作、情景对话、语法讲练、每日一句、背单词等菜单功能,根据不同的菜单功能实现不同的功能作用,然后展示资讯列表,展示资讯信息;
2,单词 单词和生词本,记录背单词的不认识的单词信息
3,我的页面主要对单词学习掌握的记录,单词书,我的词库,单词进度等
4,数据库的应用主要是缓存单词数据
首页主要是展示两块,一是gridview的展示菜单的方式,外刊阅读、高中听力、英语写作、情景对话、语法讲练、每日一句、背单词。
二是资讯列表,展示学习一些英语的案例,激发学习热情,点燃学习的薪火,坚持学习的动力。
1,首页主要是导航 tab切换 首页,单词,我的页面等其他二级页面
2,首页菜单是通过recycleview 设置GridLayout的方式展示出来的两行四列
3,底部tab按钮切换不同页面的信息
4,首页资讯列表是通过列表的形式,recycleview展示每个item
5,展示查找英文和生词本都是查找数据,然后通过adapter适配器加载到列表中
6,我的页面部分用实验表格的方式展示。
1, 首页主要是导航 tab切换 首页,单词,我的页面等其他二级页面,首页菜单是通过recycleview 设置GridLayout的方式展示出来的两行四列,底部tab按钮切换不同页面的信息
首页资讯列表是通过列表的形式,recycleview展示每个item,展示查找英文和生词本都是查找数据,然后通过adapter适配器加载到列表中,我的页面部分用实验表格的方式展示;
首页,主要是三个部分,头部是搜索入口,可以查询英文信息,跳转到新的界面,展示查询的单词信息;接下来是展示功能菜单,外刊阅读、高中听力、英语写作、情景对话、语法讲练、每日一句、背单词等菜单功能,根据不同的菜单功能实现不同的功能作用,然后展示资讯列表,展示资讯信息;
2,单词 单词和生词本,记录背单词的不认识的单词信息
3,我的页面主要对单词学习掌握的记录,单词书,我的词库,单词进度等
4,数据库的应用主要是缓存单词数据
测试方案如下表2-1所示。
表2-1 测试方案
测试模式 |
测试功能 |
测试步骤 |
期望效果 |
功能测试 |
首页菜单 |
单击菜单选项进入详情 |
实现跳转 |
页面能否跳转 |
单击页面 |
页面实现跳转 |
|
背诵单词 |
点击背诵单词,是否进入正常 是否展示单词 单词不认识 是否显示中文和发音 |
显示正常 |
|
生词本 |
不认识的单词是否进入生词本中,生词本是否显示正常 |
有生词本并展示正常 |
问题1:webview加载白屏问题。
解决措施:本地连接判断是否安全证书链接即可。
问题2:存sqlite数据库主键唯一性判断。
解决措施:自增或者唯一值。
问题3:解决权限问题 否则奔溃。
解决措施:需要申请权限。
首页感谢老师的培养和教导,此项目得与开发还是离不开老师的教导,在开发过程遇到不少问题也是在老师的帮助下完成,主要体现在sqlite数据库的应用,解决疑难问题,调式过程中经常卡克,另外需要感谢同学的鼓励和帮助,是他们一起学习生活中渡过一段时光,在枯燥乏味的日子,同学们的欢声笑语滋润了心田,是他们的一起前行中学习到了每个知识点,课外经常讨论不明白的问题,梳理了不少疑惑。
此项目离使用还存在很多的不足,希望能在积累知识点的同时继续完善功能,尽量满足每一个功能,能够达到投入使用的状态,解决用户学习英语的需求,主要问题是云交互阶段和跨端的调式,也是我需要继续挖掘和学习的地方;
此项目虽然不是很完美,但是从中学习到了一个项目的整体设计和实现过程,把理论知识应用到实践中,提升实践能力。
欢迎页面如图3-1所示。
图3-1 欢迎页面
核心代码:
//欢迎页面
package com.yunus.remember.activity.begin;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
import com.example.yunus.activity.BaseActivity;
import com.yunus.remember.R;
import com.yunus.remember.activity.chief.MainActivity;
import com.yunus.remember.entity.SevenDaysReview;
import com.yunus.remember.utils.StorageUtil;
import org.litepal.crud.DataSupport;
import java.util.ArrayList;
import java.util.List;
public class WelcomeActivity extends BaseActivity implements Runnable {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_welcome);
new Thread(this).start();
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus && Build.VERSION.SDK_INT >= 19) {
View decorView = getWindow().getDecorView();
decorView.setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
}
}
@Override
public void run() {
try {
Thread.sleep(3000);
//todo 添加引导页
String email = StorageUtil.getString(WelcomeActivity.this, StorageUtil.EMAIL, "qxf323 ");
if (" ".equals(email)) {
Intent intent = new Intent(WelcomeActivity.this, LoginActivity.class);
startActivity(intent);
finish();
} else {
Intent intent = new Intent(WelcomeActivity.this, MainActivity.class);
startActivity(intent);
finish();
}
} catch (Exception e) {
e.printStackTrace();
}
DataSupport.deleteAll(SevenDaysReview.class);
List
for (int i = 0; i < 7; i++) {
SevenDaysReview review = new SevenDaysReview();
review.setTheDate("2018.05." + (23 + i));
review.setAllWordsCount(200 + i * 20);
review.setAllHadCount(100 + i * 20);
review.setStudiedTime((int) (20 + Math.random() * (60 - 20 + 1)));
review.setTodayStudiedCount((int) (60 + Math.random() * (100 - 60 + 1)));
reviews.add(review);
}
DataSupport.saveAll(reviews);
}
}
英语助手APP首页如图3-2所示。
图3-2 APP首页
核心代码:
//首页
package com.yunus.remember.adapter;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v7.view.menu.MenuAdapter;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.example.yunus.utils.LogUtil;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.yunus.remember.R;
import com.yunus.remember.activity.home.DiariesActivity;
import com.yunus.remember.activity.home.TestActivity;
import com.yunus.remember.activity.home.WordsDetailActivity;
import com.yunus.remember.activity.mine.BooksActivity;
import com.yunus.remember.activity.mine.ProgressActivity;
import com.yunus.remember.bean.Menu;
import com.yunus.remember.entity.Book;
import com.yunus.remember.entity.SevenDaysReview;
import com.yunus.remember.entity.TodayWord;
import com.yunus.remember.entity.Word;
import com.yunus.remember.utils.HttpUtil;
import com.yunus.remember.utils.StorageUtil;
import org.litepal.crud.DataSupport;
import java.io.IOException;
import java.sql.Date;
import java.util.ArrayList;
import java.util.List;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.FormBody;
import okhttp3.RequestBody;
import okhttp3.Response;
/**
* Created by yun on 2018/3/29.
*/
public class HomeFragment extends Fragment {
TextView doneDay;
TextView newNum;
TextView todayNum;
TextView remainNum;
TextView mineNum;
TextView btMineNum;
Button startStudy;
LinearLayout numLayout;
LinearLayout welcomeLayout;
LinearLayout commonLayout;
TextView addBook;
ProgressBar progress;
ImageView allDiary;
WordsListAdapter menuAdapter;
HomeListAdapter listAdapter;
RecyclerView recyclerView,listRecyclerView;
public HomeFragment() {
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.main_pager_home_new, container, false);
return view;
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
doneDay = getActivity().findViewById(R.id.done_day);
newNum = getActivity().findViewById(R.id.home_num_new);
todayNum = getActivity().findViewById(R.id.home_num_today);
remainNum = getActivity().findViewById(R.id.home_num_remain);
mineNum = getActivity().findViewById(R.id.home_num_mine);
btMineNum = getActivity().findViewById(R.id.home_bt_mine);
startStudy = getActivity().findViewById(R.id.start_study);
numLayout = getActivity().findViewById(R.id.home_num_layout);
welcomeLayout = getActivity().findViewById(R.id.home_welcome_layout);
commonLayout = getActivity().findViewById(R.id.home_common_layout);
addBook = getActivity().findViewById(R.id.home_add_book);
progress = getActivity().findViewById(R.id.home_progress);
allDiary = getActivity().findViewById(R.id.home_calendar);
recyclerView = getActivity().findViewById(R.id.menu_recycler_view);
listRecyclerView = getActivity().findViewById(R.id.mlist_recycler_view);
startStudy.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(getActivity(), TestActivity.class);
startActivity(intent);
}
});
btMineNum.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(getActivity(), ProgressActivity.class);
startActivity(intent);
}
});
addBook.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(getActivity(), BooksActivity.class);
getActivity().startActivity(intent);
}
});
allDiary.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(getActivity(), DiariesActivity.class);
getActivity().startActivity(intent);
}
});
menuAdapter = new WordsListAdapter();
listAdapter = new HomeListAdapter();
menuAdapter.setDataList(getContext(),getData());
listAdapter.setDataList(getContext(),getData());
recyclerView.setLayoutManager(new GridLayoutManager(getContext(),4));
recyclerView.setAdapter(menuAdapter);
listRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
listRecyclerView.setAdapter(listAdapter);
menuAdapter.setOnItemClickListener(new WordsListAdapter.OnItemClickListener() {
@Override
public void onItemClick(int position) {
if (position==7){
Intent intent = new Intent(getContext(), WordsDetailActivity.class);
getActivity().startActivity(intent);
}else{
Intent intent = new Intent(getContext(), DiariesActivity.class);
getActivity().startActivity(intent);
}
}
@Override
public void onClickMoreOp(int position, View view, Menu ArrangeBean) {
}
@Override
public void onClickConnectPrint(int position, Menu ArrangeBean) {
}
});
}
@Override
public void onStart() {
super.onStart();
if (!StorageUtil.getString(getContext(), StorageUtil.TODAY_DATE, " ").equals(StorageUtil
.getToday())) {
//
// commonLayout.setVisibility(View.GONE);
// numLayout.setVisibility(View.VISIBLE);
// welcomeLayout.setVisibility(View.VISIBLE);
startStudy.setText("准备中");
startStudy.setEnabled(false);
if (!(DataSupport.count(Book.class) == 0)) {
new DownloadTask().execute();
}
}
initText();
}
private void initText() {
doneDay.setText(String.valueOf(StorageUtil.getInt(getContext(), StorageUtil.REGISTER_DAY,
0)));
newNum.setText(String.valueOf(StorageUtil.getInt(getContext(), StorageUtil
.TODAY_REAL_NEW_NUM, 0)));
todayNum.setText(String.valueOf(StorageUtil.getInt(getContext(), StorageUtil.TODAY_NUM,
0)));
remainNum.setText(String.valueOf(StorageUtil.getInt(getContext(), StorageUtil
.TODAY_REMAIN_NUM, 0)));
mineNum.setText(String.valueOf(StorageUtil.getInt(getContext(), StorageUtil.WORDS_NUM, 0)));
}
private Word getWord(int level) {
if (DataSupport.where("level > 0").count(Word.class) <= 0) {
return null;
} else {
if (DataSupport.where("level = ?", level + "").count(Word.class) == 0) {
return getWord(level % 5 + 1);
}
int importance;
switch ((int) (Math.random() * 10)) {
case 0:
case 1:
case 2:
case 3:
case 4:
importance = 3;
break;
case 5:
case 6:
case 7:
importance = 2;
break;
case 8:
case 9:
importance = 1;
break;
default:
importance = 3;
}
if (DataSupport.where("level = ? and importance = ?", level + "", importance + "")
.count(Word.class) == 0) {
return getWord(level);
}
Word word = DataSupport.where("level = ? and importance = ?", level + "", importance
+ "").findFirst(Word
.class);
DataSupport.delete(Word.class, word.getId());
return word;
}
}
class DownloadTask extends AsyncTask
@Override
protected void onPreExecute() {
progress.setVisibility(View.VISIBLE);
}
@Override
protected Boolean doInBackground(Void... voids) {
//前期更新
if (StorageUtil.getInt(getContext(), StorageUtil.TODAY_NUM, 0) == 0) {
StorageUtil.updateInt(getContext(), StorageUtil.TODAY_NUM, 100);
}
if (StorageUtil.getInt(getContext(), StorageUtil.TODAY_NEW_NUM, 0) == 0) {
StorageUtil.updateInt(getContext(), StorageUtil.TODAY_NEW_NUM, 20);
}
List
for (Word word : allWord) {
word.setImportance(word.getImportance() + 1);
}
DataSupport.saveAll(allWord);
//计算要下载单词量
int needStudyNum = StorageUtil.getInt(getContext(), StorageUtil.WORDS_NUM, 0) -
StorageUtil.getInt(getContext(), StorageUtil.WORDS_STUDIED_NUM, 0);
if (needStudyNum < StorageUtil.getInt(getContext(), StorageUtil.TODAY_NUM, 100)) {
StorageUtil.updateInt(getContext(), StorageUtil.TODAY_REAL_NEW_NUM, StorageUtil
.getInt(getContext(),
StorageUtil.TODAY_NUM, 0) - needStudyNum);
} else {
int wordNum = DataSupport.where("importance > 3").count(Word.class);
if (wordNum >= StorageUtil.getInt(getContext(), StorageUtil.TODAY_NEW_NUM, 20)) {
StorageUtil.updateInt(getContext(), StorageUtil.TODAY_REAL_NEW_NUM, 0);
} else {
StorageUtil.updateInt(getContext(), StorageUtil.TODAY_REAL_NEW_NUM,
StorageUtil.getInt(getContext
(), StorageUtil.TODAY_NEW_NUM, 0) - wordNum);
}
}
//更新上次登陆记录
if (DataSupport.where("DATE(theDate) < DATE('now', '-6 day', 'localtime')").count
(SevenDaysReview.class) > 0) {
DataSupport.deleteAll(SevenDaysReview.class, "theDate < DATE(?)",
StorageUtil.getDate(new Date(System.currentTimeMillis()
- (long) (6 * 24 * 60 * 60 * 1000))));
}
SevenDaysReview lastReview = DataSupport.findLast(SevenDaysReview.class);
if (lastReview != null &&
StorageUtil.getInt(getContext(), StorageUtil.STUDY_TIME, 0) != 0) {
lastReview.setStudiedTime(StorageUtil.getInt(getContext(), StorageUtil
.STUDY_TIME, 0));
lastReview.setTodayStudiedCount(StorageUtil.getInt(getContext(), StorageUtil
.TODAY_STUDY_NUM, 0));
lastReview.save();
}
StorageUtil.updateInt(getContext(), StorageUtil.STUDY_TIME, 0);
StorageUtil.updateInt(getContext(), StorageUtil.TODAY_STUDY_NUM, 0);
//本地词库填充
DataSupport.deleteAll(TodayWord.class);
int needNum = StorageUtil.getInt(getContext(), StorageUtil.TODAY_NUM, 100) -
StorageUtil.getInt(getContext
(), StorageUtil.TODAY_REAL_NEW_NUM, 0);
List
("importance desc").find(Word.class);
List
for (Word word : words) {
todayWords.add(new TodayWord(word.getSpell(), word.getMean(), word.getPhonogram()
, word.getSentence()
, 1));
}
needNum = needNum - words.size();
List
while (needNum > 0) {
int levelNeed = (needNum + 3) / 4;
int level;
for (level = 1; level < 5; level++) {
for (int i = 0; i < levelNeed; i++) {
saveWords.add(getWord(level));
needNum--;
if (needNum == 0) {
break;
}
}
}
}
DataSupport.saveAll(saveWords);
for (Word word : saveWords) {
todayWords.add(new TodayWord(word.getSpell(), word.getMean(), word.getPhonogram()
, word.getSentence()
, 1));
}
DataSupport.saveAll(todayWords);
//联网,下载生成今日单词
RequestBody body = new FormBody.Builder()
.add("userId", "" + StorageUtil.getInt(getContext(), StorageUtil.USER_ID, 0))
.add("bookId", "" + DataSupport.where("state = -1").findFirst(Book.class)
.getId())
.add("needNum", "" + StorageUtil.getInt(getContext(), StorageUtil
.TODAY_REAL_NEW_NUM, 0))
.build();
HttpUtil.todayWord(body, new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
String result = response.body().string();
LogUtil.d("word", result);
Gson gson = new Gson();
List>() {
}.getType());
for (Word word : netWords) {
word.setLevel(5);
word.setImportance(0);
new TodayWord(word.getSpell(), word.getMean(), word.getPhonogram(),
word.getSentence(), 1).save();
}
DataSupport.saveAll(netWords);
StorageUtil.updateInt(getContext(), StorageUtil.WORDS_NUM,
DataSupport.count(Word.class));
//更新今天记录
int studiedNum = DataSupport.where("level < 1").count(Word.class);
int allNum = DataSupport.count(Word.class);
SevenDaysReview newReview = new SevenDaysReview(StorageUtil.getDate(new Date
(System.currentTimeMillis())), studiedNum, allNum);
newReview.save();
}
});
StorageUtil.updateString(getContext(), StorageUtil.TODAY_DATE, StorageUtil.getToday());
StorageUtil.updateInt(getContext(), StorageUtil.STUDY_TIME, 0);
StorageUtil.updateInt(getContext(), StorageUtil.TODAY_REMAIN_NUM,
StorageUtil.getInt(getContext(), StorageUtil.TODAY_NUM, 0));
return true;
}
@Override
protected void onPostExecute(Boolean aBoolean) {
progress.setVisibility(View.GONE);
commonLayout.setVisibility(View.VISIBLE);
startStudy.setText("学习");
startStudy.setEnabled(true);
numLayout.setVisibility(View.VISIBLE);
welcomeLayout.setVisibility(View.GONE);
initText();
}
}
private List