如何创建一个可使用的数据库框架项目:Android
一个好的数据库模型需要符合MVC,通常在我们进入项目组之前,创立的数据库就像这样:
public class MySQLiteHelper extends SQLiteOpenHelper
然后就在我们代码中增删查改了,每次一条sql语句,这样首先看起来不规范,而且也非常不方便,最重要的是要做重复性的工作。
==============================================================================
【规范】:
1.一个bean 什么是bean,从代码来说就是你要保存一行数据库的参数,比如保存用户,用户的id,名字,性别,电话等等,里面需要有get和set参数,整体样子可以是这样的,下面我们会仔细一步步来,以及截图上传。
2.一个Dao,Dao就是对数据库具体封装,如果有一个UserBean,那么需要一个UserDao作为桥梁联通SQLiteOpenHelper和UserBean,UserDao对于 User对象进行增删查改,同时映射到数据库进行增删查改,这样看起来是不是系统多了?
3.最后就是SQLiteOpenHelper类,增删查改。
==============================================================================
【动手】:
新建Android项目:
除了默认设置,我们新建一个User类作为一个bean:
这时候为了方便使用,我们事先导进来一个数据库表格。
我将我的数据库放在assets里面的datebase文件夹下,创建数据库表可以使用navicat直接创建,导出db
然后我建立的数据库其中user类表格结构如下:
然后建立我们的SQLiteClientDaoHelper 数据库操作类
package com.example.core; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.List; import android.annotation.SuppressLint; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.os.SystemClock; import android.text.TextUtils; /** * 数据库操作类 * * @author Jing * */ public final class SQLiteClientDaoHelper { public static final String DATABASE_PATH = SQLiteHelperWrapper.PATH + File.separator + SQLiteHelperWrapper.DATABASE_NAME; private Context context; private SQLiteOpenHelper helper; private static SQLiteClientDaoHelper instance; private SQLiteClientDaoHelper(Context context) { this.context = context; this.helper = new SQLiteHelperWrapper(context); } public static synchronized SQLiteClientDaoHelper getInstance(Context context) { if(instance == null) { instance = new SQLiteClientDaoHelper(context); } return instance; } public Context getContext() { return context; } /** * 数据库插�? * @param table 表名 * @param values参数�? */ public long insert(String table, ContentValues values) { if (TextUtils.isEmpty(table)) throw new IllegalArgumentException("Table is not null!"); long id = -1; SQLiteDatabase database = helper.getWritableDatabase(); database.beginTransaction(); try { id = database.insert(table, null, values); database.setTransactionSuccessful(); } finally { database.endTransaction(); } return id; } /** * 数据库删�? * @param table */ public void delete(String table) { delete(table, null, null); } /** * 数据库删�? * @param table * @param whereClause * @param whereArgs */ public void delete(String table, String whereClause, String[] whereArgs) { if (TextUtils.isEmpty(table)) throw new IllegalArgumentException("Table is not null!"); SQLiteDatabase database = helper.getWritableDatabase(); database.beginTransaction(); try { database.delete(table, whereClause, whereArgs); database.setTransactionSuccessful(); } finally { database.endTransaction(); } } /** * 数据库更�? * @param table * @param values */ public void update(String table, ContentValues values) { update(table, values, null, null); } /** * 数据库更�? * @param table * @param values * @param whereClause * @param whereArgs */ public void update(String table, ContentValues values, String whereClause, String[] whereArgs) { if (TextUtils.isEmpty(table)) throw new IllegalArgumentException("Table is not null!"); SQLiteDatabase database = helper.getWritableDatabase(); database.beginTransaction(); try { database.update(table, values, whereClause, whereArgs); database.setTransactionSuccessful(); } finally { database.endTransaction(); } } /** * 单语句数据库执行 * @param sql */ public void excute(String sql) { if (TextUtils.isEmpty(sql)) throw new IllegalArgumentException("Sql is not null!"); SQLiteDatabase database = helper.getWritableDatabase(); database.beginTransaction(); try { database.execSQL(sql); database.setTransactionSuccessful(); } finally { database.endTransaction(); } } /** * 多语句数据库执行 * @param handle */ public void excute(TransactionHandle handle) { if (handle == null) throw new IllegalArgumentException("TransactionHandle is not null!"); SQLiteDatabase database = helper.getWritableDatabase(); database.beginTransaction(); try { handle.onTransactionHandle(database); database.setTransactionSuccessful(); } finally { database.endTransaction(); } } /** * 获取单个对象数据库操�? * @param sql * @param buildData * @return */ public <E> E getRaw(String sql, BuildData<E> buildData) { return getRaw(sql, null, buildData); } /** * 获取单个对象数据库操�? * @param <E> * @param sql * @param selectionArgs * @param buildData * @return */ public <E> E getRaw(String sql, String[] selectionArgs, BuildData<E> buildData) { List<E> list = this.getRawAll(sql, selectionArgs, buildData); if(list.size() > 0) { return list.get(0); } return null; } /** * 获取集合对象数据库操�? * @param sql * @param buildData * @return */ public <E> List<E> getRawAll(String sql, BuildData<E> buildData) { return getRawAll(sql, null, buildData); } /** * 获取集合对象数据库操�? * @param <E> * @param sql * @param selectionArgs * @param buildData * @return */ public <E> List<E> getRawAll(String sql, String[] selectionArgs, BuildData<E> buildData) { if (TextUtils.isEmpty(sql)) throw new IllegalArgumentException("Sql is not null!"); if (buildData == null) throw new IllegalArgumentException("BuildData is not null!"); long startTime = SystemClock.elapsedRealtime(); List<E> result = new ArrayList<E>(); SQLiteDatabase database = helper.getReadableDatabase(); Cursor cursor = database.rawQuery(sql, selectionArgs); try { if (cursor.moveToFirst()) { do { result.add(buildData.onBuildData(cursor)); } while (cursor.moveToNext()); } } catch (Exception e) { } finally { try { if (cursor != null && !cursor.isClosed()) { cursor.close(); } } catch (Exception e) { } } return result; } /** * 获取单个对象数据库操�? * @param <E> * @param sql * @param selectionArgs * @param buildData * @return */ public <E> E get(String sql, String[] selectionArgs, BuildData<E> buildData) { List<E> list = this.getAll(sql, selectionArgs, buildData); if(list.size() > 0) { return list.get(0); } return null; } /** * 获取集合对象数据库操�? * @param <E> * @param sql * @param selectionArgs * @param buildData * @return */ public <E> List<E> getAll(String sql, String[] selectionArgs, BuildData<E> buildData) { if (TextUtils.isEmpty(sql)) throw new IllegalArgumentException("Sql is not null!"); if (buildData == null) throw new IllegalArgumentException("BuildData is not null!"); List<E> result = new ArrayList<E>(); SQLiteDatabase database = helper.getReadableDatabase(); Cursor cursor = database.rawQuery(sql, selectionArgs); try { if (cursor.moveToFirst()) { do { result.add(buildData.onBuildData(cursor)); } while (cursor.moveToNext()); } } finally { if (cursor != null && !cursor.isClosed()) { cursor.close(); } } return result; } /** * 获取单个对象数据库操�? * @param table * @param columns * @param selection * @param selectionArgs * @param buildData * @return */ public <E> E get(String table, String[] columns, String selection, String[] selectionArgs, BuildData<E> buildData) { return get(table, columns, selection, selectionArgs, null, null, null, buildData); } /** * 获取单个对象数据库操�? * @param table * @param columns * @param selection * @param selectionArgs * @param groupBy * @param having * @param buildData * @return */ public <E> E get(String table, String[] columns, String selection, String[] selectionArgs, String orderBy, BuildData<E> buildData) { return get(table, columns, selection, selectionArgs, null, null, orderBy, buildData); } /** * 获取单个对象数据库操�? * @param table * @param columns * @param selection * @param selectionArgs * @param groupBy * @param having * @param buildData * @return */ public <E> E get(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, BuildData<E> buildData) { return get(table, columns, selection, selectionArgs, groupBy, having, null, buildData); } /** * 获取单个对象数据库操�? * @param <E> * @param table * @param columns * @param selection * @param selectionArgs * @param groupBy * @param having * @param orderBy * @param buildData * @return */ public <E> E get(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, BuildData<E> buildData) { List<E> list = getAll(table, columns, selection, selectionArgs, groupBy, having, orderBy, buildData); if(list.size() > 0) { return list.get(0); } return null; } /** * 获取集合对象数据库操�? * @param table * @param columns * @param selection * @param selectionArgs * @param buildData * @return */ public <E> List<E> getAll(String table, String[] columns, String selection, String[] selectionArgs, BuildData<E> buildData) { return getAll(table, columns, selection, selectionArgs, null, null, null, buildData); } /** * 获取集合对象数据库操�? * @param table * @param columns * @param selection * @param selectionArgs * @param orderBy * @param buildData * @return */ public <E> List<E> getAll(String table, String[] columns, String selection, String[] selectionArgs, String orderBy, BuildData<E> buildData) { return getAll(table, columns, selection, selectionArgs, null, null, orderBy, buildData); } /** * 获取集合对象数据库操�? * @param table * @param columns * @param selection * @param selectionArgs * @param groupBy * @param having * @param buildData * @return */ public <E> List<E> getAll(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, BuildData<E> buildData) { return getAll(table, columns, selection, selectionArgs, groupBy, having, null, buildData); } /** * 获取集合对象数据库操�? * @param <E> * @param table * @param columns * @param selection * @param selectionArgs * @param groupBy * @param having * @param orderBy * @param buildData * @return */ public <E> List<E> getAll(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, BuildData<E> buildData) { if (buildData == null) throw new IllegalArgumentException("BuildData is not null!"); List<E> result = new ArrayList<E>(); SQLiteDatabase database = helper.getReadableDatabase(); Cursor cursor = database.query(table, columns, selection, selectionArgs, groupBy, having, orderBy); try { if (cursor.moveToFirst()) { do { result.add(buildData.onBuildData(cursor)); } while (cursor.moveToNext()); } } finally { if (cursor != null && !cursor.isClosed()) { cursor.close(); } } return result; } /** * 获取单个对象数据库操�? * @param <E> * @param table * @param columns * @param selection * @param selectionArgs * @param groupBy * @param having * @param orderBy * @param limit * @param buildData * @return */ public <E> E get(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit, BuildData<E> buildData) { List<E> list = this.getAll(table, columns, selection, selectionArgs, groupBy, having, orderBy, limit, buildData); if(list.size() > 0) { return list.get(0); } return null; } /** * 获取集合对象数据库操�? * @param <E> * @param table * @param columns * @param selection * @param selectionArgs * @param groupBy * @param having * @param orderBy * @param limit * @param buildData * @return */ public <E> List<E> getAll(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit, BuildData<E> buildData) { if (buildData == null) throw new IllegalArgumentException("BuildData is not null!"); List<E> result = new ArrayList<E>(); SQLiteDatabase database = helper.getReadableDatabase(); Cursor cursor = database.query(table, columns, selection, selectionArgs, groupBy, having, orderBy, limit); try { if (cursor.moveToFirst()) { do { result.add(buildData.onBuildData(cursor)); } while (cursor.moveToNext()); } } finally { if (cursor != null && !cursor.isClosed()) { cursor.close(); } } return result; } /** * 从数据库获取数据时的对象构建接口 * @author Jing * * @param <E> */ public interface BuildData<E> { E onBuildData(Cursor cursor); } /** * 在带事务的多语句的操作时的事务处理接�? * @author Jing * */ public interface TransactionHandle { void onTransactionHandle(SQLiteDatabase database); } /** * 对SQLiteOpenHelper进行包装, 统一�?有数据库操作 * @author Jing * */ public class SQLiteHelperWrapper extends SQLiteOpenHelper { @SuppressLint("SdCardPath") public static final String PATH = "/data/data/com.jacinter/databases"; public static final String DATABASE_NAME = "jttxl.db"; public static final int DEFAULT_DATABASE_VERSION = 1; public SQLiteHelperWrapper(Context context) { super(context, DATABASE_NAME, null, DEFAULT_DATABASE_VERSION); initDatabase(context); } @Override public void onCreate(SQLiteDatabase db) { } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { } /** * 初始化数据库 * 当第�?次打�?数据库时, 验证/data/data/com.viewserver/databases中数据库是否存在 * 如果, 不存在就将assert/database/viewserver.db拷贝�?/data/data/com.viewserver/databases进行数据库初始化 * @param context * @return */ private boolean initDatabase(Context context) { InputStream input = null; FileOutputStream output = null; try { File file = new File(DATABASE_PATH); boolean isExists = file.exists(); if(isExists) { return false; } File directory = new File(SQLiteHelperWrapper.PATH); if(!isExists && !directory.exists() && !directory.mkdirs()) { throw new IOException(SQLiteHelperWrapper.PATH + " create fail!"); } if(!isExists && !file.createNewFile()) { throw new IOException(SQLiteHelperWrapper.DATABASE_NAME + " create fail!"); } input = context.getAssets().open("database" + File.separator + SQLiteHelperWrapper.DATABASE_NAME); output = new FileOutputStream(file); byte[] buffer = new byte[1024]; int read; while ((read = input.read(buffer)) != -1) { output.write(buffer, 0, read); } output.flush(); return true; } catch (Exception e) { } finally { if (input != null) { try { input.close(); input = null; output.close(); output = null; } catch (IOException e) { } } } return false; } } }
以上大家完全可以复制粘贴,基本涵盖了数据库几个基本操作。
接下来就开始建立UserDao开始对于User进行具体管理,里面是对User增删改查的sql语句操作,这个Dao是数据库框架里面的精髓,减少了很多重复性的操作。
【UserDao】
这个类我会重点讲,因为是三个类中的桥梁,桥梁搭建好了畅通无阻,前人开路后人无忧,相反若是没有搭建好,拥堵,出错,掉桥,以及崩塌找不到数据库都是很常见的事情,最重要的是以后做项目就可以拿我们这次的项目,改几个参数就可以使用了(这些都不重要,重要是你的项目逼格升高了)
现在预览下我的项目结构,虽然没有几个class文件但是却有4个包。
这样的项目,适合重复开发,后面人接手一目了然,前人栽树,后人乘凉。
现在展示UserDao代码,代码里面带了注释,我就不写在这里了。
你可以根据自己的项目需要自我定制UserDao不是每个项目都适用,但是你参透了代码,想要修改起来很容易,最重要的是要把这种框架和思想深植在脑海中,那么生根发芽就是时间问题了,除非你根本不浇水施肥。
package com.example.dao; import java.util.List; import com.example.bean.User; import com.example.core.SQLiteClientDaoHelper; import com.example.core.SQLiteClientDaoHelper.BuildData; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; public class UserDao { //由于需要对数据库进行管理我们将SQLiteClientDaoHelper对象定义好 private SQLiteClientDaoHelper helper; public UserDao(Context context) { helper = SQLiteClientDaoHelper.getInstance(context); } /* * 之所以定义list接受user是因为组织id是有一样的,有很多用户属于同一个组织,这时候只返回User类显然不合适,所以 * 采用List接受多个User类。 */ public List<User> getUsers(long orgId) { return helper.getAll("SELECT userId, userName, phoneNumber1, phoneNumber2, shortNumber1, shortNumber2, orgId FROM user WHERE orgId = ? ORDER BY shortNumber1", new String[] { String.valueOf(orgId) }, new BuildData<User>() { @Override //通过orgid这里定义的是组织id,来找到cursor大家可以把它看成游标,定义到此id的user那一行 public User onBuildData(Cursor cursor) { User user = new User(); /* * 定义到那一行以后,根据我们写好的数据库知道第一个是Id,第二个是名字,类似这样获取,返回。 */ user.setUserId(cursor.getString(0)); user.setUserName(cursor.getString(1)); user.setPhoneNumber1(cursor.getString(2)); user.setPhoneNumber2(cursor.getString(3)); user.setShortNumber1(cursor.getString(4)); user.setShortNumber2(cursor.getString(5)); user.setOrgId(cursor.getInt(6)); return user; } }); } /* * 更新数据库表格,根据我们定义的元素使用ContentValues values = new ContentValues();进行元素更新。 */ public void updateUser(User user){ ContentValues values = new ContentValues(); values.put("userId", user.getUserId()); values.put("userName", user.getUserName()); values.put("phoneNumber1", user.getPhoneNumber1()); values.put("phoneNumber2", user.getPhoneNumber2()); values.put("shortNumber1", user.getShortNumber1()); values.put("shortNumber2", user.getShortNumber2()); values.put("orgId", user.getOrgId()); if(isExistsUser(user.getUserId())) { helper.update("user", values, "userId=?", new String[] { user.getUserId() }); } else { helper.insert("user", values); } } public void deleteUser(String userid){ helper.delete("user", "userId = ?", new String[] { userid }); } public boolean isExistsUser(String stationId) { Boolean result = helper.get("SELECT count(1) as counts FROM user WHERE userId = ?", new String[] { stationId }, new BuildData<Boolean>() { @Override public Boolean onBuildData(Cursor cursor) { return cursor.getInt(0) > 0; } }); return result != null && result; } }
现在全部框架已经搭建出来了,我们试着增删查改。
==============================================================================
【实验】:
读:之所以第一个用读,是看下我们是否能够成功读到数据库如果能读到说明桥梁搭建成功,只有搭建成功后面操作才会成功:
public class MainActivity extends Activity { private TextView datashow; UserDao userdao; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); datashow=(TextView)findViewById(R.id.datashow); initdatabase(); } private void initdatabase() { // TODO Auto-generated method stub User user=new User(); user.setOrgId(4); userdao=new UserDao(this); List<User> users=userdao.getUsers(3); for(User user1:users){ datashow.append(user1.getUserName()+"\n"); } } }
主函数查询组织机构为3的全部user
这时候出来应该是一大堆,目前我们的页面只有一个TextView,所以无法看全部,加一个scrollview
主配置文件代码:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.example.databasetest.MainActivity" > <ScrollView android:id="@+id/scrollView1" android:layout_width="match_parent" android:layout_height="match_parent" > <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <TextView android:id="@+id/datashow" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout> </ScrollView> </RelativeLayout>
然后运行项目:
效果图如下:
==============================================================================
【增】:
如何增加仔细看UserDao里面的增加方法:
public void updateUser(User user){ ContentValues values = new ContentValues(); values.put("userId", user.getUserId()); values.put("userName", user.getUserName()); values.put("phoneNumber1", user.getPhoneNumber1()); values.put("phoneNumber2", user.getPhoneNumber2()); values.put("shortNumber1", user.getShortNumber1()); values.put("shortNumber2", user.getShortNumber2()); values.put("orgId", user.getOrgId()); if(isExistsUser(user.getUserId())) { helper.update("user", values, "userId=?", new String[] { user.getUserId() }); } else { helper.insert("user", values); } }
增加的方法,简单,传入一个User类,看到里面的values,就知道我们在传入这个User 对象之前,就要把这些参数设置好,然后接下来就简单了,一键更新。
主函数代码怎么写:initdatabase 现在改成这样
private void initdatabase() { // TODO Auto-generated method stub //在读取用户之前加入用户,看看我们是否加入成功 userdao=new UserDao(this); User user=new User(); user.setOrgId(3); user.setUserId("sadasd"); user.setUserName("我的部门"); user.setPhoneNumber1("888888"); userdao.updateUser(user); //暂时设置到这里,可以多添加,接下来我们显示名字加号码 List<User> users=userdao.getUsers(3); for(User user1:users){ datashow.append(user1.getUserName()+"电话号码:"+user1.getPhoneNumber1()+"\n"); }
现在binggo,运行:
【删】:
首先看下我们UserDao的删除方法:
public void deleteUser(String userid){ helper.delete("user", "userId = ?", new String[] { userid }); }
这里看到我们删除是直接传入userid,userid在数据库中我们已经有了。
代码:
这里我要删除刚才我添加的“我的部门” 传入我的userid指
private void initdatabase() { // TODO Auto-generated method stub //在读取用户之前加入用户,看看我们是否加入成功 userdao=new UserDao(this); // User user=new User(); // user.setOrgId(3); // user.setUserId("sadasd"); // user.setUserName("我的部门"); // user.setPhoneNumber1("888888"); // userdao.updateUser(user); userdao.deleteUser("sadasd"); //暂时设置到这里,可以多添加,接下来我们显示名字加号码 List<User> users=userdao.getUsers(3); for(User user1:users){ datashow.append(user1.getUserName()+"电话号码:"+user1.getPhoneNumber1()+"\n"); }
关键代码就一句:
userdao.deleteUser("sadasd");
【注意】你们看到我注释掉的语句肯定想我都注释掉了怎么数据库还存在我的部门呢,还记得我第一次运行么,此时我的手机本地数据库已经存入了“我的部门”,再次运行时直接覆盖,本地数据库还是之前的。如果想要完全清楚之前数据库痕迹,请先卸载再安装apk,这个问题也困惑了很久。总之想要数据库显示跟你的电脑一模一样,请先卸载再安装,如果直接覆盖的话,之前你在代码中的操作,数据库就是你操作后的数据库。
记住你电脑中的数据库不会由于你的代码操作做出改变,你的代码运行的时候是在手机中。
ok,就讲到这里,看下我们运行后的效果:
ok我的部门已经删除到了
【改】:
改和增加其实是一个道理,就是有一个判断,判断用户存在不,不存在增加,存在修改,所以我们看一下UserDao代码。
public void updateUser(User user){ ContentValues values = new ContentValues(); values.put("userId", user.getUserId()); values.put("userName", user.getUserName()); values.put("phoneNumber1", user.getPhoneNumber1()); values.put("phoneNumber2", user.getPhoneNumber2()); values.put("shortNumber1", user.getShortNumber1()); values.put("shortNumber2", user.getShortNumber2()); values.put("orgId", user.getOrgId()); if(isExistsUser(user.getUserId())) { helper.update("user", values, "userId=?", new String[] { user.getUserId() }); } else { helper.insert("user", values); } }
代码意思是如果用户不存在,直接插入,如果用户存在根据userId,更新新数据
User user=new User(); user.setOrgId(3); user.setUserName("怀铁*处"); user.setUserId("51cf9cb38172cbbcf72620011761bedc"); user.setPhoneNumber1("888888"); userdao.updateUser(user);
这里我们更新的是怀铁*处,id号码从数据库得知,改变第一个电话号码
运行看效果:
号码已经改过来了。
今天我们的数据库标准化学习已经到此结束,肯定还有同学想问,这样增删查改是不是太死板,只能按照框架走,比如我删除不想按照用户userId去删除,我想按照用户名字,或者电话号码?或者组织号?
这里就需要深入了解SQLiteClientDaoHelper里面的方法,然后自己写对应的方法,这些深入了解改造我们的框架来适应不同的项目的内容我们下节课一起学习,下次课我也会制作一个简单的框架扔上来,大家下载就可以使用,边使用边学习进步比较快。
下一篇: 第八章