Android SDK上手指南:应用程序数据

版权声明:本文为博主原创文章,转载请标明出处。 https://blog.csdn.net/chaoyu168/article/details/52996965

在本系列教程当中,我们将学习如何从零开始进行Android SDK开发。我们已经熟悉了Android应用程序的结构与基本组成元素,其中包括资源、清单与用户界面。在着手进行Android平台的功能性应用开发之后,大家肯定需要保存这样或者那样的数据信息。Android平台提供多种选项,用于打理应用程序中的数据存储任务,而这正是今天这篇文章要讨论的核心内容。

介绍

从广义上讲,Android应用中的数据存储选项共有五种主要类型:将数据保存在应用的共享偏好当中、保存在内部存储(专属于应用本身)当中、保存在外部存储(向设备公开)当中、保存在数据库当中以及保存在可通过设备互联网连接访问的Web资源当中。受篇幅所限,我们无法详细对这些选项作出论述,但会对每种方案的基础特性加以概括、从而帮助大家在需要使用持久化数据时理清存储问题的解决思路。

1. 共享偏好

第一步

共享偏好允许大家以键-值对的形式保存基本数据类型。应用程序的共享偏好文件通常被视为最简单的数据存储选项,但从本质上说它对于存储对象提出了一定程度的限制。大家可以通过它存储基本类型数字(如整数、长数以及浮点数字)、布尔值以及文本字符串。我们需要为自己保存的每个数值分配一个名称,从而在应用程序运行时据此对其进行检索。由于大家很可能在自己创建的第一款应用中就用到共享偏好,因此我们人把它作为讲解的重点、以更为详尽的方式(相较于其它选项)进行表述,从而帮助各位巩固必要知识。

大家可以在自己的主Activity类中尝试这些代码,并在稍后运行本系列教程的应用示例时对其加以测试。在理想情况下,共享偏好应该可以符合应用程序中的用户配置选项,如同选择外观设置一样。大家应该还记得,我们曾经创建过一个简单的按钮,用户点击它之后屏幕上会显示出“Ouch”文本内容。现在让我们假设自己希望用户在点击一次之后,该按钮上会持续显示“Ouch”字样,且该状态在应用程序运行过程中始终保持不变。这意味着按钮上的初始文本仅在用户首次点击操作之前存在。

让我们为应用程序添加共享偏好内容。在该类的起始位置、onCreate方法之前,我们为共享偏好选择一个名称:

 
  1. public static final String MY_APP_PREFS = "MyAppPrefs"; 

利用“public static”修饰符,我们可以访问处于应用内任何类中的这项变量,因此我们只需要将偏好名称字符串保存在这里即可。我们使用大写是因为该变量属于常数,“final”修饰符也是因此而存在。每一次检索或者在应用程序偏好当中设置数据条目时,大家都必须使用同样的名称。

第二步

现在我们来编写共享偏好内容。在我们的onClick方法中、按钮“Ouch”文本设置部分的下方,尝试通过名称取回这条共享偏好:

 
  1. SharedPreferences thePrefs = getSharedPreferences(MY_APP_PREFS, 0); 

大家需要为“android.conent.SharedPreferences”类添加一条导入。将鼠标悬停在“SharedPreferences”文本上方,并利用Eclipse提示完成导入。第一项参数是我们所定义的偏好名称,第二项则是我们作为默认选项的基本模式。

现在我们需要为共享偏好指定一套编辑器,从而实现对其中数值的设定:

 
  1. SharedPreferences.Editor prefsEd = thePrefs.edit(); 

现在我们可以向共享偏好当中写入值了:

prefsEd.putBoolean("btnPressed", true);

这里我们使用了布尔类型,因为当前状态只分为两种——用户已经或者尚未按下按钮。编辑器提供多种不同类型,我们可以从中选择以保存这套共享偏好,其中每种方法都拥有自己的名称与值参数。最后,我们需要提交编辑结果:

 
  1. prefsEd.commit(); 

第三步

现在让我们利用已经保存的值来检测用户运行应用程序后,按钮应该显示什么样的内容。在onCreate中的现有代码之后添加共享偏好:

 
  1. SharedPreferences thePrefs = getSharedPreferences(MY_APP_PREFS, 0); 

这一次我们不必使用编辑器,因为我们只需要获取一个值:

 
  1. boolean pressed = thePrefs.getBoolean("btnPressed", false); 

现在我们利用已经设置过的名称检索该值,并读取变量中的结果。如果该值尚未被设置,返回的则为第二项参数,也就是默认值——代表否定含义。现在让我们使用该值:

 
  1. if(pressed) theButton.setText("Ouch"); 

如果用户在应用程序运行之后按下该按钮,则按钮直接显示“Ouch”字样。在本系列的后续文章当中,大家会看到我们在应用运行中进行这一操作的情况。这个简单的例子很好地诠释了共享偏好的使用过程。大家会发现,共享偏好在帮助应用程序通过外观及使用感受迎合用户喜好方面具有重要的作用。

2. 私有内部文件

第一步

大家可以将文件保存在用户设备的内部以及外部存储当中。如果将文件保存在内部存储中,Android系统会将其视为专属于当前应用的私有数据。这类文件基本上属于应用程序的组成部分,我们无法在应用程序之外直接对其进行访问。再有,如果应用程序被移除、这些文件也会同时被清空。

大家可以利用以下输出例程在内存存储中创建一个文件:

 
  1. FileOutputStream fileOut = openFileOutput("my_file", Context.MODE_PRIVATE); 

大家需要为“java.io.FileOutputStream”类进行导入添加。我们提供了文件名称与模式,选择私有模式意味着该文件将只能被该应用程序所使用。如果大家现在就把这部分代码加入到Activity当中,例如onClick方法中,Eclipse将弹出错误提示。这是因为当我们进行输入/输出操作时,应用程序可能遭遇一些需要应对的错误。如果大家的输入/输出操作无法解决这类错误,Eclipse就会提示异常状况、应用程序也会中止运行。为了保证应用程序在这种情况下仍能正常运行,我们需要将自己的输入/输出代码封装在try代码块当中:

 
  1. try{     FileOutputStream fileOut = openFileOutput("my_file", Context.MODE_PRIVATE); 
  2. catch(IOException ioe){     
  3. Log.e("APP_TAG", "IO Exception", ioe); } 

如果输入/输出操作导致异常,那么catch块中的上述代码就会付诸执行,从而将错误信息写入到日志当中。大家今后会经常用到应用程序中的Log类(导入‘android.util.Log’),它会记录代码执行时所发生的具体情况。我们可以为字符串标签定义一个类变量,也就是上述代码中的第一条参数。这样一旦出现错误,大家就可以在Android LogCat中查看异常信息了。

第二步

现在回到try块,在创建了文件输出例程之后,大家可以尝试将以下代码写入文件:

 
  1. String fileContent = "my data file content"; fileOut.write(fileContent.getBytes()); 

在将所有必要内容写入数据文件之后,利用以下代码作为结尾:

 
  1. fileOut.close(); 

第三步

当大家需要检索内部文件中的内容时,可以通过以下流程实现:

 
  1. try{    
  2.  FileInputStream fileIn = openFileInput("my_file");     
  3. //read the file } catch(IOException ioe){     
  4. Log.e("APP_TAG", "IO Exception", ioe); } 

在try块当中,利用利用缓冲读取器读取文件内容:

 
  1. InputStreamReader streamIn = new InputStreamReader(fileIn); 
  2. BufferedReader fileRead = new BufferedReader(streamIn); 
  3. StringBuilder fileBuild = new StringBuilder(""); 
  4. String fileLine=fileRead.readLine(); while(fileLine!=null){    
  5.  fileBuild.append(fileLine+"\n");     
  6. fileLine=fileRead.readLine(); } 
  7. String fileText = fileBuild.toString(); streamIn.close(); 

大家不要被其中所涉及的大量不同对象所吓倒,这其实属于标准的Java输入/输出操作。其中的while循环会在文件中的每一行执行一次。在执行完成后,“fileText”变量将把文件内容保存为字符串、以备我们直接使用。

3. 公共外部文件

第一步

只要用户设备支持,我们的应用程序也可以将文件保存在外部存储当中。外部存储种类繁多,包括SD卡、其它便携式介质或者用户无法移除但被系统认定为外部类型的内存存储机制。当我们将文件保存在外部存储中时,其内容将完全公开、大家也无法以任何方式阻止用户或者其它应用对其进行访问。

在我们尝试将数据保存在外部存储中之前,必须首先检查对应存储机制是否可用——尽量避免意外状况绝对是种好习惯:

 
  1. String extStorageState = Environment.getExternalStorageState(); 

系统会将信息以字符串的形式返回,大家可以对其进行分析、并与Environment类中的外部存储状态字段加以比对:

 
  1. if(Environment.MEDIA_MOUNTED.equals(extStorageState)){     
  2. //ok to go ahead and read/ write to external storage } 
  3. else if(Environment.MEDIA_MOUNTED_READ_ONLY.equals(extStorageState)){    
  4.  //can only read } else{     //cannot read or write } 

即使设备上确实存在外部存储,我们也不能先入为主地假定应用可以向其写入数据。

第二步

在证实了我们确实能够向外部存储写入数据之后,大家接下来需要检索目录以指定文件保存的位置。以下应用程序设置内容指向八级及更高API:

 
  1. File myFile = new File(getExternalFilesDir(null), "MyFile.txt"); 

这样大家就可以对该文件进行写入与读取了。不过也别忘了在项目的清单文件中添加以下仅限:

 
  1. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> 

随着我们开发的应用程序变得愈发复杂,大家可能希望将自己保存得到的文件与其它应用共享。在这种情况下,大家可以使用公共目录下的各类通用条目,例如图片以及音乐文件。

4. 数据库

随着我们的应用程序所涉及的复杂结构数据越来越多,共享偏好或者内部/外部文件可能已经无法满足实际需求,这时候大家就应该考虑使用数据库方案了。Android支持开发人员在应用程序内部创建并访问SQLite数据库。在我们创建一套数据库时,其将作为私有组件服务单纯服务于相关应用程序。

在Android应用中利用SQLite数据库的方法多种多样,推荐大家使用扩展SQLiteOpenHelper的类来实现这方面需求。在该类当中,我们需要定义数据库属性、创建各种类变量(包括我们所定义的数据库列表名称及其SQL创建字符串),具体代码如下所示:

 
  1. private static final String NOTE_TABLE_CREATE =     "CREATE TABLE Note (noteID INTEGER PRIMARY KEY AUTOINCREMENT, " +     "noteTxt TEXT);"; 

这里所举的例子只涉及一套非常简单的表格,其中包含两列,一列内容为ID、另一列内容为文本;两列都用于记录用户注释信息。在SQLiteOpenHelper类当中,大家可以重写onCreate方法来创建自己的数据库。在应用程序的其它部分当中,例如Activity类中,大家可以通过SQLiteOpenHelper实现对数据库的访问,并利用WritableDatabase方法插入新记录、利用getReadableDatabase方法来查询现有记录,而后将结果显示在应用程序UI当中。

在对查询结果进行迭代时,我们的应用程序将使用Cursor类——该类会依次引用结果集中的每一行内容。

5. 互联网数据

很多应用都会使用互联网数据资源,而且某些应用甚至基本是由一套界面与大量Web数据源所构成。大家可以利用用户设备上的互联网连接来存储并检索来自Web的数据,只要网络连接有效、这一机制就能正常运作。为了实现这一目标,我们需要在自己的清单文件中添加“android.permission.INTERNET”权限。

如果我们希望自己的应用能够从互联网中获取数据,则必须保证这一流程脱离应用主UI线程。利用AsyncTask,大家可以通过后台进程的方式从Web源获取数据、在数据下载完成后将结果写入UI、最后让UI正常执行自身功能。

大家还可以将一个内部AsyncTask类添加到Activity类当中,并在需要获取数据的时候在该Activity中创建一个AsyncTask实例。通过在AsyncTask中引入doInBackground与onPostExecute两种方法,大家可以检索Activity中所获取到的数据并将其写入用户界面。

获取Web数据在应用开发工作当中属于中等难度的任务,大家最好在熟练掌握了Android开发知识之后再进行尝试。不过大家可能很快就会发现,这样的数据获取机制对不少应用都非常适合,因为这能有效利用用户设备的连接资源。Java与Android都提供相关工具,用于处理返回的结构化数据——例如JSON feed。

结论

在今天的文章中,我们基本了解了开发Android应用程序时需要接触到的数据存储方案。无论大家最终选择哪种方案,都应该以实际需求作为参考标准,因为不同的方案只适合特定需求。在本系列教程的下一篇当中,我们将共同探讨如何将物理设备与已安装的Eclipse相连、同时学习如何创建虚拟设备。在此之后,我们还将探索如何让应用程序运行在这两种类型的设备之上。顺便向大家报告,再有两篇文章本系列教程就将彻底结束;在最后一篇文章中,我们将研究通用类以及Android Activity生命周期,从而帮助大家做好开发应用程序的一切准备。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/457682.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

设计微服务架构需要解决的问题

问题: 划分服务的原则是什么服务之间选择何种轻量级的通信协议如何做到服务的独立部署如何确定使用何种编程语言?控制多语言带来的复杂度如何做到服务的去中心化如何解决大量微服务引入的运维成本转载于:https://www.cnblogs.com/fight-tao/p/5641286.html

Django Model设计详解

Django Model 设计 Django Model设计是Django五项基础核心设计之一(Model设计,URL配置,View编写,Template设计,From使用),也是MVC模式中重要的环节。 如果图片无法访问,大家可以移…

python设置全局变量失败_Python全局变量与global关键字常见错误解决方案

在Python的变量使用中,经常会遇到这样的错误:local variable a referenced before assignment它的意思是:局部变量“a”在赋值前就被引用了。比如运行下面的代码就会出现这样的问题:a 3def Fuc():print (a)a a 1Fuc()​ 但是如果把 a a …

Atititi tesseract使用总结

Atititi tesseract使用总结 消除bug,优化,重新发布。当前版本为3.02 项目下载地址为:http://code.google.com/p/tesseract-ocr。 Windows cmd命令行使用Tesseract-OCR引擎识别验证码: 1、下载安装Tesseract-OCR引擎(3.0版本才支持中文识别) t…

Javascipt数组去重的几种方式

方法一 function unique(arr) {var retArr [];for (var i 0; i < arr.length; i) {(retArr.indexOf(arr[i]) -1) && retArr.push(arr[i]);}return retArr; } 方法二 function unique(arr) {return arr.filter(function(item, index, array) {return array.indexO…

01_JS语法

JS语法 严格区分大小写以;结尾&#xff0c;不写浏览器会自动加&#xff0c;但不准确&#xff0c;且会占用浏览器资源自动忽略多个空格和换行 写在哪 所有JS代码都必须依托网页运行 内嵌 写在html的script标签中 <script>// JS代码 </script>事件 写在某个ht…

pythonwhile循环love_python基础之while循环及编码

while 条件&#xff1a;循环体死循环&#xff1a;没有终止条件(修改方法&#xff1a;1.改变条件2.使用break)break 终止当前循环contiune&#xff1a;跳出本次循环&#xff0c;继续下次循环break和contione必须在循环体里while 条件&#xff1a;循环体else&#xff1a;结果当wh…

css页面布局

居中布局 水平居中 父元素和子元素的宽度都未知 inline-block text-ailgn .child{display:inline-block;} .parent{text-align:center;} 优点&#xff1a;兼容性好 缺点&#xff1a;子元素文本继承了text-align属性&#xff0c;子元素要额外加text-align:left; table ma…

02_JS变量

JS变量 字面量 常量&#xff0c;不可变量 变量 变量用 var 变量名声明 命名 变量命名以数字字母下划线和$组成&#xff0c;不能以数字开头&#xff0c;还可以是utf-8的任意字符&#xff0c;包括中文&#xff0c;一般采用驼峰命名法 常用的几个函数 alert():浏览器弹窗d…

Rotate String

Given a string and an offset, rotate string by offset. (rotate from left to right) Example Given "abcdefg". offset0 > "abcdefg" offset1 > "gabcdef" offset2 > "fgabcde" offset3 > "efgabcd"分析&am…

音视频播放、录音、拍照

音频 在iOS中音频播放从形式上可以分为音效播放和音乐播放。前者主要指的是一些短音频播放&#xff0c;通常作为点缀音频&#xff0c;对于这类音频不需要进行进度、循环等控制。后者指的是一些较长的音频&#xff0c;通常是主音频&#xff0c;对于这些音频的播放通常需要进行精…

python 递归函数与循环的区别_提升Python效率之使用循环机制代替递归函数

斐波那契数列当年&#xff0c;典型的递归题目&#xff0c;斐波那契数列还记得吗&#xff1f;def fib(n):if n1 or n2:return 1else:return fib(n-1)fib(n-2)当然, 为了程序健壮性&#xff0c;加上try...except...def fib(n):if isinstance(n, int):print(兄弟,输入正整数哈)ret…

03_JS数据类型

JS数据类型 基本数据类型 String 字符串类型&#xff0c;申明时用单引号或双引号引起来&#xff0c;两种引号不可嵌套&#xff0c;不可混用 Number 数值型&#xff0c;有两个特殊的数字 Infint:无穷大NaN&#xff1a;非数值型数字&#xff0c;不与任何类型相等 Boolean …

7.5

姓名 崔巍 时间 2016年7月5日 学习内容 最后一次确定同步控制力度等实现细节。 学习了Visual Studio C#软件测试方面的工具。巩固了等价类黑盒测试方法的相关理论&#xff0c;并且学习了集成测试、回归测试的相关内容&#xff0c;并进行了测试。 集成测试&#xff0c;…

python scratch ev3_如何在scratch上连接乐高ev3?

乐高教育的官网有关于EV3使用Python的详细介绍https://education.lego.com/zh-cn/support/mindstorms-ev3/python-for-ev3​education.lego.com来自网易有道Scratch是现在小朋友们最热的编程工具&#xff0c;也是各学校和培训机构对小学生编程的入门首选。网易有道Kada平台是一…

04_JS运算符

JS运算符 一元运算符 -,正负号&#xff0c;对非数值类型做正负操作会先转换成数值型&#xff0c;可以用快速进行类型转换 逻辑运算符 且 &&&#xff0c;从左到右看&#xff0c;一旦返现值为false的表达式立刻返回false&#xff0c;全真为真或 ||&#xff0c;从左到右…

C语言 第八章 函数、指针与宏

一、函数 函数是一个包含完成一定功能的执行代码段。我们可以把函数看成一个"黑盒子", 你只要将数据送进去就能得到结果, 而函数内部究竟是如何工作的的, 外部程序是不知道的。外部程序所知道的仅限于输入给函数什么以及函数输出什么。函数提供了编制程序的手段,使之…

ByteBuffer用法小结

在NIO中,数据的读写操作始终是与缓冲区相关联的.读取时信道(SocketChannel)将数据读入缓冲区,写入时首先要将发送的数据按顺序填入缓冲区.缓冲区是定长的,基本上它只是一个列表,它的所有元素都是基本数据类型.ByteBuffer是最常用的缓冲区,它提供了读写其他数据类型的方法,且信道…

promise用法_Promise的秘密

写在前面本篇文章将会带大家从分解promise入手&#xff0c;一步步实现一个promise。但阅读之前需要比较熟练地了解了解用法&#xff0c;结合用法看文章可能更容易理解。结构先看一下简单的用法。const promise new Promise((resolve, reject) > {setTimeout(() > {resol…

SpringMVC视图解析器(转)

前言 在前一篇博客中讲了SpringMVC的Controller控制器&#xff0c;在这篇博客中将接着介绍一下SpringMVC视图解析器。当我们对SpringMVC控制的资源发起请求时&#xff0c;这些请求都会被SpringMVC的DispatcherServlet处理&#xff0c;接着Spring会分析看哪一个HandlerMapping定…