1719Android开发技术讲义 之保存数据.docx
- 文档编号:3151984
- 上传时间:2023-05-05
- 格式:DOCX
- 页数:14
- 大小:25.37KB
1719Android开发技术讲义 之保存数据.docx
《1719Android开发技术讲义 之保存数据.docx》由会员分享,可在线阅读,更多相关《1719Android开发技术讲义 之保存数据.docx(14页珍藏版)》请在冰点文库上搜索。
1719Android开发技术讲义之保存数据
Android开发技术讲义之保存数据
大部分的android的app需要保存数据,即使在onPause()方法中也要保存app的状态信息以免用户进度丢失。
大部分的比较好的app会需要保存用户设置,并且一些app必须管理大量的文件和数据库信息。
这里我们看看一些重要的数据存储方法,包括:
●以键值对的方式将简单的数据类型保存在共享preference文件中
●保存基本的文件
●使用SQLite管理数据库
保存键值对集合
如果你要保存一个相对较小的键值对集合,你应该使用SharedPreferences。
一个SharedPreferences对象指向一个保存键值对的文件,并且提供了简单的方法来读写它们。
每个SharedPreferences文件都是由系统管理的,它可以是私有或者共享的。
SharedPreferencesAPI仅仅提供了读写键值对的功能,你不要和PreferenceAPI相混淆。
后者可以帮助你创建一个设置用户配置的UI(尽管也会使用SharedPreferences来保存app的设置)
获取SharedPreferences的handle
你可以通过调用下面的两个方法来创建或访问一个sharedpreference:
●getSharedPreferences()如果你需要通过名字区分多个共享preference文件,该方法的第一个参数就是名字,你可以在任何一个Context中来调用这个方法。
●getPreferences()当你的activity仅仅需要一个sharedpreference文件的时候。
因为这个方法会检索activity的默认共享preference文件,所以你不需要提供名字。
例如,下面的代码会在一个Fragment中执行,它存取通过资源字符串R.string.preference_file_key标示的共享preference文件,并使用private模式打开它,这时该文件就只能由你的app存取。
Contextcontext=getActivity();
SharedPreferencessharedPref=context.getSharedPreferences(
getString(R.string.preference_file_key),Context.MODE_PRIVATE);
当你命名你的共享preference文件的时候,应该用一个能够唯一标示它的名字,比如:
"com.example.myapp.PREFERENCE_FILE_KEY"
另外,如果你的activity只需要一个共享preference文件,你可以使用getPreferences()方法:
SharedPreferencessharedPref=getActivity().getPreferences(Context.MODE_PRIVATE);
注意:
如果你在创建共享preference文件的时候使用MODE_WORLD_READABLE或者MODE_WORLD_WRITEABLE,任何其他知道该文件的app均可以存取你的数据。
写入SharedPreferences
为了写入共享preference文件,需要通过调用SharedPreferences的edit()方法来创建SharedPreferences.Editor。
通过类似putInt()和putString()方法来传递key和value。
然后调用commit()来保存该变化。
例如:
SharedPreferencessharedPref=getActivity().getPreferences(Context.MODE_PRIVATE);
SharedPreferences.Editoreditor=sharedPref.edit();
editor.putInt(getString(R.string.saved_high_score),newHighScore);
mit();
从共享Preference文件中读取数据
为从一个共享preference文件中提取值,需要调用getInt()和getString()方法,给这些方法传递你需要获取值的key,如果没有对应key值,会返回一个默认值。
SharedPreferencessharedPref=getActivity().getPreferences(Context.MODE_PRIVATE);
intdefaultValue=getResources().getInteger(R.string.saved_high_score_default);
longhighScore=sharedPref.getInt(getString(R.string.saved_high_score),defaultValue);
保存文件
android所使用的文件系统和基于磁盘的文件系统类似。
我们来看看通过File来读写文件。
File对象适合读写那种流式顺序的大量数据。
比如图片文件或者在网络上交换的数据。
选择内部还是外部存储区
所有的Android设备有两个文件存储区域:
"internal"and"external"。
这些名字来自于Android早期,那时大部分设备提供内置的非易失内存(internal存储),再加一个可移除的存储媒介,如SD卡(external存储)。
一些设备把持久的存储空间分为了intenal和external分区,所以即使没有可移除的存储媒介,也有两种存储空间,并且不管是不是可移除的,API的行为也是一致的。
Internal存储
External存储
总是可用
不是总可用的,由于用户可以mountexternal存储为USB存储,在某些情况下会从设备中移除。
存储在这里的文件默认是只能你的app来访问的。
是world-readable的,因此存在这里的文件,它的读取不受你的控制
当用户卸载你的app的时候,系统会移除internal中你的app的所有文件
当用户卸载你的app的时候,系统移除你app在通过getExternalFilesDir()方法取到的目录中的文件
Internal存储区是确保不被用户和其他app所访问的最佳存储区域,而external存储区是不需要访问控制,并且需要同其他app共享或者允许用户通过计算机访问的最佳存储区域。
提示:
尽管app默认是安装到internal存储区的,但你可以在你的manifest文件中指定android:
installLocation属性,这样你的app就可以安装在external存储区。
当APK比较大的时候,而且external存储比internal存储区大的多的时候,用户是比较喜欢这种选择的。
获取对external存储区的存取权限
为了向external存储区写数据,你必须在manifest文件中获取WRITE_EXTERNAL_STORAGE权限。
name="android.permission.WRITE_EXTERNAL_STORAGE"/> ... 注意: 当前,所有的app都不需特别的权限就可以读取外部存储区。 这种情况未来可能会发生变化。 如果你的app需要读取(而不是写)external存储区,你需要声明READ_EXTERNAL_STORAGE权限。 为保证你的app将来也可以很好的工作,你应该现在就声明这个权限。 然而,如果你的app使用WRITE_EXTERNAL_STORAGE权限,就意味着你对external存储区同时有读权限。 你在internal存储区中保存文件的时候,不需要任何权限。 你的app总是对internal存储区目录具有读写权的。 在internal存储区中存文件 当向internal存储区存放文件的时候,你可以通过执行下面中的两个方法之一来获取合适的目录作为File对象。 ●getFilesDir()为你的app返回一个代表internal目录的File对象 ●getCacheDir()返回一个用于存放你的app临时缓存文件的internal目录。 确保这些文件一旦不再需要就马上删除掉,并给出一个合理大小的使用限制,比如1MB。 如果系统的运行存储低了,cache文件会被自行删除。 为了在这里目录中创建一个新的文件,你可以使用File()构造方法,将上述方法作为参数传递过去。 如: Filefile=newFile(context.getFilesDir(),filename); 另外,你可以调用openFileOutput()方法来获取FileOutputStream,向internal目录中写文件,如: Stringfilename="myfile"; Stringstring="Helloworld! "; FileOutputStreamoutputStream; try{ outputStream=openFileOutput(filename,Context.MODE_PRIVATE); outputStream.write(string.getBytes()); outputStream.close(); }catch(Exceptione){ e.printStackTrace(); } 或者,如果你需要缓存一些文件,你应该使用createTempFile()。 例如,下面的方法从URL重提取文件名,并且以该名字在你的app内部缓存目录中创建文件。 publicFilegetTempFile(Contextcontext,Stringurl){ Filefile; try{ StringfileName=Uri.parse(url).getLastPathSegment(); //createTempFile(Stringprefix,Stringsuffix,Filedirectory) //在指定目录中创建空文件,用给定的前缀名prefix和后缀名suffix file=File.createTempFile(fileName,null,context.getCacheDir()); catch(IOExceptione){ //Errorwhilecreatingfile } returnfile; } 注意: 你的app的internal存储目录在android文件系统的特定位置,由你的app包名所标示。 技术上,如果你设置文件的模式为可读的,其他的app就可以读取你的internal文件。 然而,其他的app也需要知道你的app的包名和文件名。 若是你没有设置为可读或可写,其他的app是没有办法进行读写的。 因此,只要你使用MODE_PRIVATE,这些文件就不可能被其他app所访问。 在external存储区中保存文件 因为external存储区可能不可用,比如用户将存储mount到PC了,也或者将SD卡移除了。 你在使用之前一定要检查是否可用。 你可以通过getExternalStorageState()获取外部存储区的状态,如果返回的状态等于MEDIA_MOUNTED,那么你就可以读写你的文件。 例如,下面的方法用于判断是否存储区可用: /*Checksifexternalstorageisavailableforreadandwrite*/ publicbooleanisExternalStorageWritable(){ Stringstate=Environment.getExternalStorageState(); if(Environment.MEDIA_MOUNTED.equals(state)){ returntrue; } returnfalse; } /*Checksifexternalstorageisavailabletoatleastread*/ publicbooleanisExternalStorageReadable(){ Stringstate=Environment.getExternalStorageState(); if(Environment.MEDIA_MOUNTED.equals(state)|| Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)){ returntrue; } returnfalse; } 尽管external存储可以被用户和其他app所修改,但还是把你可能存放在这里的文件分为两类: ●public文件: 这类文件可以被其他app和用户自由存取。 当用户卸载你的app的时候,这些文件对用户依然可用。 如你的app照的照片或其他下载的文件。 ●Private文件: 这些文件属于你的app,当用户删除你的app的时候,这些文件应一并删除。 尽管这些文件在技术上可以被用户与其他app所访问,但对于其他的app没有意义。 当用户卸载掉你的app的时候,你的app的外部私有目录会被删除。 比如你的app下载的附加资源或临时媒体文件。 如果你要在external存储区保存public文件,使用getExternalStoragePublicDirectory()方法来获取一个File对象表示外部存储区中的目录。 该方法需要设置一个参数用于指定你要保存的文件的类型,以便对该文件进行分类,比如: DIRECTORY_MUSICorDIRECTORY_PICTURES,例如: publicFilegetAlbumStorageDir(StringalbumName){ //Getthedirectoryfortheuser'spublicpicturesdirectory. Filefile=newFile(Environment.getExternalStoragePublicDirectory( Environment.DIRECTORY_PICTURES),albumName); if(! file.mkdirs()){ Log.e(LOG_TAG,"Directorynotcreated"); } returnfile; } 如果你要保存的文件对你的app是私有的,你可以通过调用getExternalFilesDir()来获取相应的目录,并且传递一个表示文件类型的参数。 每个以这种方式创建的目录都会被添加到用于封装你的app外部存储文件的父目录中,当你的app卸载的时候,该目录会被删除。 下例的方法可以用于创建一个个人photoalbum目录 publicFilegetAlbumStorageDir(Contextcontext,StringalbumName){ //Getthedirectoryfortheapp'sprivatepicturesdirectory. Filefile=newFile(context.getExternalFilesDir( Environment.DIRECTORY_PICTURES),albumName); if(! file.mkdirs()){ Log.e(LOG_TAG,"Directorynotcreated"); } returnfile; } 如果刚开始的时候,没有预定义的子目录存放你的文件,你可以给getExternalFilesDir()传递null,它会返回你的app在外部存储下的私有的根目录。 请记住,getExternalFilesDir()方法创建在某个目录中的目录在以后卸载你的app的时候会被删除。 如果你的文件想在app被删除的时候仍然保留,比如照片等,你应该使用getExternalStoragePublicDirectory()。 不管你是使用getExternalStoragePublicDirectory()来存储可以共享的文件,还是使用getExternalFilesDir()来储存那些对于你的app来说是私有的文件,有一点很重要,那就是你要使用那些类似DIRECTORY_PICTURES的API常量。 那些目录类型参数可以确保那些文件被系统正确的对待。 例如,那些以DIRECTORY_RINGTONES类型保存的文件就会被系统的mediascanner认为是ringtone而不是音乐。 查询剩余空间 如果你事先知道你想要保存的文件大小,你可以通过执行getFreeSpace()或者getTotalSpace()来判断是否有足够的空间来保存文件,从而避免发生IOException。 那些方法提供了当前可用的空间还有存储系统的总容量。 然而,系统并不能保证你可以写入通过GetFreeSpace()查询到的容量文件,如果查询的剩余容量比你的文件大小多几MB,或者文件系统使用率还不足90%,这样则可以继续进行写的操作,否则你最好不要写进去。 注意: 你并没有被强制要求在写文件之前一定要去检查剩余容量。 你可以直接先做写的动作,然后通过捕获IOException。 这种做法仅适合于你实现并不知道你想要写的文件的确切大小。 例如,如果在把PNG图片转换成JPEG之前,你并不知道最终生成的图片大小是多少。 删除文件 你应该在不需要使用某些文件的时候,删除它。 删除文件最直接的方法是直接执行文件的delete()方法。 myFile.delete(); 如果文件是保存在internalstorage,你可以通过Context来访问并通过执行deleteFile()进行删除 myContext.deleteFile(fileName); 注意: 当用户卸载你的app时,android系统会删除下面的文件: ●所有保存到internalstorage的文件 ●所有使用getExternalFilesDir()方式保存在externalstorage的文件 然而,通常来说,你应该手动删除所有通过getCacheDir()方式创建的缓存文件,还有那些不会再用到的文件。 在SQL数据库中存放数据 将重复或者结构化的数据保存到数据库中是个不错的主意。 在android中,你操作数据库所需要使用的API均在android.database.sqlite这个包中。 定义schema与contract SQL中一个主要的概念是schema: 一种数据库组织结构的正式声明。 Schema是通过你用于创建你的数据库的SQL所反映的。 你会发现创建一个companion类会比较有用,也就是contract类,它用一种系统化并且自动生成文档的方式,显式指定了你的schema的布局。 Contract类是一些常量的容器,它定义了URI的名字、表名、列名等。 Contract类允许你在同一个包下与其它类使用共同的常量。 这使得你只需要在一个地方修改列名,然后就可以自动传递给你整个代码。 一种组织contract类的好方式是在你的类的根层级定义,该定义全局于你的整个数据库的定义。 然后针对每个表创建一个内部类,内部类枚举出它的列名。 注意: 通过实现BaseColumns这个接口,你的内部类可以继承到一个名为_ID的主键,这个对于android里面的一些类似cursoradaptor类是很有必要的。 这不是必须的,但是这有助于你的数据库同android的framework很好的相容。 例如,下面的片段就定义了表名和单个表的列名: publicfinalclassFeedReaderContract{ //Topreventsomeonefromaccidentallyinstantiatingthecontractclass, //giveitanemptyconstructor. publicFeedReaderContract(){} /*Innerclassthatdefinesthetablecontents*/ publicstaticabstractclassFeedEntryimplementsBaseColumns{ publicstaticfinalStringTABLE_NAME="entry"; publicstaticfinalStringCOLUMN_NAME_ENTRY_ID="entryid"; publicstaticfinalStringCOLUMN_NAME_TITLE="title"; publicstaticfinalStringCOLUMN_NAME_SUBTITLE="subtitle"; ... } } 使用SQLHelper创建数据库 一旦你定义好了你的数据库是什么样之后,你应该实现一些创建和维护数据库和表的方法。 下面是一些典型的创建和删除表的语句。 privatestaticfinalStringTEXT_TYPE="TEXT"; privatestaticfinalStringCOMMA_SEP=","; privatestaticfinalStringSQL_CREATE_ENTRIES= "CREATETABLE"+FeedEntry.TABLE_NAME+"("+ FeedEntry._ID+"INTEGERPRIMARYKEY,"+ FeedEntry.COLUMN_NAME_ENTRY_ID+TEXT_TYPE+COMMA_SEP+ FeedEntry.COLUMN_NAME_TITLE+TEXT_TYPE+COMMA_SEP+ ...//AnyotheroptionsfortheCREATEcommand ")"; privatestaticfinalStringSQL_DELETE_ENTRIES= "DROPTABLEIFEXISTS"+FeedEntry.TABLE_NAME; 就像保存文件到设备的internal存储区一样,android将你的数据库保存在你的app的private的磁盘空间上。 你的数据是安全的,这因为默认情况下,其他的app是不能访问这个区域的。 在SQLiteOpenHelper类中,有一些很有用的API。 当你使用这个
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 1719Android开发技术讲义 之保存数据 1719 Android 开发 技术 讲义 保存 数据