android sqlite数据库封装 实现crud
android常用的数据保存方式有文件、sharepreferences、数据库、网络、contentprovider集中方式。
文件存储方式,经常使用在缓存整个页面数据,比如电子书内容、html数据等。
sharepreferrences存储方式,实质也就是xml文件存储的封装,常用于存储配置参数数据。当然也可以用文件存储+Properties来存储参数数据。
网络,就是将数据存储在网络空间上。
contentprovider主要作用是统一数据存储方式,实现数据共享,以后有机会仔细分析下。
数据库的方式,常用在存储一系列的结构复杂的数据,轻量级的数据库SQlit使用起来还是比较简单,但是总想能像hibernate似的框架可以进行下封装,实现orm并且可以实现简单的rcud。这里就介绍下一个分装过程,源码下载在后面。
一、封装数据库的类结构
结构比较简单:BaseBean.java--实体类的基类
DBConfig.java---数据库的参数,包括数据库名、要创建的表列表、数据库版本等
IssContentProvider.java--继承了ContentProvider,定义了数据库的初始化和操作
DBFactory--数据库工厂类
Table.java----定义Table的annotation
TableColumn.java--定义表的列的annotation和属性
TableUtil.java--书库操作工具类,主要是获得表和根据标签拼装sql语句
二、封装数据库的使用过程
由于封装后的数据库使用比较简单,就跟配置好hibernate之后使用似的,所以咱们先看下咱们使用,不理解的地方,等分析了整个实现过程后就行清晰了。
1、要实现orm,肯定要定义带标签的实体类,当然是继承BaseBean类。
2、要将数据库参数传递给DBConfig,并初始化。
3、数据库操作类,通过contentprovideder实现crud。
用例子看下
1,定义实体类
- publicclassSmartDownloadBeanextendsBaseBean<SmartDownloadBean>{
- @TableColumn(type=TableColumn.Types.TEXT,isIndex=true,isNotNull=true)
- publicStringdownpath;
- @TableColumn(type=TableColumn.Types.INTEGER)
- publicintthreadid;
- @TableColumn(type=TableColumn.Types.INTEGER)
- publicintdownlength;
- @Override
- publicSmartDownloadBeanparseJSON(JSONObjectjsonObj){
- returnnull;
- }
- @Override
- publicJSONObjecttoJSON(){
- //TODOAuto-generatedmethodstub
- returnnull;
- }
- @Override
- publicSmartDownloadBeancursorToBean(Cursorcursor){
- this.downpath=cursor.getString(cursor.getColumnIndex("downpath"));
- this.threadid=cursor.getInt(cursor.getColumnIndex("threadid"));
- this.downlength=cursor.getInt(cursor.getColumnIndex("downlength"));
- returnthis;
- }
- @Override
- publicContentValuesbeanToValues(){
- ContentValuesvalues=newContentValues();
- if(!TextUtils.isEmpty(downpath)){
- values.put("downpath",downpath);
- }
- if(!TextUtils.isEmpty(threadid+"")){
- values.put("threadid",threadid);
- }
- if(!TextUtils.isEmpty(downlength+"")){
- values.put("downlength",downlength);
- }
- returnvalues;
- }
- }
实体类通过标签,定义了对应表的列名、及列的属性
2、定义要创建的表、数据名等参数
[java] view plain copy- /**
- *数据库配置
- **/
- publicclassSssProviderextendsIssContentProvider{
- @Override
- publicvoidinit(){
- //数据库相关参数设置
- DBConfigconfig=newDBConfig.Builder()
- .addTatble(SmartDownloadBean.class)
- .setName("sss.db").setVersion(2)
- .setAuthority("com.sss").build();
- IssDBFactory.init(getContext(),config);
- }
- }
要定义都个表的话,再addTatble(Bean.class)即可。
3、调用数据库的工具类
[java] view plain copy- /**
- *操作数据库的utils
- *
- *@authordllik2013-11-23
- */
- publicclassDBUtils{
- publicstaticUriURI_SMARTDOWNLOAD=IssContentProvider.buildUri(SmartDownloadBean.class);
- /**
- *获取每条线程已经下载的文件长度
- *
- *@paramcontext
- *@paramdownpath
- *@return
- */
- publicstaticMap<Integer,Integer>querySmartDownData(Contextcontext,Stringdownpath){
- ContentResolvermResolver=context.getContentResolver();
- Cursorcursor=mResolver.query(URI_SMARTDOWNLOAD,null,"downpath=?",newString[]{
- downpath
- },null);
- Map<Integer,Integer>data=newHashMap<Integer,Integer>();
- while(cursor.moveToNext()){
- SmartDownloadBeanbean=newSmartDownloadBean();
- bean.cursorToBean(cursor);
- data.put(bean.threadid,bean.downlength);
- }
- cursor.close();
- returndata;
- }
- /**
- *保存每条线程已经下载的文件长度
- *
- *@paramcontext
- *@parampath
- *@parammap
- */
- publicstaticvoidinsertSmartDown(Contextcontext,Stringpath,Map<Integer,Integer>map){
- ContentResolvermResolver=context.getContentResolver();
- for(Map.Entry<Integer,Integer>entry:map.entrySet()){
- SmartDownloadBeanbean=newSmartDownloadBean();
- bean.downpath=path;
- bean.downlength=entry.getValue();
- bean.threadid=entry.getKey();
- mResolver.insert(URI_SMARTDOWNLOAD,bean.beanToValues());
- }
- }
- /**
- *实时更新每条线程已经下载的文件长度
- *
- *@paramcontext
- *@parampath
- *@parammap
- */
- publicstaticvoidupdateSmartDown(Contextcontext,Stringpath,Map<Integer,Integer>map){
- ContentResolvermResolver=context.getContentResolver();
- for(Map.Entry<Integer,Integer>entry:map.entrySet()){
- SmartDownloadBeanbean=newSmartDownloadBean();
- bean.downpath=path;
- bean.downlength=entry.getValue();
- bean.threadid=entry.getKey();
- mResolver.update(URI_SMARTDOWNLOAD,bean.beanToValues(),"downpath=?andthreadid=?",
- newString[]{
- bean.downpath,bean.threadid+""
- });
- }
- }
- /**
- *当文件下载完成后,删除对应的下载记录
- *
- *@paramcontext
- *@parampath
- */
- publicstaticvoiddeleteSmartDown(Contextcontext,Stringpath){
- ContentResolvermResolver=context.getContentResolver();
- mResolver.delete(URI_SMARTDOWNLOAD,"downpath=?",newString[]{
- path
- });
- }
- }
三、数据库的封装过程
看下实体类的基类
[java] view plain copy- publicabstractclassBaseBean<T>implementsSerializable{
- privatestaticfinallongserialVersionUID=-804757173578073135L;
- @TableColumn(type=TableColumn.Types.INTEGER,isPrimary=true)
- publicstaticfinalString_ID="_id";
- /**
- *将json对象转化为Bean实例
- *
- *@paramjsonObj
- *@return
- */
- publicabstractTparseJSON(JSONObjectjsonObj);
- /**
- *将Bean实例转化为json对象
- *
- *@return
- */
- publicabstractJSONObjecttoJSON();
- /**
- *将数据库的cursor转化为Bean实例(如果对象涉及在数据库存取,需实现此方法)
- *
- *@paramcursor
- *@return
- */
- publicabstractTcursorToBean(Cursorcursor);
- /**
- *将Bean实例转化为一个ContentValues实例,供存入数据库使用(如果对象涉及在数据库存取,需实现此方法)
- *
- *@return
- */
- publicabstractContentValuesbeanToValues();
- @SuppressWarnings("unchecked")
- publicTparseJSON(Gsongson,Stringjson){
- return(T)gson.fromJson(json,this.getClass());
- }
- publicContentValuestoValues(){
- ContentValuesvalues=newContentValues();
- try{
- Class<?>c=getClass();
- Field[]fields=c.getFields();
- for(Fieldf:fields){
- f.setAccessible(true);
- finalTableColumntableColumnAnnotation=f.getAnnotation(TableColumn.class);
- if(tableColumnAnnotation!=null){
- if(tableColumnAnnotation.type()==TableColumn.Types.INTEGER){
- values.put(f.getName(),f.getInt(this));
- }elseif(tableColumnAnnotation.type()==TableColumn.Types.BLOB){
- values.put(f.getName(),(byte[])f.get(this));
- }elseif(tableColumnAnnotation.type()==TableColumn.Types.TEXT){
- values.put(f.getName(),f.get(this).toString());
- }else{
- values.put(f.getName(),f.get(this).toString());
- }
- }
- }
- }catch(IllegalArgumentExceptione){
- e.printStackTrace();
- }catch(IllegalAccessExceptione){
- e.printStackTrace();
- }
- returnvalues;
- }
- }
说明几点:1、用到了泛型,因为定义的数据实体类有多个
2、实现序列化,实体类数据通过Intent进行传递
3、定义了一个主键id
数据库参数类
[java] view plain copy- publicclassDBConfig{
- finalArrayList<Class<?extendsBaseBean<?>>>tableList;
- finalStringdbName;
- finalintdbVersion;
- finalStringauthority;
- finalArrayList<String>tableNameList;
- privateDBConfig(finalBuilderbuilder){
- tableList=builder.tableList;
- dbName=builder.dbName;
- dbVersion=builder.dbVersion;
- authority=builder.authority;
- tableNameList=newArrayList<String>();
- for(Class<?extendsBaseBean<?>>c:tableList){
- Stringname=TableUtil.getTableName(c);
- tableNameList.add(name);
- }
- }
- publicstaticclassBuilder{
- privateArrayList<Class<?extendsBaseBean<?>>>tableList;
- privateStringdbName;
- privateintdbVersion;
- privateStringauthority="com.iss.mobile";
- publicBuilder(){
- tableList=newArrayList<Class<?extendsBaseBean<?>>>();
- }
- publicBuildersetName(Stringname){
- dbName=name;
- returnthis;
- }
- publicBuildersetVersion(intversion){
- dbVersion=version;
- returnthis;
- }
- publicBuilderaddTatble(Class<?extendsBaseBean<?>>table){
- tableList.add(table);
- returnthis;
- }
- publicBuildersetAuthority(Stringauthority){
- this.authority=authority;
- returnthis;
- }
- publicDBConfigbuild(){
- returnnewDBConfig(this);
- }
- }
- }
通过该类,来设置数据库的参数,在初始化数据库的时候用到。
内容提供者类,初始化和操作数据库
[java] view plain copy- publicabstractclassIssContentProviderextendsContentProvider{
- publicstaticStringCONTENT_TYPE="vnd.android.cursor.dir/iss.db";
- protectedSQLiteDatabasemDB;
- publicstaticStringAUTHORITY="com.iss.mobile";
- @Override
- publicbooleanonCreate(){
- init();
- IssDBFactoryissDBFactory=IssDBFactory.getInstance();
- DBConfigconfig=IssDBFactory.getInstance().getDBConfig();
- if(config==null){
- thrownewRuntimeException("dbfactorynotinit");
- }
- AUTHORITY=config.authority;
- CONTENT_TYPE="vnd.android.cursor.dir/"+config.dbName;
- mDB=issDBFactory.open();
- returntrue;
- }
- publicabstractvoidinit();
- publicstaticfinalStringSCHEME="content";
- @Override
- publicUriinsert(Uriuri,ContentValuesvalues){
- StringtableName=getTableName(uri);
- longresult=mDB.insert(tableName,null,values);
- if(result!=-1){
- getContext().getContentResolver().notifyChange(uri,null);
- }
- returnbuildResultUri(tableName,result);
- }
- @Override
- publicintbulkInsert(Uriuri,ContentValues[]values){
- mDB.beginTransaction();
- StringtableName=getTableName(uri);
- for(ContentValuesvalue:values){
- mDB.insert(tableName,null,value);
- }
- mDB.setTransactionSuccessful();
- mDB.endTransaction();
- returnvalues.length;
- }
- @Override
- publicCursorquery(Uriuri,String[]projection,Stringselection,String[]selectionArgs,
- StringsortOrder){
- StringtableName=getTableName(uri);
- returnmDB.query(tableName,projection,selection,selectionArgs,null,null,sortOrder);
- }
- @Override
- publicStringgetType(Uriuri){
- returnCONTENT_TYPE;
- }
- @Override
- publicintdelete(Uriuri,Stringselection,String[]selectionArgs){
- StringtableName=getTableName(uri);
- intresult=mDB.delete(tableName,selection,selectionArgs);
- if(result!=0){
- getContext().getContentResolver().notifyChange(uri,null);
- }
- returnresult;
- }
- @Override
- publicintupdate(Uriuri,ContentValuesvalues,Stringselection,String[]selectionArgs){
- StringtableName=getTableName(uri);
- intresult=mDB.update(tableName,values,selection,selectionArgs);
- if(result!=0){
- getContext().getContentResolver().notifyChange(uri,null);
- }
- returnresult;
- }
- privateUribuildResultUri(StringtableName,longresult){
- finalUri.Builderbuilder=newUri.Builder();
- DBConfigconfig=IssDBFactory.getInstance().getDBConfig();
- if(config==null){
- thrownewRuntimeException("dbfactorynotinit");
- }
- builder.scheme(SCHEME);
- builder.authority(config.authority);
- builder.path(tableName);
- builder.appendPath(String.valueOf(result));
- returnbuilder.build();
- }
- privateStringgetTableName(Uriuri){
- DBConfigconfig=IssDBFactory.getInstance().getDBConfig();
- if(config==null){
- thrownewRuntimeException("dbfactorynotinit");
- }
- Stringpath=uri.getLastPathSegment();
- if(!config.tableNameList.contains(path)){
- thrownewIllegalArgumentException("UnknownURI"+uri);
- }
- returnpath;
- }
- publicstaticUribuildUri(Stringpath,Stringid){
- finalUri.Builderbuilder=newUri.Builder();
- DBConfigconfig=IssDBFactory.getInstance().getDBConfig();
- if(config==null){
- thrownewRuntimeException("dbfactorynotinit");
- }
- builder.scheme(SCHEME);
- builder.authority(config.authority);
- builder.path(path);
- builder.appendPath(id);
- returnbuilder.build();
- }
- publicstaticUribuildUri(Stringpath){
- finalUri.Builderbuilder=newUri.Builder();
- DBConfigconfig=IssDBFactory.getInstance().getDBConfig();
- if(config==null){
- thrownewRuntimeException("dbfactorynotinit");
- }
- builder.scheme(SCHEME);
- builder.authority(config.authority);
- builder.path(path);
- returnbuilder.build();
- }
- publicstaticUribuildUri(Class<?extendsBaseBean<?>>c){
- finalStringtableName=TableUtil.getTableName(c);
- returnbuildUri(tableName);
- }
- }
该内容提供者在创建的时候,先执行init()(将要数据库的参数设置好,再将参数传递给工厂类),工厂类根据参数创建数据库mDB = issDBFactory.open();
数据库工厂类:
- publicclassIssDBFactory{
- privatestaticfinalStringTAG=IssDBFactory.class.getSimpleName();
- privateDBConfigmConfig;
- privateSQLiteDatabasemSQLiteDB;
- privateIssDBOpenHelpermDBOpenHelper;
- privatefinalContextmContext;
- privatestaticIssDBFactoryinstance;
- privateIssDBFactory(Contextcontext){
- mContext=context;
- }
- publicstaticvoidinit(Contextcontext,DBConfigdbConfig){
- if(instance==null){
- instance=newIssDBFactory(context.getApplicationContext());
- instance.setDBConfig(dbConfig);
- }
- }
- publicstaticIssDBFactorygetInstance(){
- returninstance;
- }
- publicvoidsetDBConfig(DBConfigdbConfig){
- mConfig=dbConfig;
- }
- publicDBConfiggetDBConfig(){
- returnmConfig;
- }
- publicSQLiteDatabaseopen(){
- if(mSQLiteDB==null){
- mDBOpenHelper=newIssDBOpenHelper(mContext,mConfig.dbName,null,mConfig.dbVersion);
- mSQLiteDB=mDBOpenHelper.getWritableDatabase();
- }
- returnmSQLiteDB;
- }
- publicvoidclose(){
- if(mDBOpenHelper!=null){
- mDBOpenHelper.close();
- }
- }
- publicvoidbeginTransaction(){
- if(mSQLiteDB==null){
- mSQLiteDB.beginTransaction();
- }
- }
- publicvoidendTransaction(){
- if(mSQLiteDB==null&&mSQLiteDB.inTransaction()){
- mSQLiteDB.endTransaction();
- }
- }
- publicvoidsetTransactionSuccessful(){
- if(mSQLiteDB==null){
- mSQLiteDB.setTransactionSuccessful();
- }
- }
- privatefinalclassIssDBOpenHelperextendsSQLiteOpenHelper{
- publicIssDBOpenHelper(Contextcontext,Stringname,CursorFactoryfactory,intversion){
- super(context,name,factory,version);
- }
- @Override
- publicvoidonCreate(SQLiteDatabasedb){
- for(Class<?extendsBaseBean<?>>table:mConfig.tableList){
- try{
- for(Stringstatment:TableUtil.getCreateStatments(table)){
- Log.d(TAG,statment);
- db.execSQL(statment);
- }
- }catch(Throwablee){
- Log.e(TAG,"Can'tcreatetable"+table.getSimpleName());
- }
- }
- /**
- *初始化数据
- */
- //initData();
- }
- @Override
- publicvoidonUpgrade(SQLiteDatabasedb,intoldVersion,intnewVersion){
- Log.d(TAG,"onUpgrade:"+oldVersion+">>"+newVersion);
- for(Class<?extendsBaseBean<?>>table:mConfig.tableList){
- try{
- db.execSQL("DROPTABLEIFEXISTS"+TableUtil.getTableName(table));
- }catch(Throwablee){
- Log.e(TAG,"Can'tcreatetable"+table.getSimpleName());
- }
- }
- onCreate(db);
- }
- }
- publicvoidcleanTable(StringtableName,intmaxSize,intbatchSize){
- Cursorcursor=mSQLiteDB.rawQuery("selectcount(_id)from"+tableName,null);
- if(cursor.getCount()!=0&&cursor.moveToFirst()&&!cursor.isAfterLast()){
- if(cursor.getInt(0)>=maxSize){
- intdeleteSize=maxSize-batchSize;
- mSQLiteDB.execSQL("deletefrom"+tableName+"where_idin("+"select_idfrom"+tableName
- +"orderby_id"+"limit"+deleteSize+")");
- }
- }
- cursor.close();
- }
看到这用过数据库的就比较清晰了,用到了SQLiteOpenHelper是以内部类的形式实现的,在oncreat里创建了表,在onupgrade里实现了更新表。
其中用到TableUtil.getCreateStatments(table),
数据库工具类:
[java] view plain copy- publicclassTableUtil{
- publicstaticStringgetTableName(Class<?extendsBaseBean<?>>c){
- Stringname=null;
- TabletableNameAnnotation=c.getAnnotation(Table.class);
- if(tableNameAnnotation!=null){
- name=tableNameAnnotation.name();
- }
- if(TextUtils.isEmpty(name)){
- name=c.getSimpleName();
- }
- returnname;
- }
- /**
- *拼装sql用的建表语句以及索引语句
- *
- *@paramc
- *@return
- */
- publicfinalstaticList<String>getCreateStatments(Class<?extendsBaseBean<?>>c){
- finalList<String>createStatments=newArrayList<String>();
- finalList<String>indexStatments=newArrayList<String>();
- finalStringBuilderbuilder=newStringBuilder();
- finalStringtableName=getTableName(c);
- builder.append("CREATETABLE");
- builder.append(tableName);
- builder.append("(");
- intcolumnNum=0;
- for(finalFieldf:c.getFields()){
- f.setAccessible(true);
- finalTableColumntableColumnAnnotation=f.getAnnotation(TableColumn.class);
- if(tableColumnAnnotation!=null){
- columnNum++;
- StringcolumnName=f.getName();
- builder.append(columnName);
- builder.append("");
- if(tableColumnAnnotation.type()==TableColumn.Types.INTEGER){
- builder.append("INTEGER");
- }elseif(tableColumnAnnotation.type()==TableColumn.Types.BLOB){
- builder.append("BLOB");
- }elseif(tableColumnAnnotation.type()==TableColumn.Types.TEXT){
- builder.append("TEXT");
- }else{
- builder.append("DATETIME");
- }
- if(tableColumnAnnotation.isPrimary()){
- builder.append("PRIMARYKEY");
- }else{
- if(tableColumnAnnotation.isNotNull()){
- builder.append("NOTNULL");
- }
- if(tableColumnAnnotation.isUnique()){
- builder.append("UNIQUE");
- }
- }
- if(tableColumnAnnotation.isIndex()){
- indexStatments.add("CREATEINDEXidx_"+columnName+"_"+tableName+"ON"
- +tableName+"("+columnName+");");
- }
- builder.append(",");
- }
- }
- builder.setLength(builder.length()-2);//removelast','
- builder.append(");");
- if(columnNum>0){
- createStatments.add(builder.toString());
- createStatments.addAll(indexStatments);
- }
- returncreateStatments;
- }
- }
就两个方法,获取表名,在更新表的时候用到,拼装sql在创建表时候用到。
最后两个标签类:
- @Retention(RetentionPolicy.RUNTIME)
- public@interfaceTable{
- Stringname();
- }
- @Retention(RetentionPolicy.RUNTIME)
- public@interfaceTableColumn{
- publicenumTypes{
- INTEGER,TEXT,BLOB,DATETIME
- }
- Typestype()defaultTypes.TEXT;
- booleanisPrimary()defaultfalse;
- booleanisIndex()defaultfalse;
- booleanisNotNull()defaultfalse;
- booleanisUnique()defaultfalse;
- }
思路比较简单,就是注意先标签、过滤器、内容提供者的使用就行了。
最后是封装包代码,使用过程没有加,自己加入吧:http://download.csdn.net/detail/xiangxue336/7001299
更多相关文章
- Android 与 JS 交互数据上限问题【Refusing to load URL as it e
- 在 Android 应用中使用数据库
- Android ListView 滚动条的设置详解及实例代码
- android 数据传输之JSON
- Android NDK c调用java代码
- Android P 以及之后版本不支持同时从多个进程使用具有相同数据目
- Android Sqlite数据库跨版本升级 保存之前数据