乐学成语实现之一:创建数据库和表
2016-06-02
<span style="font-size:32px;"> 首先在eclipse中新建一个Android项目,项目名叫做HappyIdiom,包名叫做cn.edu.bztc.happyidiom,使用的是4.4的API,为了要让项目能够有更好的结构,这里需要在com.edu.bztc.happyidiom包下再新建几个包,如图所示:</span>
其中activity包用于存放所有活动有关的代码,db包用于存放所有数据库相关的代码,entity包用于存放所有实体相关的代码,dao包用于存放数据操作相关的代码,util包用于存放所有工具相关的代码。ADT帮我们自动生成的MainActivity和activity_main.xml文件就不需要了,这里直接将它们删除掉。创建好数据库后,首先在res目录下新建raw目录,将idioms.db数据库复制到此目录下。这是因为raw目录的东西,android会原封不动的拷贝到程序中,而不会转换为二进制文件,在db 包下新建一个DBOpenHelper类,代码如下所示:
/** * 实现将数据库文件从raw目录拷贝到手机里存放数据库的位置 * * @author 源 */ public class DBOpenHelper { private final int BUFFER_SIZE = 400000;// 缓冲区大小 public static final String DB_NAME = "idioms.db";// 保存的数据库文件名 public static final String PACKAGE_NAME = "cn.edu.bztc.happyidiom";// 应用的包名 public static final String DB_PATH = "/data" + Environment.getDataDirectory().getAbsolutePath() + "/" + PACKAGE_NAME + "/databases";// 在手机里存放数据库的位置 private Context context; public DBOpenHelper(Context context) { this.context = context; } public SQLiteDatabase openDatabase() { try { File myDataPath = new File(DB_PATH); if (!myDataPath.exists()) { myDataPath.mkdirs();// 如果没有这个目录则创建 } String dbfile = myDataPath + "/" + DB_NAME; if (!(new File(dbfile).exists())) {// 判断数据库文件是否存在,若不存在则执行导入,否则直接打开数据库 InputStream is = context.getResources().openRawResource(R.raw.idioms); FileOutputStream fos = new FileOutputStream(dbfile); byte[] buffer = new byte[BUFFER_SIZE]; int count = 0; while((count = is.read(buffer))>0){ fos.write(buffer,0,count); } fos.close(); is.close(); } SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(dbfile, null); return db; } catch (NotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; } }上面的代码实现的功能主要是使用输入输出流将idioms.db复制到手机中默认存放数据库的位置。但请注意:R.raw.idioms调用的不是系统自带的R文件,而是乐学成语程序中的,否则,系统会报错
究竟有没有复制成功呢?下面搭建单元测试环境,测试数据库有没有创建到指定的路径下面。
首先修改AndroidManifest.xml文件搭建起单元测试的环境。修改后的文件如下:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="cn.edu.bztc.happyidiom" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="17" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <uses-library android:name="android.test.runner"/> </application> <instrumentation android:name="android.test.InstrumentationTestRunner" android:targetPackage="cn.edu.bztc.happyidiom"> </instrumentation> </manifest>只要加入上述代码,单元测试环境就搭建起来了。
接下来在test包下,新建DBOpenHelperTest继承AndroidTestCase.代码如下:
public class DBOpenHelperTest extends AndroidTestCase{ public void testDBCopy(){ DBOpenHelper dbOpenHelper = new DBOpenHelper(getContext()); dbOpenHelper.openDatabase(); } }该类中只封装了一个方法,测试方法通常命名为testXXX()。该方法调用了DBOpenHelper类里面定义的openDatabase()方法。
右击DBOpenHelperTest文件,选择Run as后选择Android JUnit Test进行单元测试。如果出现绿条,代表测试成功,如果测试代码中存在错误,则会出现红条并下方显示出错的原因。
接下来我们看看数据库有没有复制成功,切换到DDMS。我们发现在data/data/应用的包下成功的创建了数据库。如图所示:
public class Animal { private int id; private String name;//成语名称 private String pronounce;//成语发音 private String explain;//成语解释 private String antonym;//反义词 private String homoionym;//同义词 private String derivation;//源自 private String examples;//例子 public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPronounce() { return pronounce; } public void setPronounce(String pronounce) { this.pronounce = pronounce; } public String getExplain() { return explain; } public void setExplain(String explain) { this.explain = explain; } public String getAntonym() { return antonym; } public void setAntonym(String antonym) { this.antonym = antonym; } public String getHomoionym() { return homoionym; } public void setHomoionym(String homoionym) { this.homoionym = homoionym; } public String getDerivation() { return derivation; } public void setDerivation(String derivation) { this.derivation = derivation; } public String getExamples() { return examples; } public void setExamples(String examples) { this.examples = examples; } }可以看到,实体类的内容非常简单,基本就是生成数据库表对应字段的get和set方法就可以了。接着我们还需要创建一个AnimalDao类,这个类将会把一些常用的数据库操作封装起来,以方便我们后面使用,代码如下所示:
<pre name="code" class="java">public class AnimalDao { private static AnimalDao animalDao; private SQLiteDatabase db; /** * 将构建方法私有化 */ private AnimalDao(Context context) { DBOpenHelper dbHelper = new DBOpenHelper(context); db = dbHelper.openDatabase(); } /** * 获取AnimalDao的实例 */ public synchronized static AnimalDao getInstance(Context context) { if (animalDao == null) { animalDao = new AnimalDao(context); } return animalDao; } /** * 从数据库读取所有的动物类成语 */ public List<Animal> getAllAnimals() { List<Animal> list = new ArrayList<Animal>(); Cursor cursor = db.query("animal", null, null, null, null, null, null); if (cursor.moveToFirst()) { do { Animal animal = new Animal(); animal.setId(cursor.getInt(cursor.getColumnIndex("_id"))); animal.setName(cursor.getString(cursor.getColumnIndex("name"))); animal.setPronounce(cursor.getString(cursor .getColumnIndex("pronounce"))); animal.setAntonym(cursor.getString(cursor .getColumnIndex("antonym"))); animal.setHomoionym(cursor.getString(cursor .getColumnIndex("homoionym"))); animal.setDerivation(cursor.getString(cursor .getColumnIndex("derivation"))); animal.setExplain(cursor.getString(cursor .getColumnIndex("examples"))); list.add(animal); } while (cursor.moveToNext()); } return list; } }
可以看到,AnimalDao是一个单例类,我们将它的构造方法私有化,并提供了一个getInstance()方法来获取AnimalDao的实例,这样就可以保证全局范围内只会有一个AnimalDao的实例。接下来我们在AnimalDao中提供一个方法getAllAnimals(),该方法用来获取所有的动物类成语。
编写单元测试类AnimalDaoTest继承AndroidTestCase,代码如下:
public class AnimalDaoTest extends AndroidTestCase{ public void testGetAllAnimals(){ AnimalDao animalDao = AnimalDao.getInstance(getContext()); List<Animal> animals = animalDao.getAllAnimals(); System.out.println(animals.size()); for(Animal animal:animals){ System.out.println(animal.getName()); } } }
<span style="font-size:32px;">运行单元测试,结果如图所示:</span>
好了,第一阶段的代码写到这里就差不多了。