Android存储选项简析

  • Android存储选项简析
    • 简述
    • 共享首选项
    • 内部存储和外部存储
      • 内部存储
        • 数据区域
        • 缓存区域
        • 清除数据和清除缓存
      • 外部存储
        • 权限
        • 检查介质的可用性
        • 公有文件和私有文件
          • 存储公有文件
          • 存储私有文件
          • 缓存文件
    • 数据库
    • 各部分目录图示
    • 总结

简述

对于用户来说,Android系统的存储状况,貌似不像windows那样直观,使用windows的时候,硬盘空间每个细微的地方,都能合理的由用户自己安排,但是使用Android手机的时候,貌似绝大多数情况,都是由系统给安排的,比如应用的安装位置,照片的存放位置等等情况。

确实,这样的话,对于普通用户来说,他们对操作系统不熟悉,而且也没必要花费精力去熟悉,我见过绝大多数使用windows系统的人,都把系统搞的一团糟,很重要的一个原因就是对于系统的存储没有一个清楚的了解,各种应用的安装也相当混乱。时间一久,系统就会因为各种问题变得相当缓慢。

在Android中,普通用户貌似就不用担心这些问题了,因为绝大多数情况下,比如安装应用,拍照,下载等等,都是系统帮你管理这些东西。你只需要负责使用就好了。

虽然普通用户不用担心这些问题了,但是作为开发者的我们,却需要因为这些问题为用户买单,开发者必须要对Android系统的存储选项有一个十分清楚的了解,才不至于你的应用把系统搞的一团糟,或者是不小心随意泄露了你的应用数据。

我们这篇文章,就来看看Android的存储选项相关的内容。

共享首选项

我们在开发app的时候,有的时候,需要记住用户登陆的用户名和密码,一方便下次用户登陆的时候,直接登陆或者登陆提示等功能。

那么对于这个功能,我们应该把用户名和密码记录在哪里呢,记录在内部存储空间?用文件?很麻烦。记录在数据库?也很麻烦。记录在外部存储空间,更不可能。。。这个时候,共享首选项功能就发挥作用了。

SharedPreferences(共享首选项),是以键值对的方式,让你能够永久保存和检索原始数据类型的数据。意思就是,比如用户名和密码,我们可以用类似于哈希的方式去保存,这里用户名和密码类型都是String,我们就可以用一个(key,value)对在SharedPreferences里面保存下来。我们通常使用SharedPreferences来保存应用的一些配置信息。到底SharedPreferences是怎样存储的,我们可以继续往下看。下面,我们来看一看SharedPreferences的具体使用方法。

要写入值,通常需要以下四步:

  1. 获取应用的SharedPreferences对象
  2. 调用 edit() 以获取 SharedPreferences.Editor。
  3. 使用 putBoolean() 和 putString() 等方法添加值。
  4. 使用 commit() 提交新值。

要读取值,需要以下两步:

  1. 获取应用的SharedPreferences对象
  2. 使用 getBoolean() 和 getString() 等 SharedPreferences 方法读取值。

下面,我们来看一个Demo:

package com.example.linukey.test;import android.content.SharedPreferences;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.view.View;import android.widget.Toast;public class MainActivity extends AppCompatActivity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        User user = new User("linukey", "zheshimima");        setUserInfo(user);    }    //保存数据到首选项    void setUserInfo(User user){        //获取SharedPreferences        SharedPreferences sharedPreferences =         getSharedPreferences("data.xml", MODE_PRIVATE);        //拿到SharedPreferences的编辑权限        SharedPreferences.Editor editor =                               sharedPreferences.edit();        //写入数据        editor.putString("username", user.getUsername());        editor.putString("passwd", user.getPasswd());        //提交        editor.commit();    }    //获取首选项中的用户数据    User getUserInfo(){        SharedPreferences sharedPreferences =         getSharedPreferences("data.xml", MODE_PRIVATE);        //读取数据        return new User(sharedPreferences.getString("username", "null"),                sharedPreferences.getString("passwd", null));    }    void onClick(View view){        User user = getUserInfo();        Toast.makeText(this, user.getUsername() + " " +         user.getPasswd(), Toast.LENGTH_SHORT).show();    }}class User{    private String username;    private String passwd;    public User(String username, String passwd){        this.username = username;        this.passwd = passwd;    }    public String getUsername() {        return username;    }    public void setUsername(String username) {        this.username = username;    }    public String getPasswd() {        return passwd;    }    public void setPasswd(String passwd) {        this.passwd = passwd;    }}

