当前位置: 首页 > 科技观察

Android数据存储(下)

时间:2023-03-12 07:58:15 科技观察

1.Android数据库使用android.database.sqlite.SQLiteDatabase在Android中用来表示一个数据库对象。它提供了两种模式来帮助开发者进行基本的数据库操作,如增、删、改、查。使用SQL语句描述操作使用SQL语句调用SQLiteDatabase.execSql或SQLiteDatabase.rawQuery来执行操作。//使用sql查询数据Cursordata=db.rawQuery("selectid,namefromtable");//使用sql插入数据db.execSql("insertintocontacts(id,name)values(2,'cpacm')");学了一点懂sql语句的人应该能看懂上面的代码(其实可以大致了解语句的意思~)这里我先解释一下Cursor(游标)的作用。把游标想象成C语言中的指针变量,虽然有点对,但是意思还是不对),游标是系统为用户创建的数据缓冲区,没错,就是存放数据的数据区SQL语句的结果。但它也提供了一种机制,可以从包含多条数据记录的结果集中一次提取一条记录,这也类似于指针。游标总是与SQLselect语句相关联,因为游标由结果集(可以是关联的select语句检索到的零个、一个或多个记录)和结果集中指向特定记录的游标位置组成。在决定处理结果集时,必须声明指向结果集的游标。与C语言相比,如果你写过处理文件的程序,那么游标就像你打开文件时得到的文件句柄。只要文件打开成功,文件句柄就可以代表该文件。简而言之,请记住,游标是一个具有唯一标记的数据区域,允许用户从中一条一条地读取数据。结构化地描述数据库的操作,这样即使我们不熟悉SQL语句,也可以用最熟悉的面向对象的方式来进行数据库操作。//结构化查询数据Cursordata=db.query("contacts",newString[]{"id","name"},null,null,null,null,null);//结构化插入数据ContentValuevalues=newContentValues();values.put("id",2);values.put("name","cpacm");db.insert("table",null,values);/***参数说明*table:数据表名,columns:要显示的列名,如果为null则相当于**selection:相当于sql语句的where条件;selectionArgs数组将where条件替换?*groupBy:SQL语句分组,orderBy:排序,默认asc**/publicCursorquery(Stringtable,String[]columns,Stringselection,String[]selectionArgs,StringgroupBy,Stringhaving,StringorderBy){}比如我的SQL语句想查询ForSELECTCustomerName,SUM(OrderPrice)FROMOrdersWHERECountry=?GROUPBYCustomerNameHAVINGSUM(OrderPrice)>500ORDERBYCustomerName那么我写的代码如下","SUM(OrderPrice)"};//选择条件Stringselection="Country=?";//里面的变量对应条件中的问号,请多选一一入座。String[]selectionArgs=newString[]{"China"};//分组名称StringgroupBy="CustomerName";//分组条件Stringhaving="SUM(OrderPrice)>500";//按字段排序StringorderBy="CustomerName";Cursorc=db.query(表、列、选择、selectionArgs、groupBy、having、orderBy);这样就可以实现对数据库的查询。其他的语句参数都差不多,这里就不一一介绍了。publiclonginsert(Stringtable,StringnullColumnHack,ContentValuesvalues)publicintdelete(Stringtable,StringwhereClause,String[]whereArgs)publicintupdate(Stringtable,ContentValuesvalues,StringwhereClause,String[]whereArgs)关于GroupBy和Havinggroupby的使用,顾名思义,就是对xxx进行分组,必须要有“聚合功能”与之配合,使用时至少需要一个分组标识字段。聚合函数包括:sum()、count()、avg()等。使用groupby的目的是对数据进行分组,进行汇总操作。比如上面sql语句的CustomerName,如果它有四行{"张三","李四","张三","李四"},那么此时会分成两组,即张三组和李四组,然后统计他们使用的orderprice的总和。HAVING的作用是为每一组指定条件,就像where指定条件一样,即可以根据指定的条件来选择行。如果要使用HAVING子句,则必须在GROUPBY子句之后。还是上面的SQL语句,如果张三的SUM(OrderPrice)不超过500,那么张三的组就不会显示。SQL语句的预编译在实际应用中,有些SQL语句需要重复使用。为了避免重复解析SQL语句的开销,可以对需要复用的SQL语句进行预编译,以提高数据库操作的执行效率。//编译复杂SQLSQLiteStatementcompiledSql=db.compileStatement(aSQL);//执行SQLcompiledSql.execute();//编译复杂SQL语句SQLiteStatementcompiledSql=db.compileStatement(aSQL);//执行SQLcompiledSql.execute();课外知识:所谓事务就是用户定义的一系列数据库操作。这些操作要么做完,要么根本不做,是一个不可分割的工作单元。例如,在关系数据库中,事务可以是单个SQL语句、一组SQL语句或整个程序。一个简单的例子是当你想同时修改数据库中的两个不同的表,如果它们不是一个事务,当第一张表被修改,但是第二张表有异常,不能修改时,只有第二张表回到修改前的状态,第一个表已经被修改。而当你把它们设置为一个事务时,当第一张表被修改,但是第二张表的修改出现异常,无法修改时,第一张表和第二张表都必须更改。回到未修改状态!这就是所谓的事务回滚。SQLiteOpenHelper在SQLiteOpenHelper中封装了一个SqliteDatabase对象,用户可以使用该类进行数据库操作。packagecom.example.notebook;importandroid.content.Context;importandroid.database.sqlite.SQLiteDatabase;importandroid.database.sqlite.SQLiteOpenHelper;importandroid.database.sqlite.SQLiteDatabase.CursorFactory;publicclassDBHelperextendsSQLiteOpenHelper{privatestaticfinalintVERSION=1;子类中,必须有这个构造函数*@paramcontext上下文对象*@paramname数据库名*@paramfactory*@paramversion当前数据库的版本,值必须是整数和增量状态*/publicDBHelper(Contextcontext,Stringname,CursorFactoryfactory,intversion){super(context,name,factory,version);}publicDBHelper(Contextcontext,Stringname,intversion){this(context,name,null,version);}publicDBHelper(Contextcontext,Stringname){this(context,name,VERSION);}@OverridepublicvoidonCreate(SQLiteDatabasedb){//构造数据库***时会调用该函数,可以在这里构造表、索引等System.out.println("createadatabase");//execSQL用于执行SQL语句db.execSQL("createtablenotebook(_idintegerprimarykeyautoincrement,picvarchar(50),titlevarchar(20),contenttext,timevarchar)");}@OverridepublicvoidonUpgrade(SQLiteDatabasedb,intoldVersion,intnewVersion){//如果给定的当前数据库版本高于现有数据库版本,调用此函数System.out.println("upgradeadatabase");}}SQLiteOpenHelper应用创建一个新的数据库管理类DBManagerpackagecom.example.notebook;importandroid.content.ContentValues;importandroid.content.Context;importandroid.database.Cursor;importandroid.database.sqlite.SQLiteDatabase;importandroid.database.sqlite.SQLiteException;importandroid.util.Log;publicclassDBManager{privateContextmContext=null;privateSQLiteDatabasemSQLiteDatabase=null;//用来操作数据库的对象privateDBHelperdh=null;//用来创建数据库的对象privateStringdbName="note.db";//数据库的名称privateintdbVersion=1;//版本数据库的publicDBManager(Contextcontext){mContext=context;}publicvoidopen(){try{dh=newDBHelper(mContext,dbName,null,dbVersion);//创建数据库if(dh==null){Log.v("多发性硬化症g","isnull");return;}mSQLiteDatabase=dh.getWritableDatabase();//以可写模式打开数据库//dh.onOpen(mSQLiteDatabase);}catch(SQLiteExceptionse){se.printStackTrace();}}publicvoidclose(){mSQLiteDatabase.close();//关闭数据库dh.close();}publicCursorselectAll(){Cursorcursor=null;try{//sql语句操作Stringsql="select*fromnotebook";cursor=mSQLiteDatabase.rawQuery(sql,null);}catch(Exceptionex){ex.printStackTrace();cursor=null;}returncursor;}publicCursorselectById(intid){//Stringresult[]={};Cursorcursor=null;try{//sql语句操作Stringsql="select*fromnotebookwhere_id='"+id+"'";cursor=mSQLiteDatabase.rawQuery(sql,null);}catch(Exceptionex){ex.printStackTrace();cursor=null;}returncursor;}publiclonginsert(Stringtitle,Stringcontent,Stringpic){longdatetime=System.currentTimeMillis();longl=-1;try{//结构化方法操作ContentValuescv=newContentValues();cv.put("title",title);cv.put("content",content);cv.put("time",datetime);cv.put("pic",pic);l=mSQLiteDatabase.insert("notebook",null,cv);//Log.v("datetime",datetime+""+l);}catch(Exceptionex){ex.printStackTrace();l=-1;}returnl;}publicintdelete(intid){intaffect=0;try{//结构操作affect=mSQLiteDatabase.delete("notebook","_id=?",newString[]{String.valueOf(id)});}catch(Exceptionex){ex.printStackTrace();affect=-1;}returnaffect;}publicintupdate(intid,Stringtitle,Stringcontent,Stringpic){intaffect=0;try{//操作ContentValuescv=newContentValues();cv.put("title",title);cv.put("content",content);cv.put("pic",pic);Stringw[]={String.valueOf(id)};affect=mSQLiteDatabase.update("notebook",cv,"_id=?",w);}catch(Exceptionex){ex.printStackTrace();affect=-1;}returnaffect;}}获取数据示例privateDBManagerrdm=null;//数据库管理对象rivateCursorcursor=null;dm=newDBManager(this);//数据库操作对象dm.open();//打开数据库操作对象cursor=dm.selectAll();//获取所有数据cursor.moveToFirst();//移动光标到第一条数据,必须调用intcount=cursor.getCount();//数字ArrayListcontents=newArrayList();//所有图片集合ArrayListimgs=newArrayList<字符串>;();//所有图片集合ArrayListitems=newArrayList();//所有标题集合ArrayListtimes=newArrayList();//所有时间集合for(inti=0;iadbshell->sqlite3<路径>/<数据库名称>->sqlite>select*fromsqmple;2、Android数据云服务云存储本质上就是将移动设备上的数据存储到远程服务器上。在Android中,增加了一些辅助功能,使得整个过程的实现更加容易。首先是通过谷歌账户识别用户身份。在android中,默认支持使用Google账号作为用户身份的标识,系统上的各个应用都可以通过账号系统获取用户的登录信息。其次,有了谷歌账号,开发者就不需要自己搭建后台服务系统了。Android云数据访问由系统服务BackupManagerService统一管理。当应用程序提交备份数据请求时,BackupManagerService会将请求放入备份队列,备份队列会按照一定的控制逻辑定时提交到云端。当系统安装新的应用时,会触发数据恢复事件,BackupManagerService会根据应用包名和用户账号从云端获取相应的备份数据,并尝试恢复。在实践中,Android会构造一个派生自BackupAgent类的子类android.app.backup.BackupAgentHelper的对象来更方便的构建云存储组件。importjava.io.File;importjava.io.IOException;importandroid.app.backup.BackupAgentHelper;importandroid.app.backup.BackupDataInput;importandroid.app.backup.BackupDataOutput;importandroid.app.backup.FileBackupHelper;importandroid.os.ParcelFileDescriptor;publicclassMyBackupAgentextendsBackupAgentHelper{privatestaticfinalStringKEY="my_backup";@OverridepublicvoidonCreate(){//构造文件读写对象,声明需要备份的文件FileBackupHelperhelper=newFileBackupHelper(this,"backup_file");addHelper(KEY,helper);super.onCreate();}@OverridepublicvoidonBackup(ParcelFileDescriptoroldState,BackupDataOutputdata,ParcelFileDescriptornewState)throwsIOException{//调用父方法,将整个文件提交到云端super.onBackup(oldState,data,newState);}@OverridepublicvoidonRestore(BackupDataInputdata,intappVersionCode,ParcelFileDescriptornewState)throwsIOException/call父类方法,用从云端获取的文件覆盖本地文件super.onRestore(data,appVersionCode,newState);}@OverridepublicvoidonRestoreFile(ParcelFileDescriptordata,longsize,Filedestination,inttype,longmode,longmtime)throwsIOException{//TODOAuto-generatedmethodstubsuper.onRestoreFile(data,size,destination,type,mode,mtime);}Android不会自行向云端提交数据,需要开发者显式调用android.app.backup.BackupManager的dataChanged函数触发和所有组件一样,云存储组件由系统管理。这就需要把组件的相关信息放到配置文件中。