Android应用开发离不开对SQLite数据库的操作,一般简单的增删改查,可以直接通过SQLiteDatabase进行,但是只要操作变得频繁,并且随着需求不断增加,你应该考虑使用ORM框架,至少使用SQLiteOpenHelper,结合需要用ContentProvider再封装一层。本文不介绍具体的使用方法,而是列出一些常见的问题,供分析参考。
使用问题1.SQLiteOpenHelper
(1)一个管理数据库连接的辅助类,缓存了已打开的数据库对象,提供了onConfigureonCreateonOpen,getReadableDatabasegetWriteableDatabase方法;数据库文件不会直接创建,而是在调用getReadableDatabase或者getWriteableDatabase时才调用onConfigure等方法完成。在这个过程中会比较传入的数据库版本号,从而调用onDowngradeonUpgrade处理升级逻辑,默认的onDowngrade直接抛出异常。同时注意只有在版本号version等于0时,才会调用onCreate方法,所以数据库建表之类的操作可以在此方法中处理。
(2)单个数据库连接数据库相关操作都将是顺序执行的,因此使用单例的SQLiteOpenHelper,可以基本保证数据库执行的顺序性,避免操作被锁或阻塞
2.ContentProvider
ContentProvider封装后对外提供URI,内部既可以是对数据库的操作,也可以是文件甚至内存的操作。需要注意的是它提供的querydelete等操作是在调用的线程中执行的,而非只在主线程。据我在Android4.X时的设备上统计,一般查询操作很快,在1ms左右,而单个的插入删除操作在10ms左右,如果希望界面流畅,在UI线程谨慎的修改数据库。
异常问题数据库被锁异常android.database.sqlite.SQLiteDatabaseLockedException:databaseislocked(code5)atandroid.database.sqlite.SQLiteConnection.nativeExecuteForLong(NativeMethod)atandroid.database.sqlite.SQLiteConnection.executeForLong(SQLiteConnection.java:)可以出现此问题的一种情况是:创建多个SQLiteOpenHelper实例,一个对应的连接正在写,另一个getWritableDatabase。需要避免创建多个实例。
2.android.database.CursorWindowAllocationExceptionandroid.database.CursorWindowAllocationException:Cursorwindowallocationofkbfailedandroid.database.CursorWindowAllocationException:Cursorwindowallocationofkbfailed.#OpenCursors=22(#cursorsopenedbythisproc=22)或者CouldnotallocateCursorWindowxxx.dbofsizeduetoerror-9.
一般前者出现opencursors过多,可能是cursor没有close导致,比较稳妥的方法在可能忽略的Java基础知识-理解内部类和匿名内部类,异常与异常捕获有介绍。而如果是duetoerror后面跟-12表示内存消耗过多具体数值和对应的原因如下所示
#defineEPERM1/*Operationnotpermitted*/#defineENOENT2/*Nosuchfileordirectory*/#defineESRCH/*Nosuchprocess*/#defineEINTR4/*Interruptedsystemcall*/#defineEIO5/*I/Oerror*/#defineENXIO6/*Nosuchdeviceoraddress*/#defineE2BIG7/*Argumentlisttoolong*/#defineENOEXEC8/*Execformaterror*/#defineEBADF9/*Badfilenumber*/#defineECHILD10/*Nochildprocesses*/#defineEAGAIN11/*Tryagain*/#defineENOMEM12/*Outofmemory*/#defineEACCES1/*Permissiondenied*/#defineEFAULT14/*Badaddress*/#defineENOTBLK15/*Blockdevicerequired*/#defineEBUSY16/*Deviceorresourcebusy*/#defineEEXIST17/*Fileexists*/#defineEXDEV18/*Cross-devicelink*/#defineENODEV19/*Nosuchdevice*/#defineENOTDIR20/*Notadirectory*/#defineEISDIR21/*Isadirectory*/#defineEINVAL22/*Invalidargument*/#defineENFILE2/*Filetableoverflow*/#defineEMFILE24/*Toomanyopenfiles*/#defineENOTTY25/*Notatypewriter*/#defineETXTBSY26/*Textfilebusy*/#defineEFBIG27/*Filetoolarge*/#defineENOSPC28/*Nospaceleftondevice*/#defineESPIPE29/*Illegalseek*/#defineEROFS0/*Read-onlyfilesystem*/#defineEMLINK1/*Toomanylinks*/#defineEPIPE2/*Brokenpipe*/#defineEDOM/*Mathargumentoutofdomainoffunc*/#defineERANGE4/*Mathresultnotrepresentable*/是在源码的errno-base.h中可以查到
.android.database.sqlite.SQLiteDiskIOException有时碰到android.database.sqlite.SQLiteDiskIOException,例如android.database.sqlite.SQLiteDiskIOException:diskI/Oerror(code)可根据后面的errorcode来查找并判断原因,在SQLiteResultCodes中查询具体的错误码即可
这个计算的步骤如下:
sqlite.h中定义了错误码,首先与上0xff得到错误原因,再根据除去最后两个字节的值来判断具体的原因。如,转成二进制为,首先与()上0xff为,也就是SQLITE_IOERR,然后去掉低两个字节,为1,则是SQLITE_IOERR_READ,再到SQLiteResultCodes中查询具体的原因
#defineSQLITE_IOERR_READ(SQLITE_IOERR(18))#defineSQLITE_IOERR_SHORT_READ(SQLITE_IOERR
(28))#defineSQLITE_IOERR_WRITE(SQLITE_IOERR
(8))#defineSQLITE_IOERR_FSYNC(SQLITE_IOERR
(48))
()SQLITE_IOERR_READTheSQLITE_IOERR_READerrorcodeisanextendederrorcodeforSQLITE_IOERRindicatinganI/OerrorintheVFSlayerwhiletryingtoreadfromafileondisk.Thiserrormightresultfromahardwaremalfunctionorbecauseafilesystemcameunmountedwhilethefilewasopen.
版权声明:“并发编程网”所推送文章,除非确实无法确认,我们都会注明作者和来源。部分文章推送时未能与原作者取得联系。若涉及版权问题,烦请原作者联系我们,我们会在24小时内删除处理,谢谢!^_^
北京哪个医院看白癜风最好治白癜风多少钱