背单词App开发日记3
2015.07.22
距离上一次记录已经有5天时间了......这几天进度比较慢.主要是一直在纠结一些问题(后面会说到).最终将数据库封装好了!进度条又跳了一节有木有!!!
其实进度慢的原因主要是在纠结该怎么写.看了很多别人的写法,总感觉没办法用在我这里.一开始纠结要不要用SQLite,打算直接用读文件绑定控件的,后来发现行不通,还是得乖乖用SQLite.于是问题来了----怎么具体化这个数据库?其实面临的问题无非是一下几个
a.怎么创建数据库?
b.准备让数据库具有什么功能?
c.如何将单词表封装到数据库中?
d.如何将数据库和控件绑定----也就是让单词显示在屏幕上
e.如何处理进度问题和其他细节(比如占用更少资源,怎么避免重复创建等等)?
以上这些问题是我这几天来思考良久想到的接下来急需解决的问题,其他的细节可以暂且放在一边.今天主要记录的是数据库的准备工作.
本文基本上是参考scott's blog的代码改写的.本质上是重复.我下面会贴出代码还有相应简略的介绍,更多细节请移步http://blog.csdn.net/liuhe688/article/details/6715983/ 查看:
1.常用方法概述:
//打开或创建test.db数据库 SQLiteDatabase db = openOrCreateDatabase("test.db", Context.MODE_PRIVATE, null); db.execSQL("DROP TABLE IF EXISTS person"); //创建person表 db.execSQL("CREATE TABLE person (_id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR, age SMALLINT)"); Person person = new Person(); person.name = "john"; person.age = 30; //插入数据 db.execSQL("INSERT INTO person VALUES (NULL, ?, ?)", new Object[]{person.name, person.age}); person.name = "david"; person.age = 33; //ContentValues以键值对的形式存放数据 ContentValues cv = new ContentValues(); cv.put("name", person.name); cv.put("age", person.age); //插入ContentValues中的数据 db.insert("person", null, cv); cv = new ContentValues(); cv.put("age", 35); //更新数据 db.update("person", cv, "name = ?", new String[]{"john"}); Cursor c = db.rawQuery("SELECT * FROM person WHERE age >= ?", new String[]{"33"}); while (c.moveToNext()) { int _id = c.getInt(c.getColumnIndex("_id")); String name = c.getString(c.getColumnIndex("name")); int age = c.getInt(c.getColumnIndex("age")); Log.i("db", "_id=>" + _id + ", name=>" + name + ", age=>" + age); } c.close(); //删除数据 db.delete("person", "age < ?", new String[]{"35"}); //关闭当前数据库 db.close(); //删除test.db数据库 deleteDatabase("test.db");
这些是比较基础的,对于插入删除我们还有:
db.executeSQL(String sql);
db.executeSQL(String sql, Object[] bindArgs);//sql语句中使用占位符,然后第二个参数是实际的参数集
db.insert(String table, String nullColumnHack, ContentValues values);
db.update(String table, Contentvalues values, String whereClause, String whereArgs);
db.delete(String table, String whereClause, String whereArgs);
对于查询操作,可以这样:
db.rawQuery(String sql, String[] selectionArgs);
db.query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy);
db.query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit);
db.query(String distinct, String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit);
他们最终都返回一个Cursor对象,其操作有:
c.move(int offset); //以当前位置为参考,移动到指定行
c.moveToFirst(); //移动到第一行
c.moveToLast(); //移动到最后一行
c.moveToPosition(int position); //移动到指定行
c.moveToPrevious(); //移动到前一行
c.moveToNext(); //移动到下一行
c.isFirst(); //是否指向第一条
c.isLast(); //是否指向最后一条
c.isBeforeFirst(); //是否指向第一条之前
c.isAfterLast(); //是否指向最后一条之后
c.isNull(int columnIndex); //指定列是否为空(列基数为0)
c.isClosed(); //游标是否已关闭
c.getCount(); //总数据项数
c.getPosition(); //返回当前游标所指向的行数
c.getColumnIndex(String columnName);//返回某列名对应的列索引值
c.getString(int columnIndex); //返回当前行指定列的值
具体细节参见链接.
2.具体在app里面的实现:
我将和数据库有关的文件单独建了一个包.这三个文件中:DBHelper是一个继承SQLiteOpenHelper的子类,他的作用是替我们生成一个生成一个新的数据库,并且含有一个更新版本的操作,这两个方法会在onCreate方法执行后启动.具体代码见下:
<span style="font-family:SimSun;">package mywordapp.wordsqlite;import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;public class DBHelper extends SQLiteOpenHelper{private static final String DATABASE_NAME = "vocabulary_db";private static final int DATABASE_VERSION = 1;public DBHelper(Context context){//CursorFactory 设置为默认值nullsuper(context, DATABASE_NAME, null, DATABASE_VERSION);}//数据库第一次被创建时onCreate会被调用@Overridepublic void onCreate(SQLiteDatabase db) {db.execSQL("CREATE TABLE IF NOT EXISTS word"+"(_id INTEGER PRIMARY KEY AUTOINCREMENT,en_meaning VARCHAR,cn_meaning VARCHAR,repeating_number INTEGER)");}//如果DATABASE_VERSION的值被改成2,系统发现现有数据库版本不同,就会调用onUpgrade@Overridepublic void onUpgrade(SQLiteDatabase db,int oldVersion,int newVersion){db.execSQL("ALTER TABLE word ADD COLUMN other STRING");}
}</span>
当然,在生成数据库之前,写一个相关的对象是必要的,这就是Word类.它代表的就是单词这个类,其中的属性我目前只设置了三个----分别是en_meaning(单词的英文),cn_meaning()单词的中文释义,repeating_number(已经记忆的遍数),但让还有id,这个是数据库默认的.非常简单,注意每个属性都必须要get和set方法,至于单独写还是写成一个函数看自己了,这里不在多说.有了这个类之后,我们便可以着手将一些常用的功能封装在DBManager这个类里面以便我们后续的操作:
<span style="font-family:SimSun;">package mywordapp.wordsqlite;import java.util.ArrayList;
import java.util.List;import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;public class DBManager {private DBHelper helper;private SQLiteDatabase db;public DBManager(Context context){helper=new DBHelper(context);db=helper.getWritableDatabase();}/** 添加单词*/public void add(List<Word> words){db.beginTransaction();try{for (Word word : words) {db.execSQL("INSERT INTO word VALUES(null,?,?,?)",new Object[]{word.en_meaning,word.cn_meaning,word.repeating_number});}db.setTransactionSuccessful();}finally{db.endTransaction();}}/*更新记忆次数*/public void updateRepeating_Number(Word word) {ContentValues cv=new ContentValues();cv.put("repeating_number", word.repeating_number);db.update("word", cv, "en_meaning=?", new String[]{word.en_meaning});}/*删除烂熟的单词*/public void deleteAdroidWord(Word word) { db.delete("word", "repeating_number >=40", new String[]{String.valueOf(word.repeating_number)}); } /*查询所有单词,返回一个完整的单词表*/public List<Word> query() {ArrayList<Word> words=new ArrayList<Word>();Cursor csr=queryTheCursor();while (csr.moveToNext()) {Word word = new Word();word._id=csr.getInt(csr.getColumnIndex("_id"));word.en_meaning=csr.getString(csr.getColumnIndex("en_meaning"));word.cn_meaning=csr.getString(csr.getColumnIndex("cn_meaning"));word.repeating_number=csr.getInt(csr.getColumnIndex("repeating_number"));}return words;}public Cursor queryTheCursor() {Cursor c=db.rawQuery("SELECT*FROM word", null); return c;}/*关闭数据库*/public void closeDB(){db.close();}
}</span>
我们在DBManager构造方法中实例化DBHelper并获取一个SQLiteDatabase对象,作为整个应用的数据库实例;在添加多个Person信息时,我们采用了事务处理,确保数据完整性;最后我们提供了一个closeDB方法,释放数据库资源,这一个步骤在我们整个应用关闭时执行,这个环节容易被忘记,所以要注意一下。至于选择获取可写数据库而不是只读数据库的原因,我没有深究,有兴趣的可以看一下链接中的解释.
3.控件的设置
经过以上的设置,数据库已经有框架了,万事俱备,只欠东风----东风就是我们单词表.限于能力和自己的惰性,我没有去学习比较可行的模式:诸如读写缓存,读写SDcard,读写raw之类的方法.我的做法很原始----利用asset里面的文件不会被压缩的特性将单词表的txt格式存入,然后用读写文件的方式将它里面的内容导入数据库.
<span style="font-family:SimSun;">package example.mywordapp;import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;import org.apache.http.util.EncodingUtils;import android.app.Activity;
import android.database.Cursor;
import android.database.CursorWrapper;
import android.os.Bundle;
import android.view.View;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.SimpleCursorAdapter;
import mywordapp.wordsqlite.DBManager;
import mywordapp.wordsqlite.Word;
public class MySQLiteActivity extends Activity{private DBManager mgr;private ListView listView;@Overridepublic void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_sqlite);listView=(ListView)findViewById(R.id.listView);//初始化DBManagermgr=new DBManager(this);}//添加单词public void add(View view) {ArrayList<Word> words=new ArrayList<Word>();String fileName = "GRE.txt"; //单词表名字 ,文件要放在asset文件夹下String res=""; try{ //得到资源中的asset数据流 InputStream in = getResources().getAssets().open(fileName); int length = in.available(); byte [] buffer = new byte[length]; in.read(buffer); in.close(); res = EncodingUtils.getString(buffer, "UTF-8"); }catch(Exception e){ e.printStackTrace(); } String []tmp=res.split("\n");for(int i=0;i<tmp.length;i++){String []tmp_word=tmp[i].split(" ");System.out.println(i+1+" "+tmp_word[0]+" "+tmp_word[1]);Word word=new Word(tmp_word[0],tmp_word[1],0);words.add(word);}mgr.add(words);}//更新记忆次数public void update(View view){Word word=new Word();word.en_meaning="son";word.repeating_number=1;mgr.updateRepeating_Number(word);}//利用HashMap获得单词以便查询public void query(View view) { List<Word> words = mgr.query(); ArrayList<Map<String, Integer>> list = new ArrayList<Map<String, Integer>>(); for (Word word : words) { HashMap<String, Integer> map = new HashMap<String, Integer>(); map.put("repeating_number", word.repeating_number); //map.put("en_meaning", word.en_meaning); list.add(map); } SimpleAdapter adapter = new SimpleAdapter(this, list, android.R.layout.simple_list_item_2, new String[]{"en_meaning"}, new int[]{android.R.id.text1}); listView.setAdapter(adapter); } //删除烂熟的单词public void delete(View view) { Word word = new Word(); word.repeating_number = 40; mgr.deleteAdroidWord(word);} //全体查询,返回的是整个单词表,然后利用SimpleAdapter和ListView绑定在一起//注意要确保查询结果中有"_id"列 @SuppressWarnings("deprecation")public void queryTheCursor(View view) { Cursor c = mgr.queryTheCursor(); startManagingCursor(c); //托付给activity根据自己的生命周期去管理Cursor的生命周期 CursorWrapper cursorWrapper = new CursorWrapper(c) { @Override public String getString(int columnIndex) { //在英文后加上中文if (getColumnName(columnIndex).equals("en_meaning")) { String cn_meaning = getString(getColumnIndex("cn_meaning")); return super.getString(columnIndex)+" "+cn_meaning; } return super.getString(columnIndex); } }; //下面是在绑定语句----其结果是每个list显示两行:第一行是单词+释义,第二行是记忆次数.SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_2, cursorWrapper, new String[]{"en_meaning", "repeating_number"}, new int[]{android.R.id.text1, android.R.id.text2}); ListView listView = (ListView) findViewById(R.id.listView); listView.setAdapter(adapter); }
}</span><span style="font-family:SimHei;">
</span>
注意的一点是加入调试的时候发现logcat里面显示id列找不到证明你的word类里面的id列的名称不是"_id",这个很重要,解决办法是要么按规范做(列名称改为_id而不是id),要么在数据库里面的查询语句该名称(声明在id里面查而不是_id)
以上就是建立数据库的全过程,进度条感觉前进了好大一截!!!好开森!!!!
接下来是考虑如何将单词导入进去,加油!!!!
背单词App开发日记3相关推荐
- 背单词App开发日记5(上)
2015.07.28 今天是我阳历生日,先自己庆祝一下!哈哈. 为什么总是写博客的时间和发博客的时间不一样那?这我也没办法啊.....因为每天花在这上面的时间比较少,所以做完一项的时间很长(回家全是事 ...
- 背单词App开发日记5(下)
2015.08.06 自上次实现可用控件显示不同的单词之后,经过自己的调试我终于实现了显示单词的前提工作----读取进度和今日计划.下面分别记录一下: 1.读取进度和今日计划 既然是背单词软件必然需要 ...
- 基于AndroidStudio+Java+SQLite开发的背单词APP系统
目 录 第一章 绪论 1 1.1 选题设计开发的应用背景及价值 1 1.2 选题的研究现状 1 1.3 关于本课题 2 第二章 开发环境与主要技术 3 2.1 开发平台 3 2.2 主要技术 4 2. ...
- 免费自定义txt背单词APP(其它科目也可以)
需求: 本人觉得现有的背单词 APP 不能满足自己的需要(其实是自己懒的找,或者某些APP要收费),个性化不足,因此根据 自己的需要开发了一个背单词 APP 供自己使用. 代码免费下载地址: http ...
- 考研词汇测试软件,考研有哪些好用的背单词APP神器
原标题:考研有哪些好用的背单词APP神器 英语单词大家都很脑阔疼吧,但是不背又不行,目前市面上背单词的啊婆婆(APP)这么多,想挑一款适合考研用的应该很费时间吧,不用担心了,今天给大家推荐几个备受考研 ...
- 背单词app软件测试与评估
一.计划说明 1.本小组选择的对比测试产品是百词斩和不背单词. 2.Psp表格 测试进度表 项目 内容说明 预估耗时 (分钟) 实际耗时 (分钟) Planning 计划 10 10 · Estim ...
- 基于Jquery编写的背单词app
这是我的第一款基于Jquery编写的背单词app,使用Hbuilder工具,借助Eclipse软件,可以实现在手机直接安装app.该app界面比较简单,但主要是关于内容展现的,不涉及到数据库,所以看起 ...
- 还在用背单词App?使用Python开发英语单词自测工具,助你逆袭单词王!
学英语广告 最近也许是刚开学的原因,不管是公众号,还是刷抖音,导出都能看到关于学英语.背单词的广告. 不知道现在学生们背单词买的什么辅导材料.反正我们上学那会,<星火阅读>特别的火.记得当 ...
- python单词软件哪个好_还在用背单词App?使用Python开发英语单词自测工具,助你逆袭单词王!...
学英语广告 最近也许是刚开学的原因,不管是公众号,还是刷抖音,导出都能看到关于学英语.背单词的广告. 不知道现在学生们背单词买的什么辅导材料.反正我们上学那会,<星火阅读>特别的火.记得当 ...
- 扇贝和不背单词_你还没找到中意的背单词APP?我都试过,我来帮你盘点盘点
为了背单词,我试了很多APP(感觉相亲似的哈哈哈),这是主要的几个.现在,我来给大家盘点盘点. 呐~就是上面六款APP啦~跟着我的脚步来看一看吧 这里的每款软件都可以自己选择词书,查看单词列表,个性化 ...
最新文章
- (0026)iOS 开发之模块化封装初步实践
- 西门子标准报文1常用_基于Snap7使用C#编程访问西门子PLC系列教程(2)-S7协议
- 关于 Method Swizzing方法
- JAVA程序设计计时器代码_Java中的定时器Timer使用示例代码详解
- 多选取值_机制砂如何控制MB值和石粉含量
- IPC--进程间通信三(共享内存)
- tushare pro接口_Python与交易策略分析amp;tushare/baostock库介绍(附代码)
- 触发事件_SAP 通过事件触发后台JOB
- git 使用笔记(一)
- 说说微信聊天记录收费这件事
- 年仅44岁,又一高校教师英年早逝
- cvHoughLines2() 霍夫线变换
- 遥控器进入鼠标模式,退出鼠标模式,上下左右移动和确认
- 理财笔记 - 关于沪深300指数基金
- linux aufs,UnionFS有什么用?AUFS的一些特性
- Python网速监控
- python图像白色背景变透明
- winmerge多个文件夹生成html,功能强大的文件、文件夹比对工具-WinMerge使用教程
- 【Docker基本原理和常用命令】
- 802.11--802.11ac协议