Android数据存储

来源:互联网 发布:淘宝怎样改评价 编辑:程序博客网 时间:2024/06/08 14:45

数据存储在Android开发中是很重要的,因为做一个项目一定会用到数据存储,比如游戏或者应用的一些设置配置,游戏存档,应用使用习惯等。这篇主要写本地文件的存储,下篇会介绍数据库相关内容。
这里首先讲Android的存储结构,存储空间
android设备有两个存储空间:

内部存储空间

RAM内存:运行内存,相当于电脑的内存
ROM内存:存储内存,相当于电脑的硬盘

外部存储空间

SD卡:相当于电脑的移动硬盘,可有可无
现在的手机很多不支持sd卡,但是是有外部存储空间的。比如手机内存32G,其实是指外部空间。而ROM多大。手机厂商一般不会告诉你。对于普通用户,是不知道的,而我们程序员可以获取。
我们读写文件可以在内部存储或外部存储。

1、在内部存储中写文件

eg.保存用户名密码,勾选记住用户名,首次登陆把用户名保存到本地
示例图
布局文件就是两个ExitText,一个CheckBox和一个Button。(这里CheckBox应该加一个 android:layout_centerVertical=”true” 在父元素中垂直居中)
布局
在java中存储文件的步骤是这样的:
File file = new File(“D:/info.txt”);
FileOutputStream fos = new FileOutputStream(file);
fos.write(buffer);
在android中也是这么简单:首先我们看android的存储目录结构File Explorer(找不到,可以在这里找Window——Show View——Other——File Explorer )
我们应用程序数据存储在内部存储空间的路径“data-data-项目包名”下。所以我们把上边语句改改,完整写法是这样的:
String name = et_name.getText().toString();
String pass = et_pass.getText(0.toString();
CheckBox cb = (CheckBox) findViewById(R.id.cb);
if(cb.isChecked()){
File file = new File(“data/data/com.live.rwinrom/info.txt”);
FileOutputStream fos = new FileOutputStream(file);
try{
fos.write((name + “##” + pass).getBytes());//##是为了拆分用户名和密码。这里正式开发中不是这样做
fos.close();//关流。
}catch(Exception e) {
e.printStackTrace();
}
我们点登录按钮的时候执行上边代码,就可在内部存储空间中生成info.txt文件。

2、在内部存储中读文件

  • 读取数据前先检测文件是否存在
    if(file.exists())
  • 读取保存的数据,也是直接开文件输入流读取
    File file = new File(“data/data/com.live.rwinrom/info.txt”);
    FileInputStream fis = new FileInputStream(file);
    //把字节流转换成字符流
    BufferedReader br = new BufferedReader(new InputStreamReader(fis));
    String text = br.readLine();
    String[] s = text.split(“##”);
  • 读取到数据之后,回显至输入框
    et_name.setText(s[0]);
    et_pass.setText(s[1]);
  • 应用只能在自己的包名目录下创建文件,不能到别人家去创建。权限
    3、使用路径API获取内部存储的路径
    因为上一部分中的”data/data/com.live.rwinrom/info.txt”路径是固定的,写错一个字符就会异常,而且拼写一个长字符串是很没有效率的,有时候我们在做数据库语句时,最好用一些数据库api直接调用。所以我们可以如下方法做。
  • getFilesDir()得到的file对象的路径是data/data/com.live.rwinrom/files
    File file = new File(getFilesDir(),”info.txt”);
    • 存放在这个路径下的文件,只要你不删,它就一直在
  • getCacheDir()得到的file对象的路径是data/data/com.live.rwinrom/cache

    • 存放在这个路径下的文件,当内存不足时,有可能被删除
      • 比如我们打开微信朋友圈,有很多头像啊图片啊,第一次打开慢,第二次瞬间打开。这些就是存在cache里的。
      • 谷歌说,在系统内存少时,cache文件可能会被删,也可能不会被删,建议我们建个阀门,比如达到1MB删。
  • 系统管理应用界面的清除缓存,会清除cache文件夹下的东西,清除数据,会清除整个包名目录下的东西
    清除cache和data区别
    4、在外部存储读写文件

sd卡的路径

  • sdcard:2.3之前的sd卡路径
  • mnt/sdcard:4.3之前的sd卡路径
  • storage/sdcard:4.3之后的sd卡路径

  • 最简单的打开sd卡的方式

    File file = new File("sdcard/info.txt");//谷歌为了兼容低版本,在存储空间中建了一个sdcard文件快捷方式指向storage/sdcard
  • 写sd卡需要权限

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
  • 读sd卡,在4.0之前不需要权限,4.0之后可以设置为需要

    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
  • 使用api获得sd卡的真实路径,部分手机品牌会更改sd卡的路径

    Environment.getExternalStorageDirectory()
  • 判断sd卡是否准备就绪

    if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))

5、文件访问权限

  • 在Android中,每一个应用是一个独立的用户
  • drwxrwxrwx
  • 第1位:d表示文件夹,-表示文件
  • 第2-4位:rwx,表示这个文件的拥有者用户(owner)对该文件的权限
    • r:读
    • w:写
    • x:执行
  • 第5-7位:rwx,表示跟文件拥有者用户同组的用户(grouper)对该文件的权限
  • 第8-10位:rwx,表示其他用户组的用户(other)对该文件的权限

openFileOutput的四种模式

  • MODE_PRIVATE:-rw-rw—-
  • MODE_APPEND:-rw-rw—-
  • MODE_WORLD_WRITEABLE:-rw-rw–w-
  • MODE_WORLD_READABLE:-rw-rw-r–

6、用SharedPreference存储账号密码

  • 往SharedPreference里写数据

    //拿到一个SharedPreference对象SharedPreferences sp = getSharedPreferences("config", MODE_PRIVATE);//拿到编辑器Editor ed = sp.edit();//写数据ed.putString("name", name);ed.commit();
  • 从SharedPreference里取数据

    SharedPreferences sp = getSharedPreferences("config", MODE_PRIVATE);//从SharedPreference里取数据String name = sp.getBoolean("name", "");

7、生成xml文件

上边几个存储的方式不够满足我们的需求,比如我们要备份短信。每条短信,最少包含四个数据:address发送者电话号,body短信内容,date时间,type信息类型(收到的还是发出的)。
* 首先建一个Message对象
public class Message {
private String body;
private String date;
private String address;
private String type;
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public Message(String body, String date, String address, String type) {
super();
this.body = body;
this.date = date;
this.address = address;
this.type = type;
}

}

  • 创建几个虚拟的短信对象,存在list中,并备份数据通常都是备份至sd卡,使用StringBuffer拼接字符串,把整个xml文件所有节点append到sb对象里
    public class MainActivity extends Activity {
    List smsList;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    //虚拟10条短信smsList = new ArrayList<Message>();for(int i = 0; i < 10; i++){    Message sms = new Message("李伟好棒" + i, System.currentTimeMillis() + "", "138"+i+i, "1");    smsList.add(sms);}

    }
    public void click(View v){
    //在内存中把xml备份短信的格式拼接出来
    StringBuffer sb = new StringBuffer();
    sb.append(“

拿到xml文件

    InputStream is = getClassLoader().getResourceAsStream("weather.xml");

拿到pull解析器

    XmlPullParser xp = Xml.newPullParser();

开始解析

  • 拿到指针所在当前节点的事件类型

    int type = xp.getEventType();
  • 事件类型主要有五种

    • START_DOCUMENT:xml头的事件类型
    • END_DOCUMENT:xml尾的事件类型
    • START_TAG:开始节点的事件类型
    • END_TAG:结束节点的事件类型
    • TEXT:文本节点的事件类型
  • 如果获取到的事件类型不是END_DOCUMENT,就说明解析还没有完成,如果是,解析完成,while循环结束

    while(type != XmlPullParser.END_DOCUMENT)
  • 当我们解析到不同节点时,需要进行不同的操作,所以判断一下当前节点的name

    • 当解析到weather的开始节点时,new出list
    • 当解析到city的开始节点时,创建city对象,创建对象是为了更方便的保存即将解析到的文本
    • 当解析到name开始节点时,获取下一个节点的文本内容,temp、pm也是一样

      case XmlPullParser.START_TAG://获取当前节点的名字    if("weather".equals(xp.getName())){        citys = new ArrayList<City>();    }    else if("city".equals(xp.getName())){        city = new City();    }    else if("name".equals(xp.getName())){        //获取当前节点的下一个节点的文本        String name = xp.nextText();        city.setName(name);    }    else if("temp".equals(xp.getName())){        String temp = xp.nextText();        city.setTemp(temp);    }    else if("pm".equals(xp.getName())){        String pm = xp.nextText();        city.setPm(pm);    }    break;
  • 当解析到city的结束节点时,说明city的三个子节点已经全部解析完了,把city对象添加至list

    case XmlPullParser.END_TAG:    if("city".equals(xp.getName())){            citys.add(city);    }

结尾发福利:
夜煞实例
快捷键Ctrl + 1,如图设置Convert local variable to field,局部变量直接设成全局变量。

1 0
原创粉丝点击