我们来简单的说一些里面的一些注意点:

getSharedPreferences方法有两个参数:
第一个参数是一个保存首选项数据的文件的名字,我们这里肯定有疑问,什么文件?我们应该想到,首选项也不是神,我们记录永久性数据,肯定要落实到硬盘上,首选项其实就是帮我们维护了一个xml文件,但是关于文件的创建修改等等其他事情,我们无需关心,我们只需要把所有的精力都放在数据身上就好。这个第一个参数,就是xml文件的名字,如果这个名字的文件不存在,会在我们申请editor的时候自动帮我们创建一个文件,然后在我们commit的时候,把数据存储到文件中。
第二个参数是一个操作模式,就是负责我们的操作权限。我们可以使用0或者MODE_PRIVATE,来作为默认选项。大多数情况下,我们只需要默认选项就够了,至于还有什么其他的,我这里不再罗嗦,大家用到的时候,去文档里面一查就ok了。

还有一个注意点,我们上面在获得Preferences的时候,是使用的
getSharedPreferences方法,其实除了getSharedPreferences方法,我们还可以使用getPreferences(int mode)方法,两者的差别就是getPreferences,是只针对当前Activity的,而getSharedPreferences是针对整个应用的。我们知道,Android系统的应用单位,其实就是Activity,Android系统其实就是一个Activity的大容器。有的时候,我们需要给应用外界提供某个应用模块,就是一个Activity。我们可以看到,getPreferences(int mode)参数只有一个mode,我们不用提供文件名,这个xml文件的名字是系统默认的,我们只负责使用就好。

内部存储和外部存储

到底什么是什么是内部存储和外部存储,我想这个问题绝大多数人都是相当混淆的,手机自带的就是内部存储?SD卡就是外部存储?不完全正确,SD卡是外部存储,这个是无疑的,但是手机自带的,却不完全是内部存储,因为现在的很多手机存储空间已经相当大了,几十G甚至上百G,这个空间被划分为内部存储和外部存储,两者都有。我们接下来看看,这两者的具体含义。

内部存储

内部存储是一个很隐秘的空间,这个空间主要就是用来存放系统文件和应用程序的主要数据存储位置。对于每个应用,存储在内部存储里面的文件,都隶属于这个应用目录下,而且是私有的,其他应用是不能访问的。当一个应用卸载后,他的内部存储目录以及目录下的数据,就会随着应用的卸载而抹掉。
我们来联想一个场景,当我们把手机插到电脑上的时候,这个时候电脑上就会出现一个关于手机的可读写硬盘,那这块区域,是内部存储还是外部存储?它是属于外部存储,我们前面已经说了,内存存储相当隐秘,我们不能随随便便的访问到它。但是也不是没有办法访问到,我们接下来就看看,怎么去访问这个隐秘地。

数据区域

我们的应用安装后,怎么查看我们应用的内部存储所在的目录,我们可以使用getFilesDir()来获取应用在其中存储内部文件的文件系统目录的绝对路径。

File file = getFilesDir();Toast.makeText(this, file.getPath(), Toast.LENGTH_SHORT).show();

我们拿到这个路径后,我们用手机自带的文档查看器,去找一下这个路径,你会很疑惑,为什么找不到,难道是出bug了?还记得我们前面说的吗,内部存储是很隐秘的,你无法随便找到他,自然你是不能通过文档查看器轻松的找到他的。
我们要存储文件在里面,应该怎么操作?Android给我们提供了openFileOutput和openFileInput方法,我么来看一下:

    //保存文件    void saveFile(){        try {            FileOutputStream fout =             openFileOutput("Test", MODE_APPEND);            String str = "hello a!";            fout.write(str.getBytes());            fout.close();        } catch (FileNotFoundException e) {            e.printStackTrace();        } catch (IOException e) {            e.printStackTrace();        }    }    //读取文件内容    void loadFile(){        try {            FileInputStream fin = openFileInput("Test");            byte[] buffer = new byte[1024];            int len = fin.read(buffer, 0, buffer.length);            String str = new String(buffer);            str = String.copyValueOf(str.toCharArray(), 0, len);            fin.close();            Toast.makeText(this, str, Toast.LENGTH_SHORT).show();        } catch (FileNotFoundException e) {            e.printStackTrace();        } catch (IOException e) {            e.printStackTrace();        }    }

