背单词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 设置为默认值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)


以上就是建立数据库的全过程,进度条感觉前进了好大一截!!!好开森!!!!

接下来是考虑如何将单词导入进去,加油!!!!

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值