背单词App开发日记3
2015-07-24 23:16
429 查看
2015.07.22
距离上一次记录已经有5天时间了......这几天进度比较慢.主要是一直在纠结一些问题(后面会说到).最终将数据库封装好了!进度条又跳了一节有木有!!!
其实进度慢的原因主要是在纠结该怎么写.看了很多别人的写法,总感觉没办法用在我这里.一开始纠结要不要用SQLite,打算直接用读文件绑定控件的,后来发现行不通,还是得乖乖用SQLite.于是问题来了----怎么具体化这个数据库?其实面临的问题无非是一下几个
a.怎么创建数据库?
b.准备让数据库具有什么功能?
c.如何将单词表封装到数据库中?
d.如何将数据库和控件绑定----也就是让单词显示在屏幕上
e.如何处理进度问题和其他细节(比如占用更少资源,怎么避免重复创建等等)?
以上这些问题是我这几天来思考良久想到的接下来急需解决的问题,其他的细节可以暂且放在一边.今天主要记录的是数据库的准备工作.
本文基本上是参考scott's blog的代码改写的.本质上是重复.我下面会贴出代码还有相应简略的介绍,更多细节请移步http://blog.csdn.net/liuhe688/article/details/6715983/
查看:
1.常用方法概述:
2.具体在app里面的实现:
![](http://img.blog.csdn.net/20150724233450945?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
我将和数据库有关的文件单独建了一个包.这三个文件中:DBHelper是一个继承SQLiteOpenHelper的子类,他的作用是替我们生成一个生成一个新的数据库,并且含有一个更新版本的操作,这两个方法会在onCreate方法执行后启动.具体代码见下:
当然,在生成数据库之前,写一个相关的对象是必要的,这就是Word类.它代表的就是单词这个类,其中的属性我目前只设置了三个----分别是en_meaning(单词的英文),cn_meaning()单词的中文释义,repeating_number(已经记忆的遍数),但让还有id,这个是数据库默认的.非常简单,注意每个属性都必须要get和set方法,至于单独写还是写成一个函数看自己了,这里不在多说.有了这个类之后,我们便可以着手将一些常用的功能封装在DBManager这个类里面以便我们后续的操作:
3.控件的设置
经过以上的设置,数据库已经有框架了,万事俱备,只欠东风----东风就是我们单词表.限于能力和自己的惰性,我没有去学习比较可行的模式:诸如读写缓存,读写SDcard,读写raw之类的方法.我的做法很原始----利用asset里面的文件不会被压缩的特性将单词表的txt格式存入,然后用读写文件的方式将它里面的内容导入数据库.
以上就是建立数据库的全过程,进度条感觉前进了好大一截!!!好开森!!!!
接下来是考虑如何将单词导入进去,加油!!!!
距离上一次记录已经有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 设置为默认值null super(context, DATABASE_NAME, null, DATABASE_VERSION); } //数据库第一次被创建时onCreate会被调用 @Override public 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 @Override public 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; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_sqlite); listView=(ListView)findViewById(R.id.listView); //初始化DBManager mgr=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)
以上就是建立数据库的全过程,进度条感觉前进了好大一截!!!好开森!!!!
接下来是考虑如何将单词导入进去,加油!!!!
相关文章推荐
- Android事件分发机制完全解析,带你从源码的角度彻底理解(下)
- Android事件分发机制完全解析,带你从源码的角度彻底理解(上)
- Android开发环境配置问题
- ios autolayerout
- 我的cocos2之旅 第一天(环境的安装以及Hello World)
- Android消息推送完美方案
- [Android] How to import library into android studio
- HDU 5303 Delicious Apples(dp)
- 常用方法-各种常用方法封装
- Objective C Bridging header —— swift MD5
- Unity3d与设计模式(三)工厂模式
- iOS之通讯录1
- iOS开发中的压缩以及解压
- hdu 5303 Delicious Apples (DP+枚举)
- Android View动画效果—透明效果,旋转效果(二)
- Android中Fragment和Activity之间的互操作代码例子
- 第一个app-进阶:1、让EditText屏蔽软键盘仍能光标闪动:2、EditText 的inputType参数类型(密码方式-隐藏显示、只允许输入数字等等)
- swift2 扩展
- iOS中大文件下载(单线程下载)
- Android的taskAffinity对四种launchMode的影响