我们来解释一下上面的参数,openFileOutput第一个参数,就是我们希望写入内容的文件名字,第二个参数就是我们打开文件用的模式,MODE_APPEND的作用就是进行文件内容的追加,如果文件不存在,就创建一个文件。还有一个模式是MODE_PRIVATE,这个的话,如果文件不存在,就创建一个文件,如果存在的话,就擦除里面的内容。本来还有两个模式 MODE_WORLD_READABLE 和MODE_WORLD_WRITEABLE,但是已经被弃用了,如果我们在Android N及以上版本使用的话,就会抛出SecurityException异常。

除了上面的操作,关于内倍存储还有一系列的操作,这里不一一列举,大家可以去文档中查看。

缓存区域

除了可以在内部存储区域存储永久性的文件,我们还可以在内存存储区域存储一些缓存数据,我么来看一个Demo:

    //保存缓存数据    void saveCache(){        try {            FileOutputStream fout = new FileOutputStream(new File(getCacheDir(), "tmp"));            String str = "aiaiaia";            fout.write(str.getBytes());            fout.close();        } catch (FileNotFoundException e) {            e.printStackTrace();        } catch (IOException e) {            e.printStackTrace();        }    }

这样,我们就把缓存数据存入内部存储区域了。不过这个缓存区域并不保险,如果内部存储区域空间不足了系统就会删掉应用的缓存,所以,这部分区域只适合存放临时性的文件。

清除数据和清除缓存

我们大家来回想一个场景,我们平时在使用手机的时候,在设置的应用里面,我们打开应用,里面会有清除数据和清除缓存的区别,那这个数据和缓存,到底是什么,现在你明白了吗?没错,数据就是我们存放在内部存储区域的该应用的数据,缓存就是我们刚刚介绍的那个缓存,大家可以自己试一下,存点东西,然后分别清除一下这两个东西,就明白了。

外部存储

上面,我们已经搞懂了内部存储区域的一些关键点了,下面,我们再来看一下外部存储区域是个什么东东。

权限

不同与内部存储,要读取或写入外部存储上的文件,应用必须获取 READ_EXTERNAL_STORAGE 或 WRITE_EXTERNAL_STORAGE 系统权限。关于权限,我这里不想多说了,大家想详细了解的,看我之前写的文章《Android-系统权限的前世今生》。

检查介质的可用性

不同于内部存储区域的一点是,在使用外部存储执行任何工作之前,应始终调用 getExternalStorageState() 以检查介质是否可用。介质可能已装载到计算机,处于缺失、只读或其他某种状态。这里的介质,可以是我们的SD卡等可以装载到手机上的存储空间。下面,我们来看一个Demo :

/* 检查外部存储空间是否可读写 */public boolean isExternalStorageWritable() {    String state = Environment.getExternalStorageState();    if (Environment.MEDIA_MOUNTED.equals(state)) {        return true;    }    return false;}

getExternalStorageState()方法返回的状态,包括下面这些状态:MEDIA_UNKNOWN, MEDIA_REMOVED, MEDIA_UNMOUNTED, MEDIA_CHECKING, MEDIA_NOFS, MEDIA_MOUNTED, MEDIA_MOUNTED_READ_ONLY, MEDIA_SHARED, MEDIA_BAD_REMOVAL, or MEDIA_UNMOUNTABLE.
我们在使用时,按需索取就好了。

公有文件和私有文件

在外部存储区域,我们可以存储文件为公有,这些文件可以和其他应用进行共享,不仅仅是公有文件,我们还可以存储文件为私有的,这些文件只能由我们应用自己能够访问到,下面,我们来分别看一下这两种情况:

存储公有文件

一般而言,应该将用户可通过您的应用获取的新文件保存到设备上的“公共”位置,以便其他应用能够在其中访问这些文件,并且用户也能轻松地从该设备复制这些文件。 执行此操作时,应使用共享的公共目录之一,例如 Music/、Pictures/ 和 Ringtones/ 等。.

我们可以使用 getExternalStoragePublicDirectory()方法来获得公共目录的File,这个方法有两个参数,第一个是目录类型,例如 DIRECTORY_MUSIC、DIRECTORY_PICTURES、 DIRECTORY_RINGTONES 或其他类型。第二个是文件名字。

