吴昊品工程级别软件项目 Round 4 —— Wordroid项目全解析
Wordroid项目全解析
——By 吴昊
我们只能说,不借助于模板,还是很困难的(毕竟,我们对安卓组件的熟悉还没有达到那种随手擒来的这种境地)。但是,我最终还是想出了一种办法,乃是三合一。将我们做的一部分+iword的单词库+BUPT的一部分Source整合,配上我们自己的图片,这是我们的最终策略,作为一个合格的产品,没有问题了,但是,考虑在算法上面的改进,将最后留一个月来完成吧!
其中项目的截图我采用的是中国移动开发者社区提供的终端池—远程测试功能,因为自己的模拟器各种故障,如图所示:(测试的机型为SUMSUNG i9000 Galaxy S 8G)
先看BUPT的Wordroid,整个项目解剖如下:
Wordroid.activitys包:
菜单栏目:
(1) 关于(about.java)
package wordroid.activitys;
import wordroid.model.R;
import android.app.Activity;
import android.os.Bundle;
public class about extends Activity {
@Override
//在重写中打开login布局
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
this.setContentView(R.layout.login);
}
}
(login.xml)
//这里将其宽与高拉到最大,然后将背景设置为一张既有的图片
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@drawable/login">
</LinearLayout>
我们的修改:关于部分,主要是记录版权信息,我们这里引入一张图片为宜(我们的towords还没有这种功能,可以补上)
(2) 帮助(Help.java)
首先在values文件夹的strings.xml中定义如下的一些字符串(字符串的名字和键值,同时会生成相应的R文件)
在Help类中,将其从上往下排列出来:
package wordroid.activitys;
import wordroid.model.R;
import android.app.Activity;
import android.os.Bundle;
import android.widget.ScrollView;
import android.widget.TextView;
public class Help extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
this.setContentView(R.layout.showabout);
TextView tv = (TextView) this.findViewById(R.id.about_title);
tv.setText("安卓背单词-Wordroid 帮助");
TextView words = (TextView) this.findViewById(R.id.about_words);
words.setText(R.string.words);
TextView abs = (TextView) this.findViewById(R.id.about_abstract);
abs.setText(R.string.abs);
TextView learn = (TextView) this.findViewById(R.id.about_learn);
learn.setText(R.string.learn);
TextView review = (TextView) this.findViewById(R.id.about_review);
review.setText(R.string.review);
TextView test = (TextView) this.findViewById(R.id.about_test);
test.setText(R.string.test);
TextView attetion = (TextView) this.findViewById(R.id.about_attention);
attetion.setText(R.string.attetion);
}
}
对于Help类的布局showabout.xml,没有什么值得说的吧,对第一个字符串,也就是“安卓背单词-Wordroid帮助”不设置移动,对于后面的布局开启一个ScrollView,这样可以进行拖动处理,如下,竖直排列七个字符串
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@drawable/main_back"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:id="@+id/about_title"
android:textColor="#000000"
android:textSize="20px"
/>
<ScrollView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/scrollView"
>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textColor="#000000"
android:id="@+id/about_abstract"
android:textSize="16px"
/>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textColor="#000000"
android:id="@+id/about_words"
android:textSize="16px"
/>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textColor="#000000"
android:id="@+id/about_learn"
android:textSize="16px"
/>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textColor="#000000"
android:id="@+id/about_review"
android:textSize="16px"
/>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textColor="#000000"
android:id="@+id/about_test"
android:textSize="16px"
/>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textColor="#000000"
android:id="@+id/about_attention"
android:textSize="16px"
/>
</LinearLayout>
</ScrollView>
</LinearLayout>
我们这里与之不同,我们设置三张图片,利用onFling来实现滑动,利用返回键返回来主菜单。
(3) 设置(类似于我们的option功能)
设置按钮的布局——Preferences.xml
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory android:title="复习提醒功能">
//方形框设置是否定时提醒
<CheckBoxPreference
android:key="notify"
android:title="定时提醒"
//这个定时提醒title是一个方形的选项,有开启和关闭两种模式
android:summaryOn=" 开启 "
android:summaryOff=" 关闭 "
android:defaultValue="true"
/>
//这里设置一个widget,就是对时间的设置
<wordroid.widget.timePreference
android:key="time"
android:title="设定每天提醒时间"
android:persistent="true"
android:summary=""
android:dependency="notify">
</wordroid.widget.timePreference>
</PreferenceCategory>
<PreferenceCategory
android:title="语音功能"
>
<CheckBoxPreference
android:key="iftts"
android:persistent="true"
android:defaultValue="true"
android:title="自动朗读单词"
android:summaryOn=" 开启 "
android:summaryOff=" 关闭 "
>
</CheckBoxPreference>
//利用ListPreference拖出一个条形框并将默认的语言设置为英语
<ListPreference
android:key="category"
android:title="选择语音种类"
//初始选项为英语
android:defaultValue="1"
android:summary=""></ListPreference>
</PreferenceCategory>
</PreferenceScreen>
package wordroid.activitys;
import java.util.HashMap;
import wordroid.business.OperationOfBooks;
import wordroid.model.R;
import wordroid.widget.timePreference;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.os.Bundle;
import android.preference.ListPreference;
import android.preference.PreferenceActivity;
import android.preference.Preference.OnPreferenceChangeListener;
public class Preference extends PreferenceActivity implements OnPreferenceChangeListener {
ListPreference listpre;
timePreference timepre;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
//在资源文件中将preference载入
addPreferencesFromResource(R.xml.preference);
timepre = (timePreference) this.findPreference("time");
timepre.setOnPreferenceChangeListener(this);
SharedPreferences settings = getSharedPreferences("wordroid.model_preferences", MODE_PRIVATE);
timepre.setSummary(settings.getString("time", "18:00 下午"));
CharSequence[] list={"英语","美语"};
listpre=(ListPreference) this.findPreference("category");
listpre.setEntries(list);
//这里选择英语或者是美语
CharSequence[] list2={"1","2"};
listpre.setEntryValues(list2);
listpre.setSummary(listpre.getEntry());
//监听对复习提醒功能和语音功能的变化 this.getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(new OnSharedPreferenceChangeListener(){
public void onSharedPreferenceChanged(
SharedPreferences sharedPreferences, String key) {
// TODO Auto-generated method stub
listpre.setSummary(listpre.getEntry());
}
});
}
@SuppressWarnings("unchecked")
//这里利用一个HashMap来存放键值对,比如这里的<String,Integer>,字符串存储的是上午还是下午,而数字存储的是具体的时间,这里面还有一个处理,就是对于分钟来说,如果<10的话,前面应该补上0,而对于小时的话,没有类似的处理,主要是因为要判断是上午还是下午
public boolean onPreferenceChange(android.preference.Preference preference,
Object newValue) {
// TODO Auto-generated method stub
if(preference.getKey().equals("time")){
HashMap<String,Integer> map =(HashMap<String, Integer>) newValue;
String ifAm="上午";
if(map.get("hour")>11) ifAm=" 下午";
int minute=map.get("minute");
String mi=String.valueOf(minute);
if (minute<10)mi="0"+minute;
timepre.setSummary(""+map.get("hour")+":"+mi+" "+ifAm);
OperationOfBooks OOB = new OperationOfBooks();
SharedPreferences settings = getSharedPreferences("wordroid.model_preferences", MODE_PRIVATE);
//此为初始设置,为18:00的下午
OOB.setNotify(settings.getString("time", "18:00 下午"),this);
}
return false;
}
}
主界面:
我们的主菜单是以四个按钮那种形式的(这里的UI功能需要借助点团队的人员来完善,但是静态的有在iWord中说明),还是先看看这款软件的主界面设计:
//包说明
package wordroid.activitys;
//导入一些控件和函数库
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.ArrayList;
import wordroid.business.*;
import wordroid.database.DataAccess;
import wordroid.database.SqlHelper;
import wordroid.model.BookList;
import wordroid.model.R;
import wordroid.model.WordList;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ProgressBar;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemSelectedListener;
import android.content.*;
import android.graphics.Typeface;
//对主界面设置各种监听
public class Main extends Activity implements OnClickListener{
//设置书的编号和书名两个字符串变量
public static String SETTING_BOOKID="bookID";
public static String BOOKNAME = "BOOKNAME";
//Spinner类(弹拉式边框)pickBook
private Spinner pickBook;
//TextView类,定义一个info变量
private TextView info;
//如下是六个按钮,具有重置和删除当前词库的功能,这一点考虑到了“词库自定义”的重要性,有“学习”(这个需要用户自己的诚实度了),复习(这个模拟的是我们的助理功能),测试(是我们的普通练习功能),至于生词库,和我们的差不多,不过,这里可以保存到外存中,在整个程序关闭后还是可以呈现的
private ImageButton deleteBu;
private ImageButton resetBu;
//如下就是这四个按钮
private Button learnBu;
private Button reviewBu;
private Button testBu;
private Button attentionBu;
//这里定义了两个progress进度条,一个注明已经学习的进度(学习的单词数占据总单词数的多少),另外一个注明已经复习的进度(复习的单词数占据总单词书的多少)
private ProgressBar learn_progress;
private ProgressBar review_progress;
//这里的两个TextView类的实例,一个是已经学习的进度(文字显示),一个是已经复习的进度(文字显示),这两个文字显示都是可以变动的
private TextView learn_text;
private TextView review_text;
//这里定义菜单的三个状态量,利用final声明为常量(设置,关于和说明)
public static final int MENU_SETTING = 1;
public static final int MENU_ABOUT = MENU_SETTING+1;
public static final int MENU_CONTACT = MENU_SETTING+2;
//定义一个View类的实例myView
View myView;
@Override
//重写
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
//这里设置主界面的标题“安卓背单词--Wordroid”
this.setTitle("安卓背单词--Wordroid");
super.onCreate(savedInstanceState);
//启动登录界面
this.setContentView(R.layout.login);
//这里是在登录界面之后,动态地装载主界面,由于是动态装载,而且是直接找的xml文件而不是控件,所以这里用的是LayoutInflater类
LayoutInflater mInflater = LayoutInflater.from(this);
myView = mInflater.inflate(R.layout.main, null);
//这里开辟一个进程,并且为登录界面刷2秒钟
Thread thread = new Thread(){
public void run(){
try {
Thread.sleep(2000);
Message m = new Message();
m.what=1;
Main.this.mHandler.sendMessage(m);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
};
//开始刷2秒的线程
thread.start();
//为词库类创造一个实例OOB,并且初始化词库
OperationOfBooks OOB = new OperationOfBooks();
//利用SharedPreferences设置一个轻量级的存储类的实例进行存储工作
SharedPreferences setting = getSharedPreferences("wordroid.model_preferences", MODE_PRIVATE);
//这里显示一个通知
OOB.setNotify(setting.getString("time", "18:00 下午"),Main.this);
//这里引入文件设置,来维持持久存储,这里将路径设置在databases文件夹下
File dir = new File("data/data/wordroid.model/databases");
//如果目录不存在的话,就创建一个
if (!dir.exists())
dir.mkdir();
//这里的文件设置暂时有些看不懂
if (!(new File(SqlHelper.DB_NAME)).exists()) {
FileOutputStream fos;
try {
fos = new FileOutputStream(SqlHelper.DB_NAME);
byte[] buffer = new byte[8192];
int count = 0;
InputStream is = getResources().openRawResource(
R.raw.wordorid);
while ((count = is.read(buffer)) > 0) {
fos.write(buffer, 0, count);
}
fos.close();
is.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
SharedPreferences settings=getSharedPreferences(SETTING_BOOKID, 0);
DataAccess.bookID=settings.getString(BOOKNAME, "");
//OOB更新表单信息
OOB.UpdateListInfo(Main.this);
//初始化组件
initWidgets();
}
//这里,初始化一个下拉列表(图为主菜单,上面是下拉列表,下面还有两个滑动条)
private void initSpinner() {
//实例化一个数据访问类
DataAccess data = new DataAccess(this);
//获取所有的图书,这里实例化一个ArrayList列表
final ArrayList<BookList> bookList = data.QueryBook(null, null);
//Log.i("size", String.valueOf(bookList.size()));这个命令主要是在调试的时候使用
//这里定义一个字符串数组,将所有图书装填,其中的+1主要是考虑鲁棒性
String[] books = new String[bookList.size()+1];
int i=0;
//循环控制,保存每一本书的书名(用数组books[])
for (;i<bookList.size();i++){
books[i]=bookList.get(i).getName();
}
最后一个下标,保存名字为“导入新词库”
books[i]="导入新词库";
ArrayAdapter< CharSequence > adapter = new ArrayAdapter< CharSequence >(this, android.R.layout.simple_spinner_item, books);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
pickBook.setAdapter(adapter);
//对于不同的书目(这里给了我们一个启示,没有必要在option里面让读者选择自己的英语级别,在主界面中直接选择,显得更醒目)
pickBook.setOnItemSelectedListener(new OnItemSelectedListener(){
public void onItemSelected(AdapterView<?> arg0, View arg1,
int arg2, long arg3) {
//如果选择的书的位置小于最大位置的话,则列出如下文字信息,并且将那五个按钮重新设置为可见的状态。初次登录的话,还不能判定是否有生词,所以,对于生词库来说,这个按钮暂时设置为false
if (arg2<bookList.size()){
DataAccess.bookID=bookList.get(arg2).getID();
info.setText("\n词库名称:\n "+bookList.get(arg2).getName()+"\n总词汇量:\n "+bookList.get(arg2).getNumOfWord()+"\n创建时间:\n "+bookList.get(arg2).getGenerateTime());
deleteBu.setEnabled(true);
learnBu.setEnabled(true);
resetBu.setEnabled(true);
reviewBu.setEnabled(true);
testBu.setEnabled(true);
//在这个访问数据中,得到这本书中的所有的单词,并将其存入ArrayList的实例lists中
DataAccess data2 = new DataAccess(Main.this);
ArrayList<WordList> lists = data2.QueryList("BOOKID ='"+DataAccess.bookID+"'", null);
(该记单词游戏的核心算法)
//设置两个进度条的最大值,都为这本书中单词的数目
learn_progress.setMax(lists.size());
review_progress.setMax(lists.size());
//设置初始进度条,对于review进度条来说,定义一个setProgress和setSecondaryProgress,这里相当于一个进度缓冲(这里是有奇妙的用处的,我会在后文进行阐述)
learn_progress.setProgress(0);
review_progress.setProgress(0);
review_progress.setSecondaryProgress(0);
//这里利用整型变量来表征布尔逻辑,对于每个单词来说,未学习过(复习过)的单词定义为0,而反之则定义为1,从未学习过(复习过)到学习过(复习过)的过程就是learn++(review++)
int learned=0,reviewed=0;
for (int k=0;k<lists.size();k++){
if (lists.get(k).getLearned().equals("1")){
learn_progress.incrementProgressBy(1);
learned++;
}
//如果这个单词复习的次数为五次以上,可以认为(这里涵盖了一种记单词的算法思想)已经掌握了单词,将其注明为复习过的,主进度条++
if (Integer.parseInt(lists.get(k).getReview_times())>=5){
review_progress.incrementProgressBy(1);
reviewed++;
}
//如果复习的次数大于等于1的话,则表示复习过(但并不能说明是复习地很全面了),所以只是从进度条++,而主进度条不增加
if (Integer.parseInt(lists.get(k).getReview_times())>0)
review_progress.incrementSecondaryProgressBy(1);
review_text.setText("已复习"+reviewed+"/"+lists.size());
//这个learn进度条不包括在已学习的进度条中
learn_text.setText("已学习"+learned+"/"+lists.size());
}
}
//如果已经读到末尾了,对界面进行跳转,利用intent跳转到新的词库的选择界面
else if(arg2==bookList.size()){
Intent intent = new Intent();
intent.setClass(Main.this, ImportBook.class);
startActivity(intent);
}
}
//这个函数不用写入
public void onNothingSelected(AdapterView<?> arg0) {
// TODO Auto-generated method stub
}
});
//如果这个词库里面没有一个单词的话,会显示选择一个词库的提示文字,给出选择框,并将所有的按钮和进度条置false
if (bookList.size()==0) {
pickBook.setSelection(1);
info.setText("请先从上方选择一个词库!");
this.deleteBu.setEnabled(false);
this.learnBu.setEnabled(false);
this.resetBu.setEnabled(false);
this.reviewBu.setEnabled(false);
this.testBu.setEnabled(false);
this.learn_progress.setProgress(0);
this.review_progress.setProgress(0);
return;
}
int j=0;
//调试信息
Log.i("BookID", DataAccess.bookID);
//获取每一本书(文件)中的单词数据
for (;j<bookList.size();j++){
if (DataAccess.bookID.equals(bookList.get(j).getID())){
pickBook.setSelection(j);
break;
}
}
}
//这里是对各种组件的初始化,写成函数的形式,更加紧凑,主过程也更简洁
private void initWidgets() {
// TODO Auto-generated method stub
this.deleteBu=(ImageButton) myView.findViewById(R.id.delete);
deleteBu.setOnClickListener(this);
this.info=(TextView) myView.findViewById(R.id.bookinfo);
this.learnBu=(Button) myView.findViewById(R.id.learn);
learnBu.setOnClickListener(this);
this.pickBook=(Spinner) myView.findViewById(R.id.pickBook);
this.resetBu=(ImageButton) myView.findViewById(R.id.reset);
resetBu.setOnClickListener(this);
this.reviewBu=(Button) myView.findViewById(R.id.review);
reviewBu.setOnClickListener(this);
this.testBu=(Button) myView.findViewById(R.id.test);
testBu.setOnClickListener(this);
this.attentionBu=(Button) myView.findViewById(R.id.attention);
attentionBu.setOnClickListener(this);
this.learn_progress= (ProgressBar) myView.findViewById(R.id.learn_progress);
this.review_progress= (ProgressBar) myView.findViewById(R.id.review_progress);
this.review_text=(TextView) myView.findViewById(R.id.review_text);
this.learn_text=(TextView) myView.findViewById(R.id.learn_text);
DisplayMetrics dm = new DisplayMetrics();
dm = getApplicationContext().getResources().getDisplayMetrics();
int screenWidth = dm.widthPixels;
int padding = (screenWidth-200);
this.learnBu.setPadding(padding/5, 0, padding/10, 0);
this.resetBu.setPadding(padding/10, 0, padding/10, 0);
this.testBu.setPadding(padding/10, 0, padding/10, 0);
this.attentionBu.setPadding(padding/10, 0, padding/5, 0);
initSpinner();
}
//这里有做,如果将整个程序Destroy的话(android的生命周期这里就不说了),关于各种书的数据还是进行保存的。
protected void onDestroy() {
// TODO Auto-generated method stub
SharedPreferences settings=getSharedPreferences(SETTING_BOOKID, 0);
settings.edit()
.putString(BOOKNAME, DataAccess.bookID)
.commit();
super.onDestroy();
}
//这里,根据按钮的响应进行各种跳转啊!分别根据响应的按钮跳转到学习,复习,测试或者是生词本的界面中去
public void onClick(View v) {
// TODO Auto-generated method stub
if (v==reviewBu){
Intent intent = new Intent();
intent.setClass(Main.this, ReviewMain.class);
this.startActivity(intent);
}
if (v==testBu){
Intent intent = new Intent();
intent.setClass(Main.this, TestList.class);
this.startActivity(intent);
}
if (v==deleteBu){
//这里设置的是一般的Dialog,不过还是加工了一下,设置了图标Icon,选择确定之后删除词库,并重新初始化放书地Spinner列表
Dialog dialog = new AlertDialog.Builder(this)
.setIcon(R.drawable.dialog_icon)
.setTitle("删除当前词库")
.setMessage("确定要将这个词库删除吗?")
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
DataAccess data = new DataAccess(Main.this);
data.DeleteBook();
DataAccess.bookID="";
Toast.makeText(Main.this, "该词库已删除", Toast.LENGTH_SHORT).show();
initSpinner();
}
})
.setNegativeButton("取消", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
}
}).create();
dialog.show();
}
//重置按钮同理啦(这个Bu的意思就是按钮Button)
if (v==this.resetBu){
Dialog dialog = new AlertDialog.Builder(this)
.setIcon(R.drawable.dialog_icon)
.setTitle("重置当前词库")
.setMessage("确定要将这个词库重置吗?它将失去所有学习记录")
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
DataAccess data = new DataAccess(Main.this);
data.ResetBook();
Toast.makeText(Main.this, "该词库已被重置", Toast.LENGTH_SHORT).show();
initSpinner();
}
})
.setNegativeButton("取消", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
}
}).create();
dialog.show();
}
if (v==this.attentionBu){
Intent intent = new Intent();
intent.setClass(Main.this, Attention.class);
startActivity(intent);
}
if (v==learnBu){
Intent intent = new Intent();
intent.setClass(Main.this, study.class);
this.startActivity(intent);
}
}
//这个是对于暂停状态(原因很多)的复原
@Override
protected void onResume() {
// TODO Auto-generated method stub
Log.i("In Resume", DataAccess.bookID);
this.initSpinner();
super.onResume();
}
//利用这种方式设置Menu的三个按钮
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// TODO Auto-generated method stub
menu.add(0, MENU_SETTING, 0, "设置");
menu.add(0, MENU_ABOUT, 1, "说明");
menu.add(0, MENU_CONTACT, 2, "关于");
return super.onCreateOptionsMenu(menu);
}
//这个也是处理Menu里面按钮的各种函数,利用switch—case逻辑,对于每一个MENU所对应的状态加上相应的响应
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// TODO Auto-generated method stub
switch(item.getItemId()){
case MENU_SETTING:{
Intent intent = new Intent();
//通过Intent进行转换,将当前状态转为Preference状态
intent.setClass(this, Preference.class);
startActivity(intent);
break;
}
case MENU_ABOUT:{
Intent intent = new Intent();
intent.setClass(this, Help.class);
startActivity(intent);
break;
}
case MENU_CONTACT:{
Intent intent = new Intent();
intent.setClass(this, about.class);
startActivity(intent);
break;
}
}
return super.onOptionsItemSelected(item);
}
//利用Handler对接受子线程发送的数据,并利用其配合主线程更新UI
private Handler mHandler = new Handler(){
public void handleMessage(Message msg) {
if (msg.what==1)
setContentView(myView);
}
};
}
四个按钮:
(1) 学习按钮(study.java+studyword.xml+studyword_main.xml)
package wordroid.activitys;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import wordroid.model.BookList;
import wordroid.model.R;
import wordroid.business.OperationOfBooks;
import wordroid.database.DataAccess;
import wordroid.model.WordList;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.os.Bundle;
import android.app.TabActivity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.view.WindowManager;
import android.view.View.OnClickListener;
import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.TabHost;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.TabHost.OnTabChangeListener;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Color;
import android.app.ListActivity;
public class study extends TabActivity implements TabHost.TabContentFactory{
/** Called when the activity is first created. */
String info = "hey";
//开启一个装载单词的容器和字符串的容器
public ArrayList<WordList> wordlist;
private ArrayList<String> listShould ;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//利用TabHost可以实现在一个屏幕间进行不同界面的版面切换
TabHost th = getTabHost();
//数据读取
DataAccess data = new DataAccess(this);
wordlist=data.QueryList("BOOKID ='"+DataAccess.bookID+"'", null);
listShould = new ArrayList<String>(wordlist.size());
for(int i=0;i<wordlist.size();i++){
//如果一个list没有学习过的话,将这个list添加进去
if (wordlist.get(i).getLearned().equals("0")){
listShould.add(wordlist.get(i).getList());
}
}
//利用内置的mysql查询到这本书
BookList book =data.QueryBook("ID ='"+DataAccess.bookID+"'", null).get(0);
//将标题设置为学习+这本书的书名
this.setTitle("学习-"+book.getName());
//利用Tab实现界面的跳转,同时,在布局上面遵从studyword_main
LayoutInflater.from(this).inflate(R.layout.studyword_main, th.getTabContentView(), true);
布局文件——studyword_main.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/FrameLayout01"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="@+id/TextView01"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=""></TextView>
<TextView
android:id="@+id/TextView02"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=""></TextView>
</FrameLayout>
//这里在装填两个Tab的同时,载入两张图片
th.addTab(th.newTabSpec("studid").setIndicator("未学过的LIST",study.this.getResources().getDrawable(R.drawable.not_learn)).setContent(this));
th.addTab(th.newTabSpec("all").setIndicator("所有的LIST",study.this.getResources().getDrawable(R.drawable.all)).setContent(this));
}
//创建一个Tab
public View createTabContent(String tag) {
ListView lv = new ListView(this);
LinearLayout ll = new LinearLayout(this);
ll.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.FILL_PARENT));
ll.setBackgroundDrawable(this.getResources().getDrawable(R.drawable.main_back));
ll.setOrientation(LinearLayout.VERTICAL);
TextView tv = new TextView(this);
//将背景设置为黑色
tv.setTextColor(Color.BLACK);
tv.setBackgroundDrawable(this.getResources().getDrawable(R.drawable.main_budget_lv_header));
ll.addView(tv);
ll.addView(lv);
lv.setCacheColorHint(0);
SimpleAdapter adapterAll = new SimpleAdapter(this, getData(tag), R.layout.list5, new String[]{"label","status","image"}, new int[]{R.id.label,R.id.status,R.id.list5_image});
SimpleAdapter adapterStudid = new SimpleAdapter(this, getData(tag), R.layout.list4, new String[]{"label","image"}, new int[]{R.id.label,R.id.list4_image});
//如果tag为all,那么将是对于所有的list
if(tag.equals("all")){
tv.setText(" 所有的LIST");
lv.setAdapter(adapterAll);
//这里监听对每一个list的点击情况
lv.setOnItemClickListener(new OnItemClickListener(){
public void onItemClick(AdapterView<?> arg0, View v, final int arg2,
long id) {
// TODO Auto-generated method stub
Intent intent = null;
//对于每一个list,已学习和未学习要启动不同的界面
if(wordlist.get(arg2).getLearned().equals("1")){
startStudy(arg2,2,1);
}
else
startStudy(arg2,2,0);
}
});
}
//如果Tag显示的不是all,将对应的是未学习过的list
else if(tag.equals("studid")){
tv.setText(" 未学习过的LIST");
lv.setAdapter(adapterStudid);
lv.setOnItemClickListener(new OnItemClickListener(){
//对于未学习的list,必然是0,所以这里没有必要像all_list一样判断,直接对于id标记为0
public void onItemClick(AdapterView<?> arg0, View v, int position,
long id) {
// TODO Auto-generated method stub
startStudy(position,1,0);
}
});
//这里,监听一个长按的响应,如果一段比较长的时间按住按钮不放的话,则标记为已经学习过
lv.setOnItemLongClickListener(new OnItemLongClickListener(){
public boolean onItemLongClick(AdapterView<?> arg0, View arg1,
final int arg2, long arg3) {
// TODO Auto-generated method stub
Dialog dialog = new AlertDialog.Builder(study.this)
.setIcon(R.drawable.dialog_icon)
.setTitle("操作")
.setItems(new String[]{"标记为已学习"}, new DialogInterface.OnClickListener(){
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
if (which==0){
DataAccess data = new DataAccess(study.this);
WordList labelList = wordlist.get(Integer.parseInt(listShould.get(arg2))-1);
labelList.setLearned("1");
Calendar cal = Calendar.getInstance();
SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd");
String date=f.format(cal.getTime());
labelList.setLearnedTime(date);
labelList.setReview_times("0");
labelList.setReviewTime("");
data.UpdateList(labelList);
Intent intent = new Intent();
intent.setClass(study.this, study.class);
finish();
startActivity(intent);
}
}
})
.setPositiveButton("取消", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
}
})
.create();
dialog.show();
return false;
}
});
}
return ll;
}
private List<Map<String, Object>> getData(String tag) {
// TODO Auto-generated method stub
List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
//这里,对于未学习的情况
if (tag.equals("studid")){
//开一个Map,对于没有学习过的LIST,装载到list中
for (int i=0;i<wordlist.size();i++){
if (wordlist.get(i).getLearned().equals("0")){
Map<String,Object> map = new HashMap<String,Object>();
map.put("label"," LIST-"+wordlist.get(i).getList());
map.put("image", android.R.drawable.btn_star_big_on);
list.add(map);
}
}
}
//这里,对于所有list的情况,在界面的布局的时候,要分未学习和已经学习两种情况进行讨论,标注都是不一样的
else if(tag.equals("all")){
for (int i=0;i<wordlist.size();i++){
if (wordlist.get(i).getLearned().equals("0")){
Map<String,Object> map = new HashMap<String,Object>();
map.put("label"," LIST-"+wordlist.get(i).getList());
map.put("status", "未学习");
map.put("image", android.R.drawable.btn_star_big_on);
list.add(map);
}
else if(wordlist.get(i).getLearned().equals("1")){
Map<String,Object> map = new HashMap<String,Object>();
map.put("label"," LIST-"+wordlist.get(i).getList());
map.put("status", "已学习");
map.put("image", android.R.drawable.btn_star_big_off);
list.add(map);
}
}
}
return list;
}
//设置“开始学习”这一函数
private void startStudy(final int arg2,final int tag,final int check) {
//对于所有的list而言
if(tag==2){
//如果已经学习过这个list的话
if(check==1){
//提示该list已经学习过,这里的arg2+1为什么要+1呢?是因为数组的下标是从0开始计数的,而这里要告知的是list的编号,所以+1
Dialog dialog = new AlertDialog.Builder(study.this)
.setIcon(R.drawable.dialog_icon)
.setTitle("提示")
.setMessage("此单元已学过,重新学习将清除学习进度,是否继续?\nLIST-"+(arg2+1))
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
/* User clicked OK so do some stuff */
Intent intent = new Intent();
//确定之后,载入数据,并且跳转到studyWord这个activity中
Bundle bundle = new Bundle();
bundle.putString("list", String.valueOf(arg2+1));
intent.setClass(study.this, studyWord.class);
intent.putExtras(bundle);
finish();
startActivity(intent);
}
})
//如果是取消的话,则保持不变
.setNeutralButton("取消", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
/* User clicked OK so do some stuff */
}
}).create();
dialog.show();
}
else{
//对于all_list中的还没有学习的内容,则进行开始学习
Dialog dialog = new AlertDialog.Builder(study.this)
.setIcon(R.drawable.dialog_icon)
.setTitle("开始学习:")
.setMessage("LIST-"+(arg2+1))
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
/* User clicked OK so do some stuff */
Intent intent = new Intent();
Bundle bundle = new Bundle();
bundle.putString("list", String.valueOf(arg2+1));
intent.setClass(study.this, studyWord.class);
intent.putExtras(bundle);
finish();
startActivity(intent);
}
})
//选择取消的话,则仅仅消除对话框,退回到原来的状态
.setNeutralButton("取消", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
/* User clicked OK so do some stuff */
}
}).create();
dialog.show();
}
}
//对于未学习状态的Tab来说,弹入的Dialog是一样的
else if(tag==1)
{
Dialog dialog = new AlertDialog.Builder(study.this)
.setIcon(R.drawable.dialog_icon)
.setTitle("开始学习:")
.setMessage("LIST-"+listShould.get(arg2))
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
/* User clicked OK so do some stuff */
finish();
Intent intent = new Intent();
Bundle bundle = new Bundle();
bundle.putString("list", listShould.get(arg2));
intent.setClass(study.this, studyWord.class);
intent.putExtras(bundle);
startActivity(intent);
}
})
.setNeutralButton("取消", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
/* User clicked OK so do some stuff */
}
}).create();
dialog.show();
}
}
//这是已经被注释掉的代码,因为无论position处于哪个位置,其都是从study这个activity跳转到studyWord这个activity
// protected void onListItemClick(ListView l,View v,int position,long id){
// Intent intent = null;
// switch(position){
// case 0:
// intent = new Intent(study.this,studyWord.class);
// startActivity(intent);
// break;
// case 1:
// intent = new Intent(study.this,studyWord.class);
// startActivity(intent);
// break;
// }
// }
}
(1的延伸)就是点击进入具体的list学习之后所对应的布局界面以及逻辑实现(studyword.xml+studyWord.java)
Studyword.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
xmlns:android="http://schemas.android.com/apk/res/android"
android:background="@drawable/main_back"
>
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="20px"
android:id="@+id/study_title"
android:layout_alignParentTop="true"
android:background="@drawable/study_title"
android:gravity="center"
>
<TextView android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="开始学习"
android:textColor="#000000"
/>
</LinearLayout>
<LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20px"
android:layout_below="@id/study_title"
android:gravity="left"
android:background="@drawable/panel">
<ImageButton
android:id="@+id/ImageButton01"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
//这实际上是一个图片资源,类似于谷歌的数字语音标记,表示目前还是对话
android:src="@android:drawable/ic_btn_speak_now" />
<TextView android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/spelling"
android:textColor="#000000"
android:textSize="22sp"
/>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/info"
android:layout_gravity="left"
android:layout_below="@id/spelling"
android:textSize="22sp"
android:textColor="#000000" />
</LinearLayout>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_alignParentBottom="true"
>
//将布局设置为水平的,并放置三个按钮——(1)上一个(2)加入生词本(3)下一个
<Button
android:id="@+id/beforeone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="上一个"
android:textColor="#ffffff"
android:textSize="14sp"
android:background="@drawable/study_btns"></Button>
<Button
android:id="@+id/add"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="加入生词本"
android:textSize="14sp"
android:textColor="#ffffff"
android:background="@drawable/study_btns"
></Button>
<Button
android:id="@+id/nextone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="下一个"
android:textSize="14sp"
android:textColor="#ffffff"
android:background="@drawable/study_btns"
></Button>
</LinearLayout>
</RelativeLayout>
关于其按钮的内部逻辑实现(studyWord.java)
package wordroid.activitys;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Locale;
import wordroid.model.R;
import wordroid.model.Word;
import wordroid.business.OperationOfBooks;
import wordroid.business.TTS;
import wordroid.database.DataAccess;
import wordroid.model.WordList;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Typeface;
import android.os.Bundle;
import android.speech.tts.TextToSpeech;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.TextView;
import android.widget.Toast;
public class studyWord extends Activity implements OnClickListener{
//定义如下的组件(listnum,current,numoflist都是用于统计记录的,相当于计数器)
private TextView tv;
private TextView tv2;
private String listnum;
private int currentnum;
private int numoflist;
private ArrayList<Word> list = new ArrayList<Word>();
//这里定义在界面上的各种组件,方便于使用
private Button add;
private Button nextone;
private Button beforeone;
private TextView spelling;
private TextView info;
private ImageButton speak;
private TextToSpeech tts;
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.studyword);
currentnum=0;
Intent intent = getIntent();
Bundle b = intent.getExtras();
String name = b.getString("list");
listnum=name;
//设置标题
this.setTitle("学习LIST-"+name);
DataAccess data = new DataAccess(this);
list=data.QueryWord("LIST = '"+name+"'", null);
numoflist = list.size();
initWidgets();
UpdateView();
}
//初始化各种在布局中声明的按钮
private void initWidgets() {
// TODO Auto-generated method stub
this.add=(Button) this.findViewById(R.id.add);
add.setOnClickListener(this);
this.info=(TextView) this.findViewById(R.id.info);
this.beforeone=(Button) this.findViewById(R.id.beforeone);
beforeone.setOnClickListener(this);
this.nextone=(Button) this.findViewById(R.id.nextone);
nextone.setOnClickListener(this);
this.spelling=(TextView) this.findViewById(R.id.spelling);
Typeface tf = Typeface.createFromAsset(getAssets(), "fonts/SEGOEUI.TTF");
info.setTypeface(tf);
this.speak=(ImageButton)this.findViewById(R.id.ImageButton01);
tts = new TextToSpeech(this, ttsInitListener);
speak.setOnClickListener(this);
DisplayMetrics dm = new DisplayMetrics();
dm = getApplicationContext().getResources().getDisplayMetrics();
//最下面的三个按钮,其中的每个按钮占据三分之一的宽度
int screenWidth = dm.widthPixels;
add.setWidth(screenWidth/3);
beforeone.setWidth(screenWidth/3);
nextone.setWidth(screenWidth/3);
}
//对文字与语音转换的初始监听,这里引用了其它包中的SDK文件
private TextToSpeech.OnInitListener ttsInitListener = new TextToSpeech.OnInitListener()
{
public void onInit(int status)
{
// TODO Auto-generated method stub
//这里读取设置的数据,默认的是uk,也就是英语发音,但是,如果将category,也就是分类从1改为2,则将uk改变为us,也就是由英语发音改为美语发音
Locale loc= new Locale("uk");
SharedPreferences setting = getSharedPreferences("wordroid.model_preferences", MODE_PRIVATE);
if(setting.getString("category", "1").equals("2"))
loc = new Locale("us");
/* 检查是否支持输入的时区 */
if (tts.isLanguageAvailable(loc) == TextToSpeech.LANG_AVAILABLE)
{
/* 设定语言 */
tts.setLanguage(loc);
}
tts.setOnUtteranceCompletedListener(ttsUtteranceCompletedListener);
}
};
private TextToSpeech.OnUtteranceCompletedListener ttsUtteranceCompletedListener = new TextToSpeech.OnUtteranceCompletedListener()
{
public void onUtteranceCompleted(String utteranceId)
{
}
};
//这里指示对三个按钮的监听响应
public void onClick(View v) {
Log.i("3", "3");
//在调试器中先刷新一下,前后输出3,3
this.UpdateView();
Log.i("3", "3");
//点击下一个的话,如果当前的单词小于这里list中的总单词的编号的话,将当前的单词数++,同时更新整个显示界面
if (v==nextone){
if(currentnum<numoflist){
currentnum++;
this.UpdateView();
}
}
else if (v==add){
DataAccess data = new DataAccess(studyWord.this);
ArrayList<Word> attention = new ArrayList<Word>();
attention=data.QueryAttention("SPELLING ='"+list.get(currentnum).getSpelling()+"'", null);
if (attention.size()==0){
data.InsertIntoAttention(list.get(currentnum));
Toast.makeText(studyWord.this, "已加入生词本", Toast.LENGTH_SHORT).show();
}
else Toast.makeText(studyWord.this, "生词本中已包含这个单词!", Toast.LENGTH_SHORT).show();
}
//如果点击上一个单词的按钮的话,将目前的单词编号--,顺便刷新整个界面
else if(v==beforeone){
currentnum--;
this.UpdateView();
}
Log.i("3", "3");
//这里表示对语音按钮的响应
if (v==speak){
//调用SDK中提供的函数,也就是先得到那个list中的单词,得到拼写,之后加入到TextToSpeech队列中,最后读出来 tts.speak(list.get(currentnum).getSpelling(),TextToSpeech.QUEUE_ADD,
null);
}
Log.i("3", "3");
}
//对于实体按键进行一些处理,如果在学习的中途退出,则响应学习还没有完成的对话框,并跳转到学习按钮的前置界面,也就是studyWord这个Activity
public boolean onKeyDown(int keyCode, KeyEvent event) {
// TODO Auto-generated method stub
if (keyCode == KeyEvent.KEYCODE_BACK) {
Dialog dialog = new AlertDialog.Builder(this)
.setIcon(R.drawable.dialog_icon)
.setTitle("学习未完成")
.setMessage("你确定现在结束学习吗?这将导致本次学习无效!")
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
/* User clicked OK so do some stuff */
tts.shutdown();
finish();
Intent intent = new Intent();
intent.setClass(studyWord.this, study.class);
startActivity(intent);
}
})
.setNegativeButton("取消", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
/* User clicked OK so do some stuff */
}
}).create();
dialog.show();
}
return true;
}
//每次更新的时候,系统自动完成的一些判断任务
private void UpdateView() {
//如下是两个潜规则,如果当前单词的编号为0的话,则将“上一个”
按钮的可见状态设置为false,如果当前单词的编号不为0的话,则将“上一个”按钮的可见状态设置为true
if(currentnum==0){
beforeone.setEnabled(false);
}
else if(currentnum>0){
beforeone.setEnabled(true);
}
//将设置中存储的一些自定义情况重新导入到这里,进行分析
SharedPreferences setting = getSharedPreferences("wordroid.model_preferences", MODE_PRIVATE);
//如果这里的语音功能关闭的话,启动线程,休眠500毫秒,并将该单词所对应的一段语音移除
if(setting.getBoolean("iftts", false)){
Thread thread =new Thread(new Runnable(){
public void run(){
try {
Thread.sleep(500);
tts.speak(list.get(currentnum).getSpelling(),TextToSpeech.QUEUE_FLUSH,
null);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
thread.start();
}
//这里表示语音功能没有移除的情况,如果是这样的话,分两种情况讨论,一种是单词没有告罄,一种是单词已经告罄了
// TODO Auto-generated method stub
//单词没有告罄的时候,给出单词的四种属性(TextView),(1)单词的数字编号(2)单词的字母(3)单词的音标拼写(4)单词的意思
if (currentnum<numoflist){
spelling.setText(list.get(currentnum).getID()+"."+list.get(currentnum).getSpelling());
info.setText(list.get(currentnum).getPhonetic_alphabet()+"\n"+list.get(currentnum).getMeanning());
}
//当单词已经告罄的时候,标注已经学习,将复习的次数设置成0,并记录当前的时间,录入list,并且将currentnum--(该list已经从未学习的list中移除)
else if(currentnum>=numoflist){
DataAccess data = new DataAccess(this);
WordList wordlist=data.QueryList("BOOKID ='"+DataAccess.bookID+"'AND LIST = '"+listnum+"'", null).get(0);
wordlist.setLearned("1");
wordlist.setReview_times("0");
wordlist.setReviewTime("");
Calendar cal = Calendar.getInstance();
SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd");
String date=f.format(cal.getTime());
wordlist.setLearnedTime(date);
data.UpdateList(wordlist);
currentnum--;
//同时,告知这里list已经完成,将关于这个list的tts关闭,转到学习按钮的前置界面,显示对话框
Dialog dialog = new AlertDialog.Builder(this)
.setIcon(R.drawable.dialog_icon)
.setTitle("学习已完成")
.setMessage("您可以依照复习计划进行本单元的复习")
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
/* User clicked OK so do some stuff */
tts.shutdown();
finish();
Intent intent = new Intent();
intent.setClass(studyWord.this, study.class);
startActivity(intent);
}
}).create();
dialog.show();
}
}
//对状态销毁时进行的一些设置,同android的生命周期类似
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
}
}
(2) 复习(Review.java+ReviewMain.java+reviewlayout.xml)
如图所示,两个以java为扩展名的文件,以及一个以xml为扩展名的布局文件,关于复习按钮,无论是其前置界面还是复习界面和学习按钮中弹出的界面大同小异,所以暂时不予以处理(其中的一些复习功能我在使用这款软件的时候搞得还不是很清楚,有待研究,有待研究)。
布局界面和学习界面的两个极为类似,这里就不列出xml文件了
核心算法:
(1)对于复习计划的时间记录
else if (tag.equals("plan")){
ArrayList<ArrayList<String>> result = new ArrayList<ArrayList<String>>();
OperationOfBooks OOB = new OperationOfBooks();
result=OOB.GetPlan(week, this);
for (int i=0;i<7;i++){
Map<String,Object> map = new HashMap<String,Object>();
map.put("date", result.get(i).get(0));
SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd");
Date date = null;
try {
date = f.parse(result.get(i).get(0));
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Calendar calendar=Calendar.getInstance();
calendar.setTime(date);
String lists="复习内容:";
String day="星期";
switch(calendar.get(Calendar.DAY_OF_WEEK)){
case 1:
day+="一 ";
break;
case 2:
day+="二 ";
break;
case 3:
day+="三 ";
break;
case 4:
day+="四 ";
break;
case 5:
day+="五 ";
break;
case 6:
day+="六 ";
break;
case 7:
day+="日 ";
break;
}
map.put("day",day );
for (int j=1;j<result.get(i).size();j++){
lists+=result.get(i).get(j)+" ";
}
if(result.get(i).size()==1)map.put("image", R.drawable.plan_off);
else map.put("image", R.drawable.plan_on);
map.put("lists", lists);
list.add(map);
}
}
return list;
}
(2)四个状态,定义一个融入键值的map映射,对于每个复习状态插入一个image,对于每个状态有每个状态进入的条件
else if(tag.equals("alllists")){
for (int i=0;i<wordlist.size();i++){
Map<String,Object> map = new HashMap<String,Object>();
map.put("label", "LIST-"+wordlist.get(i).getList());
if (wordlist.get(i).getLearned().equals("0")){
map.put("state", "状态:未学习 ");
map.put("image", android.R.drawable.btn_star_big_off);
}
else if (wordlist.get(i).getShouldReview().equals("1")){
map.put("state", "状态:该复习了! ");
map.put("image", android.R.drawable.btn_star_big_on);
}
else if (Integer.parseInt(wordlist.get(i).getReview_times())>=5){
map.put("state", "状态:复习已完成! ");
map.put("image", android.R.drawable.btn_star_big_off);
}
else{
map.put("state", "状态:暂不需复习 ");
map.put("image", android.R.drawable.btn_star_big_off);
}
list.add(map);
}
}
(3) 这里根据学生的判断(这里要求学生具备一定的客观性)来判定学生是否需要复习以及在什么时候复习
public void onClick(View v) {
// TODO Auto-generated method stub
//点击语音按钮,给出tts转换,发音
if (v==speak){
tts.speak(list.get(currentnum).getSpelling(),TextToSpeech.QUEUE_ADD,
null);
}
//点击我记得,那么将记得和不记得这两个按钮隐去,并将记对了和记错了两个按钮重新展现出来,将单词的音标以及意思利用info的setText方法显示出来
if (v==remember){
wrong.setVisibility(View.VISIBLE);
right.setVisibility(View.VISIBLE);
remember.setVisibility(View.GONE);
notremember.setVisibility(View.GONE);
info.setText(list.get(currentnum).getPhonetic_alphabet()+"\n"+list.get(currentnum).getMeanning());
}
//如果不记得的话,则隐去记得和不记得按钮,并显示出下一个的按钮,并给出音标和意思
if (v==notremember){
nextone.setVisibility(View.VISIBLE);
remember.setVisibility(View.GONE);
notremember.setVisibility(View.GONE);
info.setText(list.get(currentnum).getPhonetic_alphabet()+"\n"+list.get(currentnum).getMeanning());
}
//如果答对了,则将当前的单词编号++,并且刷新界面
if (v==right){
currentnum++;
this.UpdateView();
}
//如果答错了或者选择下一个的话,则将当前list中的当前单词赋给word,并载入到list中,转到下一个单词,并且刷新界面
if (v==wrong||v==nextone){
Word word = new Word();
word=list.get(currentnum);
list.add(word);
currentnum++;
this.UpdateView();
}
//这里如果选择加入生词本的话,在生词本中查找是否有相同的单词,如果有的话,则显示一个短暂的Toast,说明生词本里面已经包含了这个单词,而如果没有的话,则显示已经加入了生词本
if (v==add){
DataAccess data = new DataAccess(Review.this);
ArrayList<Word> attention = new ArrayList<Word>();
attention=data.QueryAttention("SPELLING ='"+list.get(currentnum).getSpelling()+"'", null);
if (attention.size()==0){
data.InsertIntoAttention(list.get(currentnum));
Toast.makeText(Review.this, "已加入生词本", Toast.LENGTH_SHORT).show();
}
else Toast.makeText(Review.this, "生词本中已包含这个单词!", Toast.LENGTH_SHORT).show();
}
}
(3)测试按钮
(A)前置界面——这里隐去对布局文件和逻辑文件的说明
package wordroid.activitys;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import wordroid.database.DataAccess;
import wordroid.model.BookList;
import wordroid.model.WordList;
import wordroid.model.R;
import android.app.ListActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.ListView;
import android.widget.SimpleAdapter;
public class TestList extends ListActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
DataAccess dataAccess = new DataAccess(this);
//从数据库中导入图书
BookList book =dataAccess.QueryBook("ID ='"+DataAccess.bookID+"'", null).get(0);
//设置标题
this.setTitle("测试-"+book.getName());
super.onCreate(savedInstanceState);
this.setContentView(R.layout.test_list);
//这里开启第一个布局界面
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:background="@drawable/main_back">
<TextView
android:layout_width="fill_parent"
android:id="@+id/test_title"
android:layout_height="wrap_content"
android:textSize="14px"
android:text=" 选择测试单元:"
android:textColor="#000000"
android:background="@drawable/main_budget_lv_header"
/>
<ListView
android:id="@android:id/list"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
</LinearLayout>
}
//对暂停状态的撤销
@Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
//这里开启了第二个布局,适配器中,每一个组合为两个字符串(string)和一个图片(image)
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
xmlns:android="http://schemas.android.com/apk/res/android"
android:background="@drawable/list_bg"
>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/test_list_image"/>
<LinearLayout
android:layout_toRightOf="@id/test_list_image"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/test_list_item_1"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="20px"
android:textColor="#000000"
></TextView>
<TextView
android:id="@+id/test_list_item_2"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="16px"
android:textColor="#000000"
></TextView>
</LinearLayout>
</RelativeLayout>
SimpleAdapter adapter = new SimpleAdapter(this,getData(),R.layout.test_list_item,
new String[]{"word_list","last_score","image"},
new int[]{R.id.test_list_item_1,R.id.test_list_item_2,R.id.test_list_image});
setListAdapter(adapter);
}
//得到数据的函数,定义一个哈希表,取得最高正确率,如果没有的话,将五角星设置为灰色的,存在的话,将其点亮。无论是否存在,将其加入到list中,对于最高正确率的计算,也就是getBestScore()函数,也是这款软件的一个亮点吧
private List<Map<String, Object>> getData() {
// TODO Auto-generated method stub
List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
DataAccess dataAccess = new DataAccess(this);
ArrayList<WordList> wordList = dataAccess.QueryList("BOOKID = '"+DataAccess.bookID+"'", null);
System.out.println("size:" + wordList.size());
Map<String, Object> map;
for (int i = 0; i < wordList.size(); i++) {
map = new HashMap<String, Object>();
map.put("word_list", "List" + wordList.get(i).getList());
map.put("last_score", "最高正确率: " + wordList.get(i).getBestScore() + "%");
if(wordList.get(i).getBestScore().equals(""))map.put("image", android.R.drawable.btn_star_big_off);
else map.put("image", android.R.drawable.btn_star_big_on);
list.add(map);
}
return list;
}
//监听是对哪一个list的响应,并将其转入Test这个Activity
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
// TODO Auto-generated method stub
super.onListItemClick(l, v, position, id);
Intent intent = new Intent();
intent.setClass(TestList.this, Test.class);
intent.putExtra("wordList", ""+position);
TestList.this.startActivity(intent);
System.out.println(position);
}
}
(B)测试界面
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@drawable/main_back"
xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="20px"
android:id="@+id/test_title"
android:layout_alignParentTop="true"
android:background="@drawable/study_title"
android:gravity="center"
>
//标题为单词测验
<TextView android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="单词测验"
android:textColor="#000000"
/>
</LinearLayout>
<LinearLayout
//如下的一个线性布局,表明单词和单词的音标拼写
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="@id/test_title"
android:layout_marginTop="10px"
android:background="@drawable/panel">
<TextView android:id="@+id/Spelling"
android:textSize="24dp"
android:textColor="#000000"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
//定义一组(四个)RadioButton,竖直放置,每一个RadioButton后面的文字为单词的意思
<RadioGroup android:id="@+id/Meanning"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_x="3px"
android:layout_y="4px">
<RadioButton android:id="@+id/RadioButton0"
android:textColor="#000000"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<RadioButton android:id="@+id/RadioButton1"
android:textColor="#000000"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<RadioButton android:id="@+id/RadioButton2"
android:textColor="#000000"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<RadioButton android:id="@+id/RadioButton3"
android:textColor="#000000"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RadioGroup>
//水平地放置三个按钮(实际上,每次只有两个按钮显示出来,无论对于什么状态来说,总是有一个按钮处于隐藏状态)
</LinearLayout>
<LinearLayout android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
>
<Button
android:id="@+id/NextButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#ffffff"
android:background="@drawable/study_btns"
android:text="下一个"></Button>
<Button
android:id="@+id/OverButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/study_btns"
android:textColor="#ffffff"
android:text="结束"></Button>
<Button
android:id="@+id/test_addintoattention"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#ffffff"
android:background="@drawable/study_btns"
android:text="加入生词本"></Button>
</LinearLayout>
</RelativeLayout>
(C)逻辑实现——这一点,类似于我们的“练习功能”,在算法上也几乎是相同的,引入的是随机数的那种形式
package wordroid.activitys;
import java.util.ArrayList;
import wordroid.database.DataAccess;
import wordroid.model.BookList;
import wordroid.model.R;
import wordroid.model.Word;
import wordroid.model.WordList;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Typeface;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.View;
import android.widget.Button;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.TextView;
import android.widget.Toast;
public class Test extends Activity {
//定义各种组件
TextView spelling;
RadioGroup meaning;
RadioButton meaning0, meaning1, meaning2, meaning3;
Button nextBtn, overBtn, attention;
ArrayList<Word> list,allList;
//定义各种变量,用法之后我会提到
int allListLength;
int listLength;
int[] opt;
int currentId;
int rightAns;
int score = 0;
boolean isCheck;
Toast toast;
int[] rand;
DataAccess dataAccess;
WordList wordList;
int wordListInt;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
//开启test.xml这一布局
super.onCreate(savedInstanceState);
this.setContentView(R.layout.test);
//获取数据
Intent intent = getIntent();
String value = intent.getStringExtra("wordList");
//这里为了鲁棒性的考虑,多开设一个单元的空间
wordListInt = Integer.parseInt(value) + 1;
//设置标题
this.setTitle("测试LIST-"+wordListInt);
dataAccess = new DataAccess(this);
allList = dataAccess.QueryWord(null, null);
list = dataAccess.QueryWord("LIST='" + wordListInt + "'", null);
listLength = list.size();
allListLength = allList.size();
System.out.println("listLength2 " + listLength);
//这里设置一个随机数
rand = random();
//这里给出音标的TextView
spelling = (TextView) findViewById(R.id.Spelling);
Typeface tf = Typeface.createFromAsset(getAssets(), "fonts/SEGOEUI.TTF");
spelling.setTypeface(tf);
//设置一个定义为meanning的RadioGroup,并且排列出四个RadioButton
meaning = (RadioGroup) findViewById(R.id.Meanning);
meaning0 = (RadioButton) findViewById(R.id.RadioButton0);
meaning1 = (RadioButton) findViewById(R.id.RadioButton1);
meaning2 = (RadioButton) findViewById(R.id.RadioButton2);
meaning3 = (RadioButton) findViewById(R.id.RadioButton3);
//从这里可以看出,设置两个button,并且排列在尾部,并且将“加入生词库”这个button插入,其中,nextBtn(下一个按钮)暂时覆盖overBtn(结束按钮),当整个list读完之后,将nextBtn隐藏,将overBtn显露出来
nextBtn = (Button) findViewById(R.id.NextButton);
overBtn = (Button) findViewById(R.id.OverButton);
overBtn.setVisibility(View.GONE);
DisplayMetrics dm = new DisplayMetrics();
dm = getApplicationContext().getResources().getDisplayMetrics();
int screenWidth = dm.widthPixels;
nextBtn.setWidth(screenWidth/2);
overBtn.setWidth(screenWidth/2);
this.attention= (Button) this.findViewById(R.id.test_addintoattention);
attention.setWidth(screenWidth/2);
this.attention.setOnClickListener(new Button.OnClickListener(){
//同理,在每次将单词加入生词库的同时,判断一下这个单词是否在生词库里面,并根据不同的情况作出判断
public void onClick(View v) {
DataAccess data = new DataAccess(Test.this);
ArrayList<Word> attention = new ArrayList<Word>();
attention=data.QueryAttention("SPELLING ='"+list.get(rand[currentId]).getSpelling()+"'", null);
if (attention.size()==0){
data.InsertIntoAttention(list.get(rand[currentId]));
Toast.makeText(Test.this, "已加入生词本", Toast.LENGTH_SHORT).show();
}
else Toast.makeText(Test.this, "生词本中已包含这个单词!", Toast.LENGTH_SHORT).show();
}
});
//这里给出了一种算法,每次可以计算出最好的成绩,并且以对话框的形式回复出来
overBtn.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v) {
// TODO Auto-generated method stub
ArrayList<WordList> wordLists = dataAccess.QueryList("BOOKID = '"+DataAccess.bookID+"'and LIST='" + wordListInt + "'",null);
wordList = wordLists.get(0);
String bestScore = wordList.getBestScore();
System.out.println("bestScore" + bestScore);
//如果这个list还没有测验过的话,就直接将初始值作为最佳的记录
if (bestScore.equals("")) {
wordList.setBestScore(""+(score*100/listLength));
} else {
int bestScoreInt = Integer.parseInt(bestScore);
//如果这个list已经被测验过,而且目前检验的最高值高于当前的bestScoreInt的话,就将其更新,并且将记录存入数据库中
if (bestScoreInt < (score*100/listLength)) {
wordList.setBestScore(""+(score*100/listLength));
}
}
dataAccess.UpdateList(wordList);
//弹出一个对话框,输出最后的结果,并且对返回按钮设置监听,返回到前端界面
Dialog dlg = new AlertDialog.Builder(Test.this)
.setTitle("测试结果")
.setMessage("共" + listLength + "题,做对" + score + "题, 正确率" + (score*100/listLength) + "%")
.setPositiveButton("返回", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
// Intent intent = new Intent();
// intent.putExtra("testIntent", "123");
// intent.setClass(Test.this, Main.class);
// Test.this.startActivity(intent);
finish();
}
}).create();
dlg.show();
}
});
//产生一个随机的问题
productQues(rand[currentId]);
//对于问题的选择的监听
meaning.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
public void onCheckedChanged(RadioGroup group, int checkedId) {
// TODO Auto-generated method stub
// System.out.println("currentId " + currentId);
// System.out.println("listLength " + listLength);
if (isCheck) {
//选择之后,就将isCheck重新设置为false
isCheck = false;
//判断选择是否正确,正确的话分数增加,无论正确还是错误,给出Toast,对于错误的选择,给出单词的准确意思
switch (rightAns) {
case 0:
if ( checkedId == meaning0.getId() ) {
score++;
DisplayToast("正确");
} else {
DisplayToast("错误,正确答案是 " + allList.get(opt[0]).getMeanning());
}
break;
case 1:
if ( checkedId == meaning1.getId() ) {
score++;
DisplayToast("正确");
} else {
DisplayToast("错误,正确答案是 " + allList.get(opt[1]).getMeanning() );
}
break;
case 2:
if ( checkedId == meaning2.getId() ) {
score++;
DisplayToast("正确");
} else {
DisplayToast("错误,正确答案是 " + allList.get(opt[2]).getMeanning() );
}
break;
case 3:
if ( checkedId == meaning3.getId() ) {
score++;
DisplayToast("正确");
} else {
DisplayToast("错误,正确答案是 " + allList.get(opt[3]).getMeanning() );
}
break;
}
//选择之后,将四个RadioButton重新设置为非使能状态
meaning0.setEnabled(false);
meaning1.setEnabled(false);
meaning2.setEnabled(false);
meaning3.setEnabled(false);
//这里判断出了下面两个按钮应该为什么,唯一的区别就是看看目前的单词编号是否为最后一个单词
if ( currentId == (listLength-1) ) {
nextBtn.setEnabled(false);
overBtn.setVisibility(View.VISIBLE);
attention.setVisibility(View.VISIBLE);
} else {
nextBtn.setVisibility(View.VISIBLE);
attention.setVisibility(View.VISIBLE);
}
}
}
});
//选择下一个按钮之后,将当前的编号++,再随机地产生一个问题
nextBtn.setOnClickListener(new Button.OnClickListener(){
public void onClick(View v) {
// TODO Auto-generated method stub
currentId++;
productQues(rand[currentId]);
}
});
}
//这是随机地产生一个问题的整个过程
public void productQues(int id){
//随机选择一个单词
Word word = list.get(id);
//调用options函数,具体的算法在后面给出
opt = options(word.getID());
//利用setText方法得到单词的拼写和音标
spelling.setText(word.getSpelling()+" "+word.getPhonetic_alphabet());
//得到各个单词的意思
meaning0.setText(allList.get(opt[0]).getMeanning());
meaning1.setText(allList.get(opt[1]).getMeanning());
meaning2.setText(allList.get(opt[2]).getMeanning());
meaning3.setText(allList.get(opt[3]).getMeanning());
//将原来的选择清空处理
meaning.clearCheck();
//重新开启每个按钮的使能状态
meaning0.setEnabled(true);
meaning1.setEnabled(true);
meaning2.setEnabled(true);
meaning3.setEnabled(true);
//将下面的两个button隐藏
nextBtn.setVisibility(View.GONE);
attention.setVisibility(View.GONE);
isCheck = true;
}
//该算法的原理是先通过随机数得到一个单词(在整个list中的),一共需要得到四个这样的单词,如果不是第一个的话,还需要判断这个单词与前面的单词是否重复,判断的方法和哈希散列的线性查找法类似,就是不断i--,直到找出一个合适的单词的位置
public int[] options (String wordId) {
int id = Integer.parseInt(wordId);
int optionNum[] = new int[4];
for (int i = 0; i < 4; i++) {
optionNum[i] = (int)(Math.random()*allList.size());
if ( i > 0){
for (int j = 0; j < i; j++) {
if ( optionNum[j] == optionNum[i]) {
i--;
break;
}
}
}
}
//我们先假设不存在一个正确的答案(因为这四个单词不一定有某个单词与这个id编号的单词是匹配的)
boolean isExist = true;
for (int k = 0; k < 4; k++) {
if ( optionNum[k] == (id-1) )
{
//如果存在的话,就将isExist设置为false
isExist = false;
break;
}
}
//否则的话,需要继续去寻找人为地将该单词的id赋予一个选项,正确选项的下标rightAns为随机生成的一个0—4之间的一个数字
if (isExist) {
rightAns = (int)(Math.random()*4);
optionNum[rightAns] = id-1;
}
return optionNum;
}
public int[] random() {
int temp;
int temp1;
int rand[];
//首先,将一个list(30个单词)的下标按照顺序装入到rand数组中
rand = new int[listLength];
for (int i = 0 ; i < listLength; i++) {
rand[i] = i;
}
//低于每一个数组,交换30次,我在斗地主AI中也有讲过这种“洗牌”的方式,有许多算法都可以实现random的随机功能
for (int i = 0 ; i < listLength; i++) {
temp = rand[i];
temp1 = (int)(Math.random()*listLength);
rand[i] = rand[temp1];
rand[temp1] = temp;
}
//在控制台输出这30个数组单元的值,以便于调试
for (int i = 0 ; i < listLength; i++) {
System.out.println(rand[i]);
}
//返回数组单元
return rand;
}
//利用短暂的Toast显示一段字符串
public void DisplayToast(String str) {
toast = Toast.makeText(this, str, Toast.LENGTH_SHORT);
toast.show();
}
}
(4)最后一个按钮,也就是生词本
(A)首先看布局:attention.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:background="@drawable/main_back">
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="14px"
android:text=" 生词本:"
android:textColor="#000000"
android:background="@drawable/main_budget_lv_header"
/>
<ListView
android:id="@android:id/list"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
</LinearLayout>
(B)逻辑实现:Attention.java
package wordroid.activitys;
import java.util.ArrayList;
import wordroid.database.DataAccess;
import wordroid.model.R;
import wordroid.model.Word;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ListActivity;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ListView;
public class Attention extends ListActivity {
private ArrayList<Word> list;
public static final int MENU_ADD = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
//设置标题,打开布局文件,并设置适配器
this.setTitle("生词本");
this.setContentView(R.layout.attention);
setAdapter();
}
//这里只有一个菜单按钮,响应MENU_ADD,添加新单词的功能
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// TODO Auto-generated method stub
menu.add(0, MENU_ADD, 0, "添加新单词");
return true;
}
//设置对菜单按钮的响应,转入到EditWord这个Activity中,并且设置一个bundle类,在两个Activity之间传递数据
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// TODO Auto-generated method stub
switch(item.getItemId()){
case MENU_ADD:{
Intent intent = new Intent();
Bundle bundle = new Bundle();
bundle.putString("action", "add");
intent.putExtras(bundle);
intent.setClass(Attention.this, EditWord.class);
startActivity(intent);
break;
}
}
return super.onOptionsItemSelected(item);
}
//对于每一个list的点击,都会弹出这样一个对话框
@Override
protected void onListItemClick(ListView l, View v, final int position, long id) {
// TODO Auto-generated method stub
super.onListItemClick(l, v, position, id);
Dialog dialog = new AlertDialog.Builder(Attention.this)
.setIcon(R.drawable.dialog_icon)
.setTitle("操作")
.setItems(new String[]{"编辑该单词","从生词本中删除"}, new DialogInterface.OnClickListener(){
//对对话框中的两个按钮的选择
public void onClick(DialogInterface dialog, int which) {
switch(which){
case 0:{
//转入编辑单词的Activity(EditWord),并且传入一些数据
Intent intent = new Intent();
intent.setClass(Attention.this, EditWord.class);
Bundle bundle = new Bundle();
bundle.putString("action", "edit");
bundle.putString("id", list.get(position).getID());
intent.putExtras(bundle);
startActivity(intent);
break;
}
case 1:{
//从生词本中删除这个数据,并设置适配器
DataAccess data = new DataAccess(Attention.this);
data.DeleteFromAttention(list.get(position));
setAdapter();
break;
}
}
}
})
.setNegativeButton("取消", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
}
})
.create();
dialog.show();
}
//这个也木有看懂,是适配什么呢?
protected void setAdapter() {
// TODO Auto-generated method stub
DataAccess data = new DataAccess(this);
list=data.QueryAttention(null, null);
ArrayList<String> showlist = new ArrayList<String>();
for (int i=0;i<list.size();i++){
showlist.add((i+1)+"."+list.get(i).getSpelling()+"\n"+list.get(i).getMeanning());
}
this.setListAdapter(new ArrayAdapter<String>(this, R.layout.file_row, showlist));
}
@Override
protected void onResume() {
// TODO Auto-generated method stub
this.setAdapter();
super.onResume();
}
}
(C)单词编辑功能的实现(EditWord.java+editword.xml)
首先还是来看布局吧(有点类似于注册登录系统,这里就不解释了):
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:background="@drawable/main_back">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:text="单词:"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="22px"
/>
<EditText
android:id="@+id/EditWord_spelling"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
//这里的hint表示提示文字
android:hint="单词拼写"
/>
</LinearLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:text="中文:"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="22px"
/>
<EditText
android:id="@+id/EditWord_meanning"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:hint="中文解释"
android:lines="3"
/>
</LinearLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_horizontal">
<Button
android:id="@+id/attention_confirm_button"
android:layout_width="100px"
android:layout_height="wrap_content"
android:text="确定"
android:background="@drawable/white_btns"
></Button>
<Button
android:id="@+id/attention_cancel_button"
android:layout_width="100px"
android:layout_height="wrap_content"
android:text="取消"
android:background="@drawable/white_btns"
></Button>
</LinearLayout>
</LinearLayout>
逻辑实现:
/**
*
*/
package wordroid.activitys;
import java.util.ArrayList;
import wordroid.database.DataAccess;
import wordroid.model.R;
import wordroid.model.Word;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
/**
* @author Administrator
*
*/
public class EditWord extends Activity implements OnClickListener{
//这里设置两个编辑区域(EditText)和按钮(Button)
private String action;
private EditText spelling;
private EditText meanning;
private Button confirm;
private Button cancel;
private Word word;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
this.setTitle("编辑生词本");
//开启editword布局
this.setContentView(R.layout.editword);
Bundle bundle = this.getIntent().getExtras();
//传递数据
action = bundle.getString("action");
//初始化各种组件
initWidgets();
}
private void initWidgets() {
// TODO Auto-generated method stub
this.spelling = (EditText) this.findViewById(R.id.EditWord_spelling);
this.cancel = (Button) this.findViewById(R.id.attention_cancel_button);
this.confirm = (Button) this.findViewById(R.id.attention_confirm_button);
this.meanning = (EditText) this.findViewById(R.id.EditWord_meanning);
//为取消和确定按钮设置监听
cancel.setOnClickListener(this);
confirm.setOnClickListener(this);
if (action.equals("edit")){
Bundle bundle = this.getIntent().getExtras();
DataAccess data = new DataAccess(this);
Word word =data.QueryAttention("ID ='"+bundle.getString("id")+"'", null).get(0);
//设置为原来的文字
spelling.setText(word.getSpelling());
meanning.setText(word.getMeanning());
}
}
//为确定和取消按钮设置监听
@SuppressWarnings("unused")
public void onClick(View v) {
// TODO Auto-generated method stub
//点取消按钮,则结束这个Activity
if (v==cancel){
finish();
}
//点确定按钮,如果这两个EditText有一个为空的话,则显示一个短暂的Toast
if (v==confirm){
if (meanning.getText().toString().equals("")||spelling.getText().toString().equals("")){
Toast.makeText(EditWord.this, "信息不能为空", Toast.LENGTH_SHORT).show();
return;
}
if (action.equals("add")){
boolean add =true;
final DataAccess data = new DataAccess(this);
ArrayList<Word> words = data.QueryAttention(null, null);
for(int i=0;i<words.size();i++){
//对每一个生词进行查找,如果有相同的单词的话,则输出错误 if(this.spelling.getText().toString().equals(words.get(i).getSpelling())){
add=false;
Log.i("thesame", ""+i);
word = words.get(i);
}
}
//如果单词已经在生词本中出现了的话,则弹出一个对话框,说明这个单词已经存在(因为还有可能只更改单词的意思而不更改这个单词),如果点击确定的话,则将该单词更新,否则,退出对话框
if (!add){
Dialog dialog = new AlertDialog.Builder(this)
.setIcon(R.drawable.dialog_icon)
.setTitle("该单词已存在")
.setMessage("生词本中有这个单词,要覆盖掉它吗?")
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
word.setSpelling(spelling.getText().toString());
word.setMeanning(meanning.getText().toString());
data.UpdateAttention(word);
finish();
}
})
.setNegativeButton("取消", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
}
}).create();
dialog.show();
}
//如果是增加的一个单词,而且没有重复的单词的话,就将其加入其中
if(add){
Word word1 = new Word();
word1.setMeanning(this.meanning.getText().toString());
word1.setSpelling(this.spelling.getText().toString());
word1.setPhonetic_alphabet(" ");
data.InsertIntoAttention(word1);
finish();
}
}
//如果是编辑单词的话,也将其加入其中,但是并不改变生词的数量
else if (action.equals("edit")){
Bundle bundle = new Bundle();
bundle = this.getIntent().getExtras();
DataAccess data = new DataAccess(EditWord.this);
Word word = data.QueryAttention("ID = '"+bundle.getString("id")+"'", null).get(0);
word.setMeanning(this.meanning.getText().toString());
word.setSpelling(this.spelling.getText().toString());
data.UpdateAttention(word);
finish();
}
}
}
}
重新回到主界面,看看那个下拉框中所追加的功能:
布局文件:(选择词库文件)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:background="@drawable/main_back">
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="14px"
android:text="请选择词库文件:"
/>
<ListView
android:id="@android:id/list"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
</LinearLayout>
选择一个list之后,导入到这样一个布局:(代码附在后面)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:id="@+id/import_layout"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/filename"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="14px"
/>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="14px"
android:text="词库名称:"
/>
<EditText
android:id="@+id/newname"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:hint="为词库重新命名"
/>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="14px"
android:text="每个List容量:"
android:phoneNumber="true"
/>
<EditText
android:id="@+id/numOfEachList"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:hint="输入一个整数"
/>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<RadioGroup android:id="@+id/radioGroup"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
//水平放置的两个RadioButton
android:orientation="horizontal">
<RadioButton android:id="@+id/radioButtonshunxu"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="顺序" />
<RadioButton android:id="@+id/radioButtonluanxu"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="乱序" />
</RadioGroup>
</LinearLayout>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/import_confirm_button"
android:layout_width="100px"
android:layout_height="wrap_content"
android:text="确定"
></Button>
<Button
android:id="@+id/import_cancel_button"
android:layout_width="100px"
android:layout_height="wrap_content"
android:text="取消"
></Button>
</LinearLayout>
</LinearLayout>
(图为ADT插件的截图)
其内在的逻辑实现:
package wordroid.activitys;
import java.io.File;
import java.util.StringTokenizer;
import wordroid.business.OperationOfBooks;
import wordroid.database.DataAccess;
import wordroid.model.R;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ListActivity;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.pm.ActivityInfo;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.RadioGroup.OnCheckedChangeListener;
public class ImportBook extends ListActivity {
private ProgressDialog myDialog = null;
private String[] fileNames;
private TextView filename ;
private EditText numOfEachList ;
private Button confirm ;
private Button cancel ;
public static String result="";
protected static final int IMPORT_SUCCEED =0x108;
protected static final int IMPORT_FAIL =0x109;
RadioButton shunxu;
RadioGroup radioGroup;
String order;
private Handler mHandler = new Handler(){
public void handleMessage(Message msg) {
myDialog.dismiss();
switch (msg.what) {
case IMPORT_SUCCEED: {
Dialog dialog = new AlertDialog.Builder(ImportBook.this)
.setIcon(R.drawable.dialog_icon)
.setTitle("导入新词库")
.setMessage("导入已完成!")
.setPositiveButton("返回主菜单", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
/* User clicked OK so do some stuff */
finish();
}
})
.create();
dialog.show();
break;
}
default: {
DataAccess data = new DataAccess(ImportBook.this);
DataAccess.bookID="";
DataAccess.bookID=result;
if (!DataAccess.bookID.equals(""))
data.DeleteBook();
DataAccess.bookID="";
Toast.makeText(ImportBook.this, "导入词库失败", Toast.LENGTH_LONG)
.show();
break;
}
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
this.setTitle("导入新词库");
this.setContentView(R.layout.import_book);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);
File f = new File("/sdcard/");
File[] files=f.listFiles();
fileNames = new String[files.length];
for (int i=0;i<fileNames.length;i++){
fileNames[i]=files[i].getName();
}
this.setListAdapter(new ArrayAdapter<String>(this, R.layout.file_row, fileNames));
}
@Override
protected void onListItemClick(ListView l, View v, final int position, long id) {
// TODO Auto-generated method stub
super.onListItemClick(l, v, position, id);
final Dialog dialog = new Dialog(this);
dialog.setTitle("导入新词库");
//这里导入布局文件
dialog.setContentView(R.layout.import_book_dialog);
dialog.show();
filename = (TextView) dialog.findViewById(R.id.filename);
final EditText newname = (EditText) dialog.findViewById(R.id.newname);
numOfEachList = (EditText) dialog.findViewById(R.id.numOfEachList);
confirm = (Button) dialog.findViewById(R.id.import_confirm_button);
cancel = (Button) dialog.findViewById(R.id.import_cancel_button);
shunxu = (RadioButton)dialog.findViewById(R.id.radioButtonshunxu);
radioGroup =(RadioGroup) dialog.findViewById(R.id.radioGroup);
radioGroup.setOnCheckedChangeListener(new OnCheckedChangeListener(){
public void onCheckedChanged(RadioGroup group, int checkedId) {
// TODO Auto-generated method stub
//为选择的RadioButton编号
if (checkedId==shunxu.getId()) order ="shunxu";
else order="luanxu";
}
});
filename.setText("词库文件:"+fileNames[position]);
cancel.setOnClickListener(new OnClickListener(){
public void onClick(View v) {
dialog.cancel();
}
});
StringTokenizer st = new StringTokenizer(fileNames[position], ".");
newname.setText(st.nextToken());
confirm.setOnClickListener(new OnClickListener(){
public void onClick(View v) {
if (newname.getText().toString().equals("")){
dialog.cancel();
Toast.makeText(ImportBook.this, "词库名称不能为空", Toast.LENGTH_LONG)
.show();
}
try{
if (Integer.parseInt(numOfEachList.getText().toString())<=0)
throw new Exception();
}catch(Exception e){
dialog.cancel();
Toast.makeText(ImportBook.this, "list容量格式不正确(请输入大于0的整数)", Toast.LENGTH_LONG)
.show();
}
dialog.cancel();
final Thread thread =new Thread(new Runnable(){
public void run(){
OperationOfBooks OOB = new OperationOfBooks();
try {
DataAccess.ifContinue=true;
result="";
if(OOB.ImportBook(ImportBook.this, fileNames[position],newname.getText().toString(), Integer.parseInt(numOfEachList.getText().toString()),order)){
Message m = new Message();
m.what=ImportBook.IMPORT_SUCCEED;
ImportBook.this.mHandler.sendMessage(m);
}
else{
Message m = new Message();
m.what=ImportBook.IMPORT_FAIL;
ImportBook.this.mHandler.sendMessage(m);
}
} catch (Exception e) {
Message m = new Message();
m.what=ImportBook.IMPORT_FAIL;
ImportBook.this.mHandler.sendMessage(m);
}
}
});
thread.start();
//这里在传入中,当然,如果用滚动条来实现的话,也许更加直观
myDialog = new ProgressDialog(ImportBook.this);
myDialog.setTitle("导入新词库");
myDialog.setMessage("请稍等,这可能需要几分钟的时间");
myDialog.setCancelable(false);
myDialog.setButton("取消", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
DataAccess.ifContinue=false;
OperationOfBooks.ifContinue=false;
}
});
myDialog.show();
}
});
}
}
其余的一些包中的内容:
Business包为事务设置(包括字符语音转换工具TTS)
Database包为数据库设置(数据访问以及调试的时候用的SQL的帮助信息)
Model包中为书,单词以及list的建模(这些类的相应创建)
Widget中为时间偏向设置以及各种小微技(Widget)的设置