.Net码农学Android---快速了解数据存储
方式一:shared preferences
你可以叫它用户偏好参数,顾名思义,就是用来存储一些用户的自定义设置,或其它“微型"用户数据
等等,好像忘了一件事,很重要,很重要! 下面请按我说的做:
拿出你的android手机
打开r.e管理器(什么?没有,还不快戳我)
查看文件
如果经常查看文件的同学肯定发现了这么一个奇怪的现象
这三个路径里的文件竟然一模一样,搞毛啊!
其实真相是这样的
这个概念一定要明确,接着返回根目录,在/data/data/<包名>/...中(随便打开一个包),会看到有/lib,/shared_prefs,/files,等几个文件夹,我们的sharedpreferencesfan方式所存储的文件位置就在/shared_prefs中,读写例子大家就自己找吧,对不住了!
这里面提到的这几个文件夹会经常用到,大家一定要熟悉!
方式二:文件存储
这里的文件存储其实又可以分为两种
存储到默认位置
先看代码
复制代码
/*name 文件名,只是名字,不包含路径,如love
/*content 内容
public void save(string name, string content) {
try {
fileoutputstream outputstream = context.openfileoutput(name,context.mode_world_writeable + context.mode_world_readable);
outputstream.write(content.getbytes());
outputstream.close();
} catch (exception e) {
// todo: handle exception
}
}
复制代码
注意看代码中的注释,指定了文件名后,会默认存储到之前的/data/data/<包名>/files/<name>,格式默认xml,即是k/v的形式。
存储到自定义位置
复制代码
public void savetosdcard(string filename,string content) throws exception{
file file=new file("/storage/sdcard0",filename);
fileoutputstream outputstream=new fileoutputstream(file);
outputstream.write(content.getbytes());
outputstream.close();
}
复制代码
可以指定文件位置,比较灵活,但个人建议还是遵守android的约定,即使用默认存储位置,便于管理维护,结构也比较清晰。
方式三:sqllite存储
sqllite简介,请走此通道,android中内嵌了sqllite,所以使用部署时不用安装数据库什么的了。
sqllite场景适合于那些数据比较庞大,复杂的数据存储,并且也有相关的gui。
先看段代码:
复制代码
public class dbopenheler extends sqliteopenhelper {// 需手动实现一下构造方法
public dbopenheler(context contet) {
super(contet, "itcast.db", null, 3);//传入版本号
}
public dbopenheler(context context, string name, cursorfactory factory,
int version) {
super(context, "itcast.db", null, 1);
// todo auto-generated constructor stub
}
@override
public void oncreate(sqlitedatabase db) {
// 第一次创建时会执行
// todo auto-generated method stub
db.execsql("create table person(personid integer primary key autoincrement,name varchar(20))");
}
@override
public void onupgrade(sqlitedatabase db, int oldversion, int newversion) {
// todo auto-generated method stub//当版本号不一样时即升级时会执行
//db.execsql("alter table person add phone varchar(20) null");
db.execsql("alter table person add amount integer");
}
}
复制代码
看到oncreate和onupgrade了吗,这两个方法必须给实现了。
oncreate()在初始化你自定义的数据库时会调用,你必须给它指定一个版本号,用来标识。
onupgrade()的作用是:当我们由于需求需要修改数据库或升级数据库时,只需在构造方法中重新写入一个新的版本号(和之前的版本号不同),系统就会检测到不同从而调用onupgrade(),你只需把你要改的加入到onupgrade()中就ok了
具体sqllite操作实例,请看https://www.cnblogs.com/cczw/archive/2012/05/23/2514544.html
方式四:contentprovider
这是一种共享数据的存储方式,当你的一些数据需要暴露给其他调用者时就要用用到这个了。
有些同学可能会说,我可以把数据放在文件中,比如方式一中的路径下不也可以访问吗?不可以,安卓中非常注重用户的安全性,所以很多操作都被加上了权限的验证,方式一中的路径下的文件默认是只能让本应由访问的, (采用公开写入权限可以访问),同时也统一了应用间共享数据访问方式。
同时,android为常见的一些数据提供了默认的contentprovider(包括音频、视频、图片和通讯录等)。
首先来明确几个概念
概念一.uri(统一资源标识符)
为系统的每一个资源给其一个名字,比方说通话记录。
1、每一个contentprovider都拥有一个公共的uri,这个uri用于表示这个contentprovider所提供的数据。
2、android所提供的contentprovider都存放在android.provider包中。 将其分为a,b,c,d 4个部分:
a:标准前缀,用来说明一个content provider控制这些数据,无法改变的;"content://"
b:uri 的标识,它定义了是哪个content provider提供这些数据。对于第三方应用程序,为了保证uri标识的唯一性,它必须是一个完整的、小写的 类名。这个标识在 元素的 authorities属性中说明:一般是定义该contentprovider的包.类的名称;"content://com.android.text.myprovider"
c:路径,通俗的讲就是你要操作的数据库中表的名字,或者你也可以自己定义,记得在使用的时候保持一致就ok了;"content://com.android.text.myprovider/tablename"
d:参数,如果uri中包含表示需要获取的记录的id;则就返回该id对应的数据,如果没有id,就表示返回全部;"content://hx.android.text.myprovider/tablename/#" #表示数据id
概念.二urimatcher、contenturist和contentresolver
因为uri代表了要操作的数据,所以我们很经常需要解析uri,并从uri中获取数据。android系统提供了两个用于操作uri的工具类,分别为urimatcher 和contenturis 。
urimatcher:用于匹配uri,它的用法如下:
1.首先把你需要匹配uri路径全部给注册上,如下:
//常量urimatcher.no_match表示不匹配任何路径的返回码(-1)。
urimatcher urimatcher = new urimatcher(urimatcher.no_match);
//如果match()方法匹配content://com.letchoice.providers.personprovider路径,返回匹配码为1
urimatcher.adduri(“com.letchoice.providers.personprovider”, “person”, 1);//添加需要匹配uri,如果匹配就会返回匹配码
//如果match()方法匹配 content://com.letchoice.provider.personprovider/person/230路径,返回匹配码为2
urimatcher.adduri(“com.letchoice.providers.personprovider”, “person/#”, 2);//#号为通配符
2.注册完需要匹配的uri后,就可以使用urimatcher.match(uri)方法对输入的uri进行匹配,如果匹配就返回匹配码,匹配码是调用adduri()方法传入的第三个参数,假设匹配content://com.letchoice.provider.personprovider/person路径,返回的匹配码为1。
contenturis:用于获取uri路径后面的id部分,它有两个比较实用的方法:
• withappendedid(uri, id)用于为路径加上id部分
• parseid(uri)方法用于从路径中获取id部分
contentresolver:当外部应用需要对contentprovider中的数据进行添加、删除、修改和查询操作时,可以使用contentresolver 类来完成,要获取contentresolver 对象,可以使用activity提供的getcontentresolver()方法。 contentresolver使用insert、delete、update、query方法,来操作数据。
接下来看个例子吧:
step1:定义你的provider类
public class mycontentprovider extends contentprovider {
private dbopenheler dbopenheler;//之前的sqllite helper类
}
step2:定义你的uri
复制代码
private dbopenheler dbopenheler;
private static final urimatcher matcher = new urimatcher(urimatcher.no_match);//定义一个matcher
// private static final int person = 1;
// private static final int person = 2;
public enum person {
// 自定义枚举参数值
insert(1), delete(2);
private int ncode;
private person(int ncode) {
this.ncode = ncode;
}
@override
public string tostring() {
// todo auto-generated method stub
return string.valueof(this.ncode);
}
};
//这里是你定义的uri,分两种,一种不带参数,一种带参数
static {
matcher.adduri("com.letchoice.providers.personprovider", "person",integer.parseint(person.insert.tostring()));
matcher.adduri("com.letchoice.providers.personprovider", "person/#",integer.parseint(person.delete.tostring()));
}
复制代码
step3:在androidmanifest.xml当中进行声明
<provider
android:name=".mycontentprovider"
android:authorities="com.letchoice.providers.personprovider" >
</provider>
step4:实现curd方法(只贴一个query的)
复制代码
@override
public cursor query(uri uri, string[] projection, string selection,string[] selectionargs, string sortorder) {
// todo auto-generated method stub
sqlitedatabase db = dbopenheler.getreadabledatabase();
switch (matcher.match(uri)) {//匹配检测
case 1://如果uri不带参数就不带参数查询
return db.query("person", projection, selection, selectionargs,null, null, sortorder);
case 2://如果uri带参数就带参数查询
long rid = contenturis.parseid(uri);
string where = "personid=" + rid;
if (selection != null && !"".equals(selection.trim())) {
where += "and" + selection;
}
return db.query("person", projection, where, selectionargs, null,null, sortorder);
default:
throw new illegalargumentexception("this is unknown uri" + uri);
}
}
复制代码
step5:外部调用query得到你想要的结果
复制代码
public void testquery() {
uri uri=uri.parse("content://com.letchoice.providers.personprovider/person");
contentresolver resolver=this.getcontext().getcontentresolver();//使用contentresolver解析uri
cursor cursor=resolver.query(uri, null, null, null,"personid asc");//按照personid升级排序
cursor.movetofirst();
while (cursor.movetonext()) {
log.i("testquery",cursor.getstring(cursor.getcolumnindex("name")));//打印出结果
}
cursor.close();
}
复制代码
方式五:网络获取
前面介绍的几种存储都是将数据存储在本地设备上,除此之外,还有一种存储(获取)数据的方式,通过网络来实现数据的存储和获取。
我们可以调用webservice返回的数据或是解析http协议实现网络数据交互。
具体需要熟悉java.net.*,android.net.*这两个包的内容,在这就不赘述了,请大家参阅相关文档。
下面是一个通过地区名称查询该地区的天气预报,以post发送的方式发送请求到webservicex.net站点,访问webservice.webservicex.net站点上提供查询天气预报的服务。
复制代码
package com.android.weather;
import java.util.arraylist;
import java.util.list;
import org.apache.http.httpresponse;
import org.apache.http.namevaluepair;
import org.apache.http.client.entity.urlencodedformentity;
import org.apache.http.client.methods.httppost;
import org.apache.http.impl.client.defaulthttpclient;
import org.apache.http.message.basicnamevaluepair;
import org.apache.http.protocol.http;
import org.apache.http.util.entityutils;
import android.app.activity;
import android.os.bundle;
public class myandroidweatheractivity extends activity {
//定义需要获取的内容来源地址
private static final string server_url =
"https://www.webservicex.net/weatherforecast.asmx/getweatherbyplacename";
/** called when the activity is first created. */
@override
public void oncreate(bundle savedinstancestate) {
super.oncreate(savedinstancestate);
setcontentview(r.layout.main);
httppost request = new httppost(server_url); //根据内容来源地址创建一个http请求
// 添加一个变量
list<namevaluepair> params = new arraylist<namevaluepair>();
// 设置一个地区名称
params.add(new basicnamevaluepair("placename", "newyork")); //添加必须的参数
try {
//设置参数的编码
request.setentity(new urlencodedformentity(params, http.utf_8));
//发送请求并获取反馈
httpresponse httpresponse = new defaulthttpclient().execute(request);
// 解析返回的内容
if(httpresponse.getstatusline().getstatuscode() != 404){
string result = entityutils.tostring(httpresponse.getentity());
system.out.println(result);
}
} catch (exception e) {
e.printstacktrace();
}
}
}
上一篇: 其乐无穷的幽默趣图,让你重返天真