通过将文件保存到相应的媒体类型目录,系统的媒体扫描程序可以在系统中正确地归类您的文件(例如铃声在系统设置中显示为铃声而不是音乐)。

我们来看一个Demo :

public File getAlbumStorageDir(String albumName) {    // 获取公有的相册目录文件    File file = new File(Environment.getExternalStoragePublicDirectory(            Environment.DIRECTORY_PICTURES), albumName);    if (!file.mkdirs()) {        Log.e(LOG_TAG, "Directory not created");    }    return file;}
存储私有文件

我们可以在外部存储区域存储我们应用的私有文件,这些文件会随着应用的卸载而删掉。
我们上面提到了访问外部存储区域的时候,需要权限的申请,但是从Android4.4开始,读取或写入应用私有目录中的文件不再需要 READ_EXTERNAL_STORAGE 或 WRITE_EXTERNAL_STORAGE 权限。 因此,您可以通过添加 maxSdkVersion 属性来声明,只能在较低版本的 Android 中请求该权限。
我们来看一个Demo :

    //在外部存储区域保存私有文件    void savePrivateFile(){        try {            File file = new File(getExternalFilesDir(null), "tmp");            FileOutputStream fout = new FileOutputStream(file);            String str = "hello world";            fout.write(str.getBytes());            fout.close();        } catch (FileNotFoundException e) {            e.printStackTrace();        } catch (IOException e) {            e.printStackTrace();        }    }

第一个参数,和上面公有文件一样,也是用来指定目录的种类的,如果我们不需要,可以指定参数为null,第二个参数是文件的名字。

这个文件虽然存储在外部存储区域,但是仍然是不可见的,我们通过文档查看器,仍然找不到这个文件,因为他是应用私有的。

缓存文件

和内部存储区域一样,我们在外部存储区域,仍然可以存储应用的缓存文件。同样的,随着应用的卸载,这些数据也会被删除。
我们可以通过 getExternalCacheDir()方法,拿到缓存目录。大体使用情况和上面类似,不再列举Demo 。

数据库

除了在系统首选项,以及内部存储和外部存储区域中保存数据,我们还可以在Android系统的数据库中进行数据的存取,关于数据库相关的内容,这里不再多说,大家可以看我之前的文章《Android-从数据库到Content Provider》。

各部分目录图示

我们的手机,如果不root的话,我们上面介绍的很多目录,是看不到的,但是我们可以通过已经root的虚拟机,来看看,下面就是我截的图:
这是系统的根目录:data就是我们上面所说的内部存储区域,storage和mnt是外部存储区域。
Android存储选项简析_第1张图片
Android存储选项简析_第2张图片
我们打开data/data/com.example.linukey.test,也就是我们介绍这个文章的Demo应用内部存储目录:我们可以看到四个文件夹:
1. cache
2. databases
3. files
4. shared_prefs
这正是我们对应我们上面介绍的目录。

Android存储选项简析_第3张图片

我们再来看一下外部存储目录,也是对应我们上面的介绍的。
Android存储选项简析_第4张图片

总结

说到这里,关于Android系统的存储选项,我们已经简单的介绍完了,大家需要在反复的实战中,才能真正的理解好这些内容,文章介绍的内容比较浅陋,大家如果想深入了解,可以参考Android文档以及其他文章。

转载请注明地址:http://blog.csdn.net/linukey/article/details/65934782

更多相关文章

  1. 如何在 iOS、Android、macOS、Windows 之间快速文件互传?
  2. Android资源文件夹及资源文件的详细介绍
  3. Android Layout布局文件里的android:layout_height等属性为什么.
  4. Android多语言支持以及各国语言Values文件夹命名规则
  5. Android中measure过程、WRAP_CONTENT详解以及xml布局文件解析流
  6. android之播放多媒体文件一(播放音频)

随机推荐

  1. Android(安卓)开发之通用的 PopupWindow
  2. android.permission.WRITE_SECURE_SETTIN
  3. Android(安卓): 等待view加载完成后执行
  4. Android开发艺术探索
  5. Android自定义控件中的自定义attrs
  6. [文件] Python读取txt存储至xls
  7. Android(安卓)设计模式 笔记 - 深入了解
  8. android添加library遇到的问题
  9. android viewmodel 数据刷新异常
  10. 秒懂Android(安卓)Studio的奇技淫巧