相信很懂同学都接触过很多开源的数据库框架,具体的就不多说了,反正给我的感觉就是,用起来总是束手束脚的,哪怕说的再好也并没有自己做出来的那么趁手。另外,安卓本身对数据库的封装已经做得很不错了,我觉得自己封一个易用的并且好用的工具也并没有那么难,那么下面进入正题。
首先说说sqliteOpenHelper这个工具类吧,其实这个工具类网上的教程资料很多,具体使用就不多说,主要说一下我是怎么写的吧。先自己写一个DatabaseHelper类继承sqliteOpenHelper,这里为了更灵活我写了两个构造函数。代码如下:
public class DatabaseHelper extends sqliteOpenHelper { private static final String name = "ZPDB"; //数据库名称 private static final int version = 1; public DatabaseHelper(Context context) { this(context,name); } public DatabaseHelper(Context context,String dbname){ super(context,dbname,null,version); } @Override public void onCreate(sqliteDatabase db) { db.execsql("CREATE TABLE IF NOT EXISTS person (personid integer primary key autoincrement," + " name varchar(20),password varchar(20),age INTEGER)"); db.execsql("create table if not exists story (storyid integer primary key autoincrement," + "title varchar(30),content varchar(1000),date varchar(20))"); } @Override public void onUpgrade(sqliteDatabase db,int oldVersion,int newVersion) { } }为什么要写这两个构造函数呢,第一个我用了一个默认的数据库名称,第二个可以自己传入数据库名称。这样做的目的是为了满足多数据库操作的需要,很多同学可能遇到过这个问题,比如一个聊天app,跟每个人的聊天记录保存在不同的文件下面,而且名字也不一样,这里就需要能够自己传入数据库名称了。说到不同文件下面的数据库,我们就得用到Context(上下文对象)这个玩意了。通常情况下,直接传入上下文对象,则数据库默认保存到系统目录下,而且是不可见的,那么如何定义数据库到指定位置呢?其实很简单,我们自定义一个类,继承ContextWrapper,代码如下:
public class DatabaseContext extends ContextWrapper { private String path; public DatabaseContext(Context base,String path){ super(base); this.path = path; } @Override public File getDatabasePath(String name) { //判断是否存在sd卡 boolean sdExist = android.os.Environment.MEDIA_MOUNTED.equals(android.os.Environment.getExternalStorageState()); if(!sdExist){ return null; } else{//如果存在 //获取sd卡路径 String dbDir=android.os.Environment.getExternalStorageDirectory().toString()+"/"+path; String dbPath = dbDir+"/"+name;//数据库路径 //判断目录是否存在,不存在则创建该目录 File dirFile = new File(dbDir); if(!dirFile.exists()) dirFile.mkdirs(); //数据库文件是否创建成功 boolean isFileCreateSuccess = false; //判断文件是否存在,不存在则创建该文件 File dbFile = new File(dbPath); if(!dbFile.exists()) { try { isFileCreateSuccess = dbFile.createNewFile();//创建文件 } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } else { isFileCreateSuccess = true; } //返回数据库文件对象 if(isFileCreateSuccess) return dbFile; else return null; } } @Override public sqliteDatabase openOrCreateDatabase(String name,int mode,sqliteDatabase.CursorFactory factory) { sqliteDatabase result = sqliteDatabase.openOrCreateDatabase(getDatabasePath(name),null); return result; } @Override public sqliteDatabase openOrCreateDatabase(String name,sqliteDatabase.CursorFactory factory,DatabaseErrorHandler errorHandler) { sqliteDatabase result = sqliteDatabase.openOrCreateDatabase(getDatabasePath(name),null); return result; } }
sqliteOpenHelper sqlHelper = new DatabaseHelper(new DatabaseContext (context,path)); 或者
sqliteOpenHelper sqlHelper = new DatabaseHelper(new DatabaseContext (context,path),dbname);
这样你的数据库打开位置就是在path下面了,由于使用了sqliteOpenHelper 这个帮助类,所以如果不存在的话就会自动帮你新建一个。
好了,数据库帮助类以及数据库打开位置搞定了,下面我们还要思考一个问题,那就是对数据的操作问题,数据库无外乎增删查改,如果每次都要重写依次,既浪费时间也不便于扩展和调整。我们应该把这些操作进行一下统一,这样如果有什么大的变动我们就只需要修改一个地方就可以了,而不用考虑其它的因素和可能影响到的地方。数据库操作工具类如下:
public class DatabaseManager2 { private sqliteOpenHelper mDatabaseHelper; private sqliteDatabase db; public DatabaseManager2(sqliteOpenHelper sqliteOpenHelper){ this.mDatabaseHelper = sqliteOpenHelper; } /** for example ContentValues values = new ContentValues(); values1.put("name","张龙"); values1.put("address","beijing"); values1.put("sex","male"); insert("user",values); * @param table * @param values * @return */ public boolean insert(String table,ContentValues values){ db = mDatabaseHelper.getWritableDatabase(); boolean flag = false; long id = -1; try{ id = db.insert(table,values); flag = id != -1; }catch (Exception e){ e.printStackTrace(); } close(); return flag; } /** for example delete("user"," id =? ",new String[]{"1"}); * @param table * @param whereClause * @param whereArgs * @return */ public boolean delete(String table,String whereClause,String[] whereArgs){ db = mDatabaseHelper.getWritableDatabase(); boolean flag = false; int count; try { count = db.delete(table,whereClause,whereArgs); flag = count > 0; } catch (Exception e) { e.printStackTrace(); } close(); return flag; } /** for example ContentValues values = new ContentValues(); values.put("name","张三"); values.put("address","上海"); values.put("sex","男"); update("user",values," id=? ",new String[]{"2"}); * @param table * @param values * @param whereClause * @param whereArgs * @return */ public boolean update(String table,ContentValues values,String[] whereArgs) { db = mDatabaseHelper.getWritableDatabase(); boolean flag = false; int count; try { count = db.update(table,whereArgs); flag = count > 0; } catch (Exception e) { e.printStackTrace(); } close(); return flag; } /** for example view("user",new String[]{"2"}); * @param table * @param selection * @param selectionArgs * @return */ public Map<String,String> view(String table,String selection,String[] selectionArgs) { db = mDatabaseHelper.getReadableDatabase(); Cursor cursor = null; Map<String,String> map = new HashMap<String,String>(); try { cursor = db.query(true,table,selection,selectionArgs,null); int cols_len = cursor.getColumnCount(); while (cursor.moveToNext()) { for (int i = 0; i < cols_len; i++) { String cols_key = cursor.getColumnName(i); String cols_value = cursor.getString(cursor.getColumnIndex(cols_key)); if (cols_value == null) { cols_value = ""; } map.put(cols_key,cols_value); } } } catch (Exception e) { e.printStackTrace(); } if(cursor != null){ cursor.close(); } close(); return map; } /** for example listPersonMaps("user",null); * @param table * @param selection * @param selectionArgs * @return */ public List<Map<String,String>> listPersonMaps(String table,String[] selectionArgs,String orderBy) { db = mDatabaseHelper.getReadableDatabase(); List<Map<String,String>> list = new ArrayList<Map<String,String>>(); Cursor cursor = null; try { cursor = db.query(false,orderBy,null); int cols_len = cursor.getColumnCount(); while (cursor.moveToNext()) { Map<String,String>(); for (int i = 0; i < cols_len; i++) { String cols_key = cursor.getColumnName(i); String cols_value = cursor.getString(cursor.getColumnIndex(cols_key)); if (cols_value == null) { cols_value = ""; } map.put(cols_key,cols_value); } list.add(map); } } catch (Exception e) { e.printStackTrace(); } if(cursor != null){ cursor.close(); } close(); return list; } /** * 批量插入 * @param sTableName * @param ListOfMaps */ public void InsertMaps(String sTableName,List<Map<String,Object>> ListOfMaps) { db = mDatabaseHelper.getWritableDatabase(); try { boolean bFirst=true; if(ListOfMaps==null || ListOfMaps.size()<1) { return; } Log.e("insertbegin","begin"); db.beginTransaction(); for(int i=0;i<ListOfMaps.size();i++) { bFirst= true; StringBuilder sb=new StringBuilder(); StringBuilder columns=new StringBuilder(); StringBuilder values=new StringBuilder(); sb = sb.append("INSERT INTO [" + sTableName + "] ("); ArrayList<Object>listOfValues = new ArrayList<Object>(); Map<String,Object> map = ListOfMaps.get(i); Iterator<Map.Entry<String,Object>> iterator =map.entrySet().iterator(); while(iterator.hasNext()) { Map.Entry<String,Object> next = iterator.next(); if(!bFirst) { columns = columns.append(","); values = values.append(","); } columns.append("[").append(next.getKey()).append("]"); values.append("?"); listOfValues.add(next.getValue()); bFirst = false; } sb = sb.append(columns.toString()).append(") VALUES (").append(values.toString()).append(")"); ExecNonQuery2(sb.toString(),listOfValues); } db.setTransactionSuccessful(); db.endTransaction(); Log.e("insertend","end"); } catch (Exception e) { e.printStackTrace(); } close(); } public void ExecNonQuery2(String Statement,List<Object> Args) { sqliteStatement s = this.db.compileStatement(Statement); try { int numArgs = 0; if (Args != null) { numArgs = Args.size(); } for (int i = 0; i < numArgs; i++) { DatabaseUtils.bindObjectToProgram(s,i + 1,Args.get(i)); } s.execute(); } finally { s.close(); } } public void close(){ if(isOpen()){ db.close(); } } public boolean isOpen(){ if(db != null){ return db.isOpen(); } return false; } }
具体就不多说,使用方法也是基于系统给的方法进行的简单封装,主要注意一下关于事务的操作就差不多了。
最后是关于如何使用的问题,在这里我的建议是针对每个表自己建一个类,对涉及到的增删查改进行具体操作,因为每次增删改查的具体字段都不相同,而且考虑数据库位置及名称等原因,这样更便于管理和修改,降低耦合度。示范代码如下:
public class TestDemo{ public final String TABLE = "story"; DatabaseManager2 databaseManager2; public TestDemo(Context context){ this(context,null); } public TestDemo(Context context,String path){ databaseManager2 = new DatabaseManager2(new DatabaseHelper(!TextUtils.isEmpty(path)?new DatabaseContext(context,path):context)); } public void add(Story story) { ContentValues contentValues = new ContentValues(); contentValues.put("title",story.getTitle()); contentValues.put("content",story.getContent()); contentValues.put("date",story.getDate()); databaseManager2.insert(TABLE,contentValues); } }好了,以上是我使用数据库的一些心得体会,很多人可能还会考虑数据库的打开关闭问题,我目前的做法是每次操作完成都会关闭,当然,有的需求是比较特殊的,比如跟聊天相关的app可能涉及到数据库的持久操作,我的处理方式是,在activity的onresume中打开,在onstop中关闭,最后效果还不错,至于其它的地方基本保持随开随关的方式,对用户体验及性能上并没有太大影响,而且极大的减小了忘记关闭数据库带来的风险。最后补充一个关于数据库的线程操作问题,因为有的同学可能把比较耗时的数据库操作放到线程中去了,这里给出一个线程安全的数据库操作工具类:
public class DatabaseManager { private AtomicInteger mOpenCounter = new AtomicInteger(); private static DatabaseManager instance; private static sqliteOpenHelper mDatabaseHelper; private sqliteDatabase db; public static synchronized void initializeInstance(sqliteOpenHelper helper) { if (instance == null) { instance = new DatabaseManager(); mDatabaseHelper = helper; } } public static synchronized DatabaseManager getInstance() { if (instance == null) { throw new IllegalStateException(DatabaseManager.class.getSimpleName() + " is not initialized,call initializeInstance(..) method first."); } return instance; } public synchronized sqliteDatabase openDatabase() { if(mOpenCounter.incrementAndGet() == 1) { // opening new database db = mDatabaseHelper.getWritableDatabase(); } return db; } public synchronized void closeDatabase() { if(mOpenCounter.decrementAndGet() == 0) { // Closing database db.close(); } } /** for example ContentValues values = new ContentValues(); values1.put("name",ContentValues values){ openDatabase(); boolean flag = false; long id = -1; try{ id = db.insert(table,values); flag = id != -1; }catch (Exception e){ e.printStackTrace(); } closeDatabase(); return flag; } /** for example delete("user",String[] whereArgs){ openDatabase(); boolean flag = false; int count; try { count = db.delete(table,whereArgs); flag = count > 0; } catch (Exception e) { e.printStackTrace(); } closeDatabase(); return flag; } /** for example ContentValues values = new ContentValues(); values.put("name",String[] whereArgs) { openDatabase(); boolean flag = false; int count; try { count = db.update(table,whereArgs); flag = count > 0; } catch (Exception e) { e.printStackTrace(); } closeDatabase(); return flag; } /** for example view("user",String[] selectionArgs) { openDatabase(); Cursor cursor = null; Map<String,cols_value); } } } catch (Exception e) { e.printStackTrace(); } if(cursor != null){ cursor.close(); } closeDatabase(); return map; } /** for example listPersonMaps("user",String orderBy) { openDatabase(); List<Map<String,cols_value); } list.add(map); } } catch (Exception e) { e.printStackTrace(); } if(cursor != null){ cursor.close(); } closeDatabase(); return list; } /** * 批量插入 * @param sTableName * @param ListOfMaps */ public void InsertMaps(String sTableName,Object>> ListOfMaps) { openDatabase(); try { boolean bFirst=true; if(ListOfMaps==null || ListOfMaps.size()<1) { return; } Log.e("insertbegin","end"); } catch (Exception e) { e.printStackTrace(); } closeDatabase(); } public void ExecNonQuery2(String Statement,Args.get(i)); } s.execute(); } finally { s.close(); } } public boolean isOpen(){ if(db != null){ return db.isOpen(); } return false; } }原文链接:https://www.f2er.com/sqlite/198750.html