版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Android移动存储解决方案目标学员:学习目标:
课程时长:Android中级开发者SharedPreferencesContentProvider文件数据库4学时,180分钟1SharedPreferences2ContentProvider4数据库3文件课程目录理解Android应用中重要的四种数据存储机制原理能够熟练的混合使用四种存储技术ContentProvider数据存储内部及外部文件的读取Sqlite数据库的使用1SharedPreferences2ContentProvider4数据库3文件课程目录SharedPreferencesSharedPreferences的介绍使用SharedPreferencesSharedPreference介绍软件配置参数的保存,windows采用ini文件保存,j2se应用采用properties属性文件保存,android应用可以采用SharedPreferencesSharedPreferences是一种轻量级的键值存储方式,其存储的数据必须是基本数据类型。SharedPreferences存储的数据以XML的形式存在,存储在/data/data/包名/shared_prefs目录下。下面是一个Preference文件的示例。 <?xmlversion='1.0'encoding='utf-8'standalone='yes'?> <map> <stringname="gender">男性</string> <stringname="name">jadde</string> </map>相关介绍-SharedPreferences接口通过Context提供的getSharedPreferences(名字,模式)方法来获取SharedPreferences实例,模式包括以下几种:Context.MODE_PRIVATE:Context.MODE_APPEND:Context.MODE_WORLD_READABLE:Context.MODE_WORLD_WRITABLE:例如:SharedPreferencespres=MainActivity.this.getSharedPreferences("soft",Context.MODE_WORLD_READABLE+Context.MODE_WORLD_WRITEABLE);相关介绍-Editor对象SharedPreferences接口没有提供写入数据的能力,要调用SharedPreferences的edit()来获取它所对应的Editor对象。它有一系列操作数据的方法.putString(Stringname,Stringvalue):存储键值,
getString(Stringname,Stringvalue):获取键值,
Clear():清除键值。
Commit():执行相关操作之后,调用此方法确认数据的改变。例如:Editoreditor=sharedPreferences.edit();editor.putString(“name”,”zy”);editor.putInt(“age”,44);mit();案例一:读取和写入数据
finalSharedPreferencessp=MainActivity.this.getSharedPreferences("ma",MainActivity.MODE_PRIVATE);
finalEditoreditor=sp.edit();write=(Button)this.findViewById(R.id.write);read=(Button)this.findViewById(R.id.read);result=(TextView)this.findViewById(R.id.result);write.setOnClickListener(newView.OnClickListener(){@OverridepublicvoidonClick(Viewv){Dated=newDate();DateFormatdf=newSimpleDateFormat("yyyy年MM月dd日");editor.putString("d",df.format(d));editor.putInt("randnum",(int)(Math.random()*100));mit();}});read.setOnClickListener(newView.OnClickListener(){@OverridepublicvoidonClick(Viewv){Stringd=sp.getString("d","");intrandnum=sp.getInt("randnum",0);result.setText("时间:"+d+"随机数为:"+randnum);}});案例二:记录程序运行次数案例三:读写其它应用SharedPreferences前提:创建的SharedPreferences文件的访问权限设定为:MODE_WORLD_READABLE或MODE_WORLD_WRITABLE步骤:1.创建其他程序对应的Context2.调用其它程序的SharedPreferences.案例:Contextcontext=MainActivity.this.createPackageContext("com.icss.test_sharedPreferences.ui",Context.CONTEXT_INCLUDE_CODE);SharedPreferencessp=context.getSharedPreferences("ma",Context.MODE_WORLD_WRITEABLE);1SharedPreferences2文件4数据库3课程目录ContentProvider文件文件存储概述内部存储外部存储读取资源文件XML文件解析之SAX解析,PULL解析.文件存储概述从存储位置上区分,Android的文件可以存储在手机的内存或者外部的存储卡上。Android平台支持完整的java.io包,文件操作与PC上的Java开发差异不大。内部存储默认情况下,在/data/data/<包名>/files/目录下创建文件,且生成一个文件输出流(FileOutputStream)对象。Context提供了openFileOutput(Stringname,intmode),name表示文件名,参数mode表示文件打开或者创建的方式。
MODE_PRIVATE:表示该文件只能被本应用访问; MODE_APPEND:表示新的内容会添加在原文件内容的后面; MODE_WORLD_WRITABLE:表示该文件能被所有应用写入; MODE_WORLD_READABLE:表示该文件能被所有应用读取;存储到data目录默认情况下,文件被存储在应用程序所在目录,其他应用程序无法访问。
//将文件存储至默认文件夹privatevoidsaveToDefault(byte[]buf)throwsIOException{ ileOutputStreamfos_1=openFileOutput("test_1.txt", Context.MODE_APPEND); os_1.write(buf); os_1.close();} 如果希望将文件存储在data目录下的子目录,可以使用File类。privatevoidsaveToDirectory(byte[]buf)throwsIOException{FiletextFile_2=newFile( "/data/data/com.A/test_2.txt"); FileOutputStreamfos_2=newFileOutputStream(textFile_2); fos_2.write(buf); fos_2.close();}读取内部文件调用Context类的openFileInput()方法,返回FileInputStream。调用read()方法从文件中读取数据操作完成后,调用close()方法关闭输入流。FileInputStreamfis_1=openFileInput("test_1.txt");fis_1.read(buf);fis_1.close(); 案例一:内部文件读写功能:在主界面输入文本后能存入到手机中,也能读取文本显示到界面上架构:MVC技术点:1.测试框架的使用2.文件流的操作3.手机文件操作案例一:内部文件读写步骤一:配置junit框架
<!--加载测试框架库文件--><uses-libraryandroid:name="android.test.runner"/>
<!--将当前应用放入到测试中运行--><instrumentationandroid:name="android.test.InstrumentationTestRunner"android:targetPackage="com.icss.test_innerfilereadwrite"android:label="test"/>
步骤二:完成业务类FileService
publicstaticvoidsave(OutputStreamoutputStream,byte[]content){ outputStream.write(content); outputStream.close();}
publicstaticbyte[]read(InputStreaminputStream){ byte[]result=null; ByteArrayOutputStreamoutputStream=newByteArrayOutputStream(); byte[]buffer=newbyte[1024]; intlen=-1; while((len=inputStream.read(buffer))!=-1){ outputStream.write(buffer,0,len); } result=outputStream.toByteArray(); inputStream.close(); outputStream.close(); returnresult;}
案例一:内部文件读写步骤三:junit框架测试
publicclassTestFileextendsAndroidTestCase{ publicvoidtestSave()throwsIOException{ //this指代的是当前测试类的对象,通过它取到这个应用的上下文对象 FileOutputStreamoutputStream=this.getContext().openFileOutput ("icss.txt",Context.MODE_APPEND); FileService.save(outputStream,"abc中国".getBytes()); } publicvoidtestRead()throwsIOException{ FileInputStreaminputStream=this.getContext().openFileInput("icss.txt"); byte[]result=FileService.read(inputStream); Log.i("read",newString(result,"utf-8")); }}步骤四:界面开发
FileOutputStreamoutputStream=MainActivity.this.openFileOutput(fn,Context.MODE_WORLD_READABLE+Context.MODE_WORLD_WRITEABLE);
通过修改上面的权限,可以控制是否让外部程序读取本应用中的文件.缓存文件不希望持久性存储文件,只是为了缓存。getCacheDir()可以返回File对象,代表临时的缓存文件。当内存不足的时候,系统可以选择删除这些缓存文件。缓存的空间不应该过大,应用程序应该自己维护这些文件。当应用程序被卸载,缓存文件也被删除。外部存储外部存储是指将文件存储在存储卡或者内置的存储设备上。通常使用File类操作外部存储的文件。
在参数path指定的位置创建文件。
参数path表示包含绝对路径的文件名,且该路径应在目录
“/data/data/<包名>/”或SD卡可写目录中。
使用FileOutputStream(Filefile)方法可以为创建的文件生成一
个文件输出流对象。案例二:将文件保存到SDCARD中在模拟器中使用SDCARD,你需要先创建一张SDCARD卡,创建SDCARD可以在Eclipse创建模拟器时随同创建,也可以使用DOS命令创建,如下:
在DOS窗口中进入androidSDK安装路径的tools目录,输入以下命令:Mksdcard2048mD:\androidtool\sdcard.img在程序中访问SDCARD,你需要申请访问SDCARDr权限.在androidManifest.xml中加入创建与删除文件权限:<uses-permissionandroid:name=”android.permission.MOUNT_UNMOUNT_FILESYSTEMS”/><uses-permissionandroid:name=”android.permission.WRITE_EXTERNAL_STORAGE”/>//判断是否存在SDCardIf(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){Filefile=newFile(Environment.getExternalStorageDirector(),filename); FileOutputStreamoutStream=newFileOutputStream(file); fileService.save(outStream,content); }读资源文件(一)对于本工程的res/raw目录下的资源文件,会在R清单类中生成一个索引项,通过Resources类的openRawResource方法,并得到输入流(InputStream)。InputStreamis=getResources().openRawResource(R.raw.test);案例:播放res/raw下的音乐finalMediaPlayermp=MediaPlayer.create(MainActivity.this,R.raw.a);Buttonb=(Button)this.findViewById(R.id.start);b.setOnClickListener(newView.OnClickListener(){@OverridepublicvoidonClick(Viewv){mp.start();}});读资源文件(二)对于本工程的assets目录下的资源文件,使用AssetManager的open方法,并得到输入流(InputStream)。InputStreamis=AssetManager.open(Stringname,intaccessMode);案例:播放Assets下的音乐AssetManageram=MainActivity.this.getAssets();AssetFileDescriptorafd=am.openFd("a.mp3");Buttonb=(Button)this.findViewById(R.id.start);b.setOnClickListener(newView.OnClickListener(){@OverridepublicvoidonClick(Viewv){ mp=newMediaPlayer(); mp.setDataSource(afd.getFileDescriptor()); mp.prepare(); mp.start();}});本案例演示向默认目录、指定目录、SD卡中存储数据,以及从资源文件中获得数据的方法,并介绍了文件不同的打开方式对存储结果的影响。下面是此案例运行的结果:XML解析在android平台上可以使用SimpleAPIfroXML(sax),DocumentobjectModel(DOM)和android附带的pull解析器解析XML文件.(一)Sax是一个解析速度快并且占用内存较少的xml解析器,适合用于移动设备。SAX采用事件驱动机制,即它并不需要解析完整个文档,在按内容顺序解析文档的过程中,SAX会判断当前读到的字符是否为合法XML语法中的某部分,如果符合就会触发事件。所谓事件,其实就是一些回调(callback)方法,这些方法(事件)定义在ContentHandler接口。下面是一些ContentHandler接口的常用方法:startDocument():当遇到文档的开头的时候调用这个方法,做预处理工作endDocument():当文档结束时调用此方法,做善后工作startElement(StringnamespaceURI,StringlocalName,StringqName,Attributesatts):当读到一个开始标签时,会触发这个方法。namespaceURI就是命名空间,localName是不带命名空间前缀的标签名,qName是带命名空间前缀的标签名。通过atts可以得到所有的属性名和相应的值。注意:SAX中一个重要的特点就是它的流式处理,当遇到一个标签的时候,它并不会记录下以前所碰到的标签,也就是说,在startElement()方法中,所有你所知道的信息,就是标签的名字和属性,至于标签所的嵌套的结构,上层标签的名字,是否有子元素等其它的与结构相关的信息,都是不得而知的,都需要你的程序来完成。endElement(Stringuri,StringlocalName,Stringname):结束标签时调用characters(char[]ch,intstart,intlength):用来处理在xml文件中读到的内容,第一个参数用于存放文件的内容,后面两个参数是读到的字符串在这个数组中的起始位置和长度,使用newString(ch,start,length)就可以获取内容.
XML解析-SAX解析模拟:
标签及内容
触发的事件{文档开始} startDocument()<students>startElement(“”,”persons”,null,”{Attributes}”)“\n\t”characters(“<students>…</students>”,”12”,’2”);<person>startElement(“”,”person”,null,”{Attributes}”)……
只要为SAX提供实现ContentHandler接口的类,那么这个类就可以得到通知事件(实际上是SAX调用了该类中的回调方法).因为ContentHandler是一个接口,在使用的时候可能会有些不方便,因此,SAX还为其制定了一个HELPer类:DefaultHandler,它实现了这个接口,但是其所有的方法体都为空,在实现的时候,你只需要继承这个类。然后重载相应的方法即可。案例-xml文件的SAX解析步骤一:写一个类继承自DefaultHandler类,并重写其中的方法步骤二:写一个业务类来获取解析器业务类的核心代码:
public
staticList<Student>readXML(InputStreaminputStream)
throwsException{ //设置解析器的相关特性,开启命名空间特性 //saxParser.setProperty("/sax/features/namespaces", //true); XMLContentHandlerhandler; SAXParserFactoryspf=SAXParserFactory.newInstance(); SAXParsersaxParser=spf.newSAXParser(); handler=newXMLContentHandler(); saxParser.parse(inputStream,handler); inputStream.close();
returnhandler.getStudents(); }案例-xml文件的SAX解析步骤三:界面的调用
分三种情况:1.访问类路径下的xml文件:InputStreaminputStream=MainActivity.this.getClassLoader().getResourceAsStream("students.xml");2.访问手机文件:
InputStreaminputStream=MainActivity.this.openFileInput("students.xml");3.访问SDCard上文件:
<uses-permissionandroid:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/><uses-permissionandroid:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){Filef=newFile(Environment.getExternalStorageDirectory(),"students.xml");InputStreaminputStream=newFileInputStream(f);
案例-XML文件的PULL解析Pull解析和Sax解析很相似,都是轻量级的解析,在Android的内核中已经嵌入了Pull,所以我们不需要再添加第三方jar包来支持Pull。Pull解析和Sax解析不一样的地方有(1)pull读取xml文件后触发相应的事件调用方法返回的是数字(2)pull可以在程序中控制想解析到哪里就可以停止解析。Android内置了PULL解析器。PULL解析器的运行原理与SAX类似。它提供类似事件,如开如元素和结束元素事件,使用parser.next()可以进入下一个元素并触发相应的事件。事件将作为数值代码被发送,因此可以使用一个switch对感兴趣的事件进行处理。当元素开如解析时,调用parser.nextText()方法可以获取下一个Text类型元素的值.Pull解析器的源码及文档网站:案例-XML文件的PULL保存publicstaticvoidsaveXmlByPull(List<Student>list,Writerwriter)throwsIllegalArgumentException,IllegalStateException,IOException{XmlSerializerserializer=Xml.newSerializer();serializer.setOutput(writer);serializer.startDocument("utf-8",true);serializer.startTag(null,"students");for(Students:list){serializer.startTag(null,"student");serializer.attribute(null,"id",""+s.getId());serializer.startTag(null,"name");serializer.text(s.getName());serializer.endTag(null,"name");serializer.startTag(null,"age");serializer.text(s.getAge()+"");serializer.endTag(null,"age");serializer.endTag(null,"student");}serializer.endTag(null,"students");serializer.endDocument();serializer.flush();writer.flush();}案例-XML文件的PULL保存1.本地文件写入:FileOutputStreamoutputStream=MainActivity.this.openFileOutput("s.xml",MODE_WORLD_WRITEABLE);OutputStreamWriterwriter=newOutputStreamWriter(outputStream);StudentBiz.saveXmlByPull(list,writer);2.SDCARD文件写入:
权限:<uses-permissionandroid:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/><uses-permissionandroid:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){Filef=newFile(Environment.getExternalStorageDirectory(),"s.xml");FileOutputStreamoutputStream=newFileOutputStream(f);OutputStreamWriterwriter=newOutputStreamWriter(outputStream);StudentBiz.saveXmlByPull(list,writer);}
PULL解析-作业要解析的网络文件:/iphone/xml/bj.xml要点提示:1.要访问网络,权限:<uses-permissionandroid:name="android.permission.INTERNET"></uses-permission>2.网络访问:
xmlPullParser.setInput(url.openConnection().getInputStream(),"UTF-8");3.分析Xml文件,找出它的格式,并分析出有用的数据.
源代码1SharedPreferences2ContentProvider4文件3数据库课程目录数据库数据库概述创建数据库操作数据SQLite数据库介绍Android平台内置了对SQLite数据库,它是轻量级的嵌入式数据库。对于数据结构较为复杂的关系型数据,使用SQLite存储将非常高效。应用程序创建的数据库文件存储在/data/data/包名/database目录下,应用程序之间不能相互访问。SQLite在底层就是一个文件.数据类型:NULL,Integer,real,text,blob.创建数据库使用下面的方法可以创建一个SQLite数据库Context.openOrCreateDatabase(Stringname,intmode,CursorFactoryfactory)name代表数据库的名称。mode代表创建数据库的模式,包括MODE_PRIVATEMODE_WORLD_READABLE、MODE_WORLD_WRITEABLE。用于查询构造Cursor子类的对象,通常设置为null。例:Db=SQLiteDatabase.openOrCreateDatabase(“/mnt/db/temp.db3”,null);Sql=“createtablestudent(_idintegerprimarykey,namevarchar(50),passwordvarchar(50)):Db.execSQL(sql);//注意:最好将主键列的列名设为_id,以便与后面的适配器整合使用SQLiteDatebase的常用方法execSQL(String,sql,Object[]bindArgs):execSQL(Stringsql):CursorrawQuery(Stringsql,String[]selectionArgs):beginTransaction():开始事务endTransaction():结束事务setTransactionSuccessful();设置事务成功标志查询方法返回的是一个Cursor对象,有以下方法来访问游标:Move(intoffset):moveToFirst():moveToLast():moveToNext():moveToPosition():moveToPrevious():getXXX():获取该行数据指定列的值.案例一要求:添加两行数据后,查询所有的数据,返回Cursor对象,绑定到SimpleCursorAdapter上,并显示在ListView中.一。保存的方法
protectedvoidsave(SQLiteDatabasedb2,Stringtstr,Stringcstr){db2.beginTransaction();try{db2.execSQL("insertintosongsvalues(null,?,?)",newString[]{tstr,cstr});db2.setTransactionSuccessful();}catch(SQLExceptione){e.printStackTrace();}db2.endTransaction();}二.显示的方法protectedvoidshowList(Cursorc){SimpleCursorAdapteradapter=newSimpleCursorAdapter(MainActivity.this,R.layout.list_item,c,newString[]{"title","content"},newint[]{R.id.titleshow,R.id.contentshow});result.setAdapter(adapter);}三.事件调用//取出数据库db=SQLiteDatabase.openOrCreateDatabase(this.getFilesDir()+"/my.db3",null);save.setOnClickListener(newView.OnClickListener(){@OverridepublicvoidonClick(Viewv){Stringtstr=title.getText().toString();Stringcstr=content.getText().toString();try{save(db,tstr,cstr);Cursorc=db.rawQuery("select*fromsongs",null);showList(c);}catch(Exceptione){//当第一次访问的时候,创建表db.execSQL("createtablesongs(_idintegerprimarykeyautoincrement,title,content)");save(db,tstr,cstr);Cursorc=db.rawQuery("select*fromsongs",null);showList(c);}}});使用SQLiteOpenHelper在Android系统中,提供了一个名为SQLiteOpenHelper的类,对数据库版本进行管理,它是一个抽象类,它有两个重载方法:onCreate(SQLiteDatabasedb)和onUpgrade(SQLiteDatabasedb,intoldVersion,intnewVersion)当调用SQLiteOpenHelper的getWritableDatabase()或者getReadableDatabase()方法获取用于操作数据库的SQLiteDatabase实例的时候,如果数据库不存在,android系统支自动生成一个数据库,接着调用onCreate()方法,onCreate()方法在初次生成数据库时才会被调用,在onCreate()方法里可以生成数据库使的结构及添加一些应用使用到的初始化数据。onUpgrade()方法在数据库表的版本发生变化时会被调用,数据库的版本是由程序员控制,假设数据库现在的版本是1,由于业务的需要,修改了数据库表的结构,这时候就需要升级软件,升级软件希望更新用户手机里的数据库表结构,这样就可以把原来数据库版本设置为2,并且在onUpgrade()方法里面实现结构的更新,当软件的版本升级次数比较多,这时在onUpgrade())方法里面可以根据原版本号和目标版本号进行判断,然后作出相应的表结构及数据更新.getWritableDatabase()和getReadableDatabase()方法都是可以获取一个用于操作数据库的SQLiteDatabase实例,但getWritable()方法以读写方式打开数据库,一旦数据库空间满了,db就只能读需不能写,若使用的是getWritableDataqbase())衣服就会出错,getReadableDatabase()方法先以读写方式打开数据库,如空间满了,就会打开失败,当打开失败后可以只读方式打开使用SQLiteOpenHelper使用SQLiteOpenHelper创建数据库不会重复执行数据库的初始化操作。不需要查询数据库是否存在,执行效率更高。SQLiteOpenHelper是一个抽象类,需要实现如下方法:onCreate(SQLiteDatabasedb)onUpgrade(SQLiteDatabasedb,intoldVersion,intnewVersion)调用getWritableDatabase()可以获得可写的SQLiteDatabase对象。调用getReadableDatabase()可以获得一个只读的SQLiteDatabase对象。案例:采用SQLiteOpenHelper封装(一)DataBaseOpenHelper类:用于创建和修改数据库publicclassDataBaseOpenHelperextendsSQLiteOpenHelper{privatestaticfinalStringDBNAME="persondb";privatestaticfinalintVERSION=1;publicDataBaseOpenHelper(Contextcontext,Stringname,CursorFactoryfactory,intversion){super(context,name,null,version);}publicDataBaseOpenHelper(Contextcontext){this(context,DBNAME,null,VERSION);}@OverridepublicvoidonCreate(SQLiteDatabasedb){db.execSQL("createtableperson(_idintegerprimarykeyautoincrement,namevarchar(50),ageinteger)");}@OverridepublicvoidonUpgrade(SQLiteDatabasedb,intoldVersion,intnewVersion){db.execSQL("droptableifexistsperson");onCreate(db);}}案例:采用SQLiteOpenHelper封装(二)业务类:
privateDataBaseOpenHelperdb;privateContextcontext;publicPersonBiz(Contextcontext){this.context=context;db=newDataBaseOpenHelper(context);}publicvoidsave(Personperson){SQLiteDatabasedatabase=db.getWritableDatabase();database.execSQL("insertintoperson(name,age)values(?,?)",newObject[]{person.getName(),person.getAge()});}publicvoidupdate(Personperson){SQLiteDatabasedatabase=db.getWritableDatabase();database.execSQL("updatepersonsetname=?,age=?where_id=?",newObject[]{person.getName(),person.getAge(),person.get_id()});}publicPersonfind(Integer_id){Personp=null;SQLiteDatabasedatabase=db.getReadableDatabase();Cursorc=database.rawQuery("sleect*frompersonwhere_id=?",newString[]{_id+""});while(c.moveToNext()){p=newPerson();p.set_id(c.getInt(0));p.setName(c.getString(1));p.setAge(c.getInt(2));}returnp;}案例:采用SQLiteOpenHelper封装(三)publicvoiddelete(Integer...ids){SQLiteDatabasedatabase=db.getWritableDatabase();if(ids!=null&&ids.length>0){StringBuildersb=newStringBuilder();for(Integerid:ids){sb.append("?").append(",");}sb.deleteCharAt(sb.length()-1);database.execSQL("deletefrompersonwhere_idin("+sb+")",(Object[])ids);}}publicList<Person>getDataByPage(intstartResult,intmaxResult){List<Person>persons=newArrayList<Person>();SQLiteDatabasedatabase=db.getReadableDatabase();Cursorc=database.rawQuery("select*frompersonlimit?,?",newString[]{String.valueOf(startResult),String.valueOf(maxResult)});while(c.moveToNext()){persons.add(newPerson(c.getInt(0),c.getString(1),c.getInt(2)));}returnpersons;}publiclonggetCount(){SQLiteDatabasedatabase=db.getReadableDatabase();Cursorc=database.rawQuery("selectcount(*)fromperson",null);while(c.moveToNext()){returnc.getLong(0);}return0;}数据库调试Sqlite3命令可以用于管理数据库、查询数据库表结构。AdbshellSqlite3/data/data/包名/databases/publisher.db使用.dump,select等命令查看数据库.exit,退出.databases:查看当前数据库.tables:.help案例:英文单词生词本要求:能将英文生词添加到数据库保存起来,可以查找单词意思.示例代码:生词本设计一个数据库实例AUTHOR_TABLE中定义作者的相关信息,主键为id。BOOK_TABLE中定义了书的相关信息,主键为id,通过author_id与AUTHOR_TABLE建立关联。两个表结构的定义如下所示:获取SQLiteDatabase实例获取一个可读的SQLiteDatabaseSQLiteDatabasedb=SQLOpenHelper.getReadableDatabase()获取一个可写的SQLiteDatabaseSQLiteDatabasedb=SQLOpenHelper.getWriteableDatabase()创建触发器触发器(Trigger)机制:在试图对指定的数据表执行指定的修改语句时,特定的数据操作将被自动执行,实现关联操作。db.execSQL("CREATETRIGGERbook_deleteDELETEON"+Publisher.AUTHOR_TABLE+""+"BEGIN"+"DELETEFROM"+Publisher.BOOK_TABLE+"WHERE"+Publisher.BOOK.AUTHOR_ID+"=old._id;"+"END;");//在数据库升级时,应该在onUpdate方法中删除已经创建的触发器db.execSQL("DROPTRIGERIFEXISTSbook_delete");创建索引索引(Index)是对数据表中一列或多列的值进行排序的一种结构。使用索引可以更快地查找数据,而不用读取整个表。更新一个含有索引的表的时间要比更新没有索引的表的时间长,因此,通常仅仅在经常被检索的列上创建索引。//建立了一个针对AUTHOR_TABLE表的NAME列的降序索引db.execSQL("CREATEINDEXauthorname_indexON"+Publisher.AUTHOR_TABLE+"("+Publisher.AUTHOR.NAME+""+DESC+");");
创建视图视图(View)用来表示一个或多个表中的记录,可以在数据库中生成虚拟表。视图的创建过程中经常使用到连接操作,通过该操作可以联合查询多个表。db.execSQL("CREATEVIEWIFNOTEXISTS"+Publisher.BOOK_AUTHOR_TABLE+"AS"+"SELECT"+Publisher.BOOK_TABLE+".*"+","+Publisher.AUTHOR.NAME+"FROM"+Publisher.BOOK_TABLE+"LEFTOUTERJOIN"+Publisher.AUTHOR_TABLE+"ON"+Publisher.AUTHOR_TABLE+"."+Publisher.AUTHOR._ID+"="+Publisher.BOOK_TABLE+"."+Publisher.BOOK.AUTHOR_ID);插入数据execSQL方法db.execSQL("INSERTINTO"+Publisher.AUTHOR_TABLE+"(author_name,address,phone)"+"VALUES("+"‵"+name+"',"+"'"+address+"',"+"'"+phone+"'"+")");insert方法ContentValuesvalues=newContentValues();values.put(Publisher.AUTHOR.NAME,name);values.put(Publisher.AUTHOR.ADDRESS,address);values.put(Publisher.AUTHOR.PHONE,phone);SQLiteDatabasedb=helper.getWritableDatabase();db.insert(Publisher.AUTHOR_TABLE,null,values);删除数据execSQL方法db.execSQL("DELETEFROM"+Publisher.AUTHOR_TABLE+"WHERE"+AUTHOR._ID+"="+author_id);delete方法(不使用通配符)db.delete(Publisher.AUTHOR_TABLE,Publisher.AUTHOR._ID+"="+author_id,null);delete方法(使用通配符)db.delete(Publisher.AUTHOR_TABLE,Publisher.AUTHOR._ID+"=?",newString[]{String.valueOf(author_id)});更新数据execSQL方法db.execSQL("UPDATE"+Publisher.AUTHOR_TABLE+"SET"+AUTHOR.NAME+"='"+name+"'"+","+AUTHOR.ADDRESS+"='"+address+"'"+","+AUTHOR.PHONE+"='"+phone+"'"+"WHERE"+AUTHOR._ID+"="+id);update方法ContentValuesvalues=newContentValues();values.put(Publisher.AUTHOR.NAME,name);values.put(Publisher.AUTHOR.ADDRESS,address);values.put(Publisher.AUTHOR.PHONE,phone);SQLiteDatabasedb=helper.getWritableDatabase();db.update(Publisher.AUTHOR_TABLE,values,Publisher.AUTHOR._ID+"="+id,null);查询数据SQLiteDatabase提供了Cursorquery(Stringtable,String[]columns,Stringselection,String[]selectionArgs,StringgroupBy,Stringhaving,StringorderBy)方法来实现查询记录.able代表查询的数据表Columns代表要查询的列数组election代表查询的条件,可以使用“?”通配符selectionArgs代表selection表达式中的?roupBy代表数据分组Having代表哪些行显示rderBy代表排序的方式Cursor
Cursor类用于对数据库查询的结果进行随机的读写访问。默认情况下Cursor的游标位于返回的所有数据行的前面。
Cursor常用方法如下:move(intoffset)将当前游标移动offset个位置。moveToFirst()将游标移动到第一行。moveToLast()将游标移动到最后一行。isLast()判断游标是否在最后一行。isFirst()判断游标是否在第一行。getPosition()获得游标当前所在行的位置。getCount()获得cursor中的所有行数。1SharedPreferences2文件4ContentProvider3课程目录数据库ContentProviderContentProvider概述创建ContentProviderContentProvider更新的通知机制访问ContentProviderContentProvider概述ContentProvider允许应用程序之间共享数据,通话记录,多媒体数据等均是以ContentProvider的格式存储。ContentProvider提供了一系列标准的方法接口。ContentProvider的数据可以使用文件、数据库等多种方式存储。每个ContentProvider都拥有一个通用资源标识符(URI)作为身份标识。ContentProvider的优点当应用继承ContentProvider类,并重写该类用于提供数据和存储数据的方法,就可以向其他应用共享其数据,虽然使用其他方法也可以对外共享数据,但数据访问方式会因数据存储的方式而不同,如,采用文件方式对外共享数据,需要进行文件操作读写数据,采用sharedPreferences共享数据,需要使用SharedPreferencesAPI读写数据。而使用ContentProvider共享数据的好处是统一了数据访问方式。Android平台上常用的ContentProviderBrowser:读取或修改标签、浏览历史和网络搜索记录;CallLog:读取或修改通话记录Contacts:读取或修改联系人信息;MediaStore:提供对多媒体文件(包括音频、视频等)的读/写控制,MediaStore中保存的文件可以全局访问。Settings:读取或修改设备设置信息。ContentProvider的数据模型ContentProvider以表格的形式将数据暴露给客户端,每一行代表一条记录。ContentProvider原理当一个应用程序需要把自己的数据暴露给其它程序使用时,该应用程序就可以通过提供ContentProvider来实现;其它应用程序使用ContentResolver来操作ContentProvider暴露的数据.一旦某个应用程序通过ContentProvider暴露了自己的数据操作接口,那么不管该应用程序是否启动,其他应用程序都可以通过该接口操作该应用程序内部的数据.
使用ContentProvider向外发布共享数据当应用需要通过ContentProvider对外共享数据时,第一步需要继承contentProvider并重写下面方法:publicclassPersonContentProviderextendsContentProvider{ publicbooleanonCreate();publicURIinsert(Uriuri,ContentValuesvalues);publicintdelete(Uriuri,Stringselection,String[]selectionArgs);publicintudpate(Uriuri,ContextValuesvalues,Stringselection,String[]selectionArgs);publicCursorquery(Uriuri,String[]projection,Stringselection,String[]selectionArgs,StringsortOrder);publicStringgetType(Uriuri);}
第二步需要在AndroidManifest.xml使用<provider>对该ContentProvider进行配置,为了能让其他应用找到该ContentProvider,ContentProvider采用了authorities(主机名/域名)对它进行唯一标识,你可以把ContentProvider看作是一个网站,authorities就是他的域名:<manifest….><applicationandroid:icon=“@drawable/icon”android:label=“@string/app_name”><providerandroid:name=“.PersonContentProvider”android:authorities=“vider.personprovider”/></application></manifest>配置注释:.PersonContentProvider是类的名字authorities后面是域名案例:将生词本向外发布ContentProvider的主要方法onCreate():在类创建后调用,android在系统启动时就会创建ContentProvider.getType(Uriuri):返回当前Uri所代表数据的MIME类型。如操作的数据属于集合类型,那么MIME类型字符串的开头应为:vnd.android.cursor.dir/.例如:1.要得到所有person记录的uri为:content://vider.PersonContentProvider/person,而返回的MIME类型字符串应为:vnd.android.cursor.dir/开头2.要得到id为10的person记录,Uri为content://vider.PersonContentProvider/person/10,而返回的MIME类型字符串应为:vnd.android.cursor.item/person
Uri介绍Uri代表了要操作的数据,Uri主要包含两部分信息:1.需要操作的ContentProvider的网站域名2.对ContentProvider中的什么数据进行操作
一个Uri由以下几个部分组成:
content://vider.personprovider/person/10ContentProvider的schema已经由Android所规定,
schema为:content://
主机名(或叫Authority)用于唯一标识这个ContentProvider,外部调用者可以根据这个标识来找到它。
路径(path)/数据部分:可以用来表示我们要操作的数据,路径的构建应根据业务而定,如下:
要操作person表中id为10的记录,路径:/person/10
要操作person表中id为10的记录的name字段,路径:/person/10/name
要操作person表中所有的记录:/person
当然要操作的数据不一定来自数据库,也可以是文件等其他存储方式,如下:
要操作xml文件中person节点下的name属性:/person/name
将一个字符串转换成Uri,可以使用Uri类中的parse()方法Uriuri=Uri.parse(“content://vider.personprovier/person”);URIURI的组成为:<standard_prefix>://<authority>/<data_path>/<id>标准的前缀唯一标识整个ContentProvider描述了数据的路径,确定返回哪类数据ID唯一标注请求的数据使用ContentResolver操作数据通过Context的getContentResolver()方法获取ContentResolver对象.该对象有如下方法:insert(Uriuri,ContentValuesvalues):Delete(Uriuri,Stringwhere,String[]selectionArgs):Update(Uriuri,ContentValuesvalues,Stringwhere,String[]selectionArgs):Query(Uriuri,String[]projection,Stringselection,StringselectionArgs,Stringsortorder):UriMatcherAndroid平台通过自带的UriMatcher类来匹配当前ContentProvider中的URI,通过UriMatcher类的addURI方法来建立URI和指定数据种类的关系。addURI(Stringauthority,Stringpath,intcode)static{uriMatcher=newUriMatcher(UriMatcher.NO_MATCH);uriMatcher.addURI(PROVIDER_NAME,"authortable",AUTHORTABLE);uriMatcher.addURI(PROVIDER_NAME,"authortable/#",AUTHORTABLE_ID);uriMatcher.addURI(PROVIDER_NAME,"booktable",BOOKTABLE);uriMatcher.addURI(PROVIDER_NAME,"booktable/#",BOOKTABLE_ID);}创建ContentProvider的步骤确定用于存储ContentProvider数据
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025大豆买卖合同
- 2025房屋出租合同范本
- 2025品牌酒类买卖合同
- 物业公司保洁外包合同范本(7篇)
- 现代物流中的智能灌装机技术应用探讨
- 科技厨房中的智能餐具及其使用技巧
- 课题申报参考:跨文化传播中的话语体系建设与国家形象塑造研究
- 教育游戏在促进学生合作学习中的作用
- 科技型企业的绿色实验室建设策略
- 数学游戏在巩固小学基础知识中的作用
- 中华人民共和国保守国家秘密法实施条例培训课件
- 管道坡口技术培训
- 2024年全国统一高考英语试卷(新课标Ⅰ卷)含答案
- 2024年认证行业法律法规及认证基础知识 CCAA年度确认 试题与答案
- 皮肤储存新技术及临床应用
- 外研版七年级英语上册《阅读理解》专项练习题(含答案)
- 2024年辽宁石化职业技术学院单招职业适应性测试题库必考题
- 上海市复旦大学附中2024届高考冲刺模拟数学试题含解析
- 幼儿园公开课:大班健康《国王生病了》课件
- 小学六年级说明文阅读题与答案大全
- 人教pep小学六年级上册英语阅读理解练习题大全含答案
评论
0/150
提交评论