Android罕用数据存储形式有SharedPreferences存储数据(尽管还是属于外部存储)、文件存储(外部,内部)、SQLite数据库存储、ContentProvider存储数据、网络存储数据等几种。本篇博客次要是介绍Shared Preference的原理与应用,辨别外部与内部文件存储,以及它们的应用形式。那就从革除缓存与革除数据到底革除了什么这个问题开始吧!

<!-- more -->

外部存储 InternalStorage

在Android开发中,内存 Memory、外部存储 InternalStorage、内部存储 ExternalStorage这三者有啥区别呢? 在咱们关上手机设置 -> 利用治理,轻易抉择一个软件,而后会看到一个是革除缓存的按钮,一个革除数据的按钮,那么当点击革除缓存的时候革除的是哪里的数据?当点击革除数据的时候又是革除的哪里的数据呢? 关上Device File Explorer会看到如下目录构造:

其实在应用SharedPreferenced的时候,将数据长久化存储于本地,其实就是存在这个文件中的xml文件里,App里边的数据库文件就存储于databases文件夹中,还有咱们的一般数据存储在files中,缓存文件存储在cache文件夹中,存储在这里的文件咱们都称之为外部存储。

上面来说说应用外部存储的代表——SharedPreferences,SharedPreferences也是在开发中应用的比拟多的一种计划,用于寄存一些相似登录的配置等信息。

SharedPreferences

1、用于寄存一些相似登录的配置信息
2、实质上是一个xml文件,是通过相似键值对的形式寄存信息
3、位于程序公有目录中,即data/data/[packageName]/shared_prefs

SharedPreferences的操作模式
1、MODE_APPEND:追加形式存储
2、MODE_PRIVATE:公有形式存储,其余利用无法访问
3、MODE_WORLD_READABLE:可被其余利用读取
4、MODE_WORLD_WRITEABLE:可被其余利用写入

SharedPreferences应用形式:

// 取数据@Overrideprotected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.activity_main);    etUserName = findViewById(R.id.et_username);    etPassword = findViewById(R.id.et_password);    SharedPreferences login_info = getSharedPreferences("login_info", MODE_PRIVATE);    // 第一个参数为Key,第二个是默认值    etUserName.setText(login_info.getString("user_name", ""));    etPassword.setText(login_info.getString("password", ""));}// 存储据public void userLogin(View view) {    String userName = etUserName.getText().toString();    String password = etPassword.getText().toString();    if(TextUtils.isEmpty(userName) || TextUtils.isEmpty(password)){        Toast.makeText(MainActivity.this, "输出不残缺", Toast.LENGTH_SHORT).show();    }    // 存储输出的信息    // 1、拿到SharedPreference对象    SharedPreferences loginInfoSP = getSharedPreferences("login_info", MODE_PRIVATE);    // 2、获取Editor对象    SharedPreferences.Editor editor = loginInfoSP.edit();    // 3、通过Editor存储数据    editor.putString("user_name", userName);    editor.putString("password", password);    // 3、调用提交办法    boolean commit = editor.commit();    Log.i(TAG, "userLogin: commitRet = " + commit);    // 校验登录后果    if(!("admin".equals(userName) && "123456".equals(password))){        Toast.makeText(MainActivity.this, "用户名或明码谬误", Toast.LENGTH_SHORT).show();    }else {        Toast.makeText(MainActivity.this, "登录胜利", Toast.LENGTH_SHORT).show();        // TODO ...    }}

所以其实不难发现,SharedPreference存取数据非常简单,存数据只须要四步,取数据只有两步。

通过查看设施上的文件也能够发现,SharedPreference实质上就是一个xml文件而已,是通过相似键值对的形式寄存信息。

取得外部存储目录

Context.getFileDir(),获取/data/data/包名/files
Context.getCacheDir(),获取/data/data/包名/cache,上面通过代码演示一下:

public void saveToFileDir() {    File filesDir = MainActivity.this.getFilesDir();    File myFileTxt = new File(filesDir, "myFile.txt");    try (BufferedWriter writer = new BufferedWriter(new FileWriter(myFileTxt))){        writer.write("这是外部存储文件目录的文件内容!");    } catch (IOException e) {        e.printStackTrace();    }}public void saveToCacheDir() {    File cacheDir = MainActivity.this.getCacheDir();    File myCacheTxt = new File(cacheDir, "myCache.txt");    try (BufferedWriter writer = new BufferedWriter(new FileWriter(myCacheTxt))){        writer.write("这是外部存储缓存文件内容!");    } catch (IOException e) {        e.printStackTrace();    }}

内部存储ExternalStorage

ExternalStorage是咱们平时操作最多的,内部存储个别就是咱们下面看到的storage或者mnt文件夹,不同厂家有可能不一样,请见下图:

一般来说,在storage文件夹中有一个sdcard文件夹,这个文件夹中的文件又分为两类,一类是私有目录,还有一类是公有目录,其中的私有目录有九大类,比方DCIM、DOWNLOAD等这种零碎为咱们创立的文件夹,公有目录就是Android这个文件夹,这个文件夹关上之后里边有一个data文件夹,关上这个data文件夹,外面有许多利用包名组成的文件夹,那些就是对应的应用程序的公有内部存储区域(Android/data/利用包名)。比方浏览器的公有内部存储空间:

上面是一个存储与读取的例子:

<?xml version="1.0" encoding="utf-8"?><LinearLayout    xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:padding="20dp"    android:orientation="vertical"    tools:context=".MainActivity">    <EditText        android:id="@+id/et_content"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:minLines="10" />    <Button        android:id="@+id/btn_save"        android:onClick="save"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="保留" />    <Button        android:onClick="read"        android:id="@+id/btn_read"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="读取" />    <TextView        android:id="@+id/tv_show"        tools:text="Content Text!"        android:layout_width="match_parent"        android:layout_height="wrap_content"/></LinearLayout>

MainActivity.java

public class MainActivity extends AppCompatActivity {    private static final String TAG = "MainActivity";    private EditText etContent;    private TextView tvShow;    // 申请权限申请码    private static final int REQUEST_EXTERNAL_STORAGE = 1001;    // 查看权限,这种写法次要是针对比拟新的Android6.0及当前的版本    public static void verifyStoragePermissions(Activity activity) {        int writePermission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE);        int readPermission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.READ_EXTERNAL_STORAGE);        if (writePermission != PackageManager.PERMISSION_GRANTED                || readPermission != PackageManager.PERMISSION_GRANTED) {            // 如果没有权限须要动静地去申请权限            ActivityCompat.requestPermissions(                    activity,                    // 权限数组                    new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE},                    // 权限申请码                    REQUEST_EXTERNAL_STORAGE            );        }    }    // 如果在申请权限的过程中须要做一些对应的解决,则在此办法中解决    @Override    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {        super.onRequestPermissionsResult(requestCode, permissions, grantResults);        if(REQUEST_EXTERNAL_STORAGE == requestCode){            // TODO ...        }    }    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        // 取得内部存储的目录        File externalStorageDirectory = Environment.getExternalStorageDirectory();        Log.i(TAG, "onCreate: externalStorageDirectory = " + externalStorageDirectory.getAbsolutePath());        etContent = findViewById(R.id.et_content);        tvShow = findViewById(R.id.tv_show);        verifyStoragePermissions(this);    }    public void save(View view) {        String content = etContent.getText().toString();        if(TextUtils.isEmpty(content)) {            Toast.makeText(MainActivity.this, "输出为空", Toast.LENGTH_SHORT).show();            return;        }        // 判断内部存储的状态        if(Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())){            // 内部存储已挂载            String absolutePath = Environment.getExternalStorageDirectory().getAbsolutePath();            String descPath = absolutePath + "/input_content.txt";            File descFile = new File(descPath);            Log.i(TAG, "save: descFile = " + descFile.getAbsolutePath());            try {                BufferedWriter writer = new BufferedWriter(new FileWriter(descFile, true));                writer.write(content);                writer.close();                Toast.makeText(MainActivity.this, "写入胜利", Toast.LENGTH_SHORT).show();            } catch (IOException e) {                e.printStackTrace();            }        }else{            Toast.makeText(MainActivity.this, "存储设备未挂载", Toast.LENGTH_SHORT).show();        }    }    public void read(View view) {        String absolutePath = Environment.getExternalStorageDirectory().getAbsolutePath();        String descPath = absolutePath + "/input_content.txt";        try {            BufferedReader bufferedReader = new BufferedReader(new FileReader(new File(descPath)));            String line;            StringBuilder builder = new StringBuilder();            while((line = bufferedReader.readLine()) != null){                builder.append(line).append("\n");            }            tvShow.setText(builder.toString());        } catch (IOException e) {            e.printStackTrace();        }    }}

manifest文件中别忘记申明权限:

<!-- 在SDCard中创立与删除文件的权限 --><uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

取得内部存储目录

通过Environment.getExternalStorageDirectory(),咱们很容易取得内部存储的根目录,通过拼接,很容易拿到DOWNLOAD、DCIM、MUSIC、MOVIES、LOST.DIR等私有目录,如何拿到内部存储的公有目录呢?

Context.getExternalFilesDir(String type),通常用于须要长时间保留的数据,获取到SDCard/Android/data/包名/files/目录。

Context.getExternalCacheDir(),通常用于须要长期保留的数据,获取到SDCard/Android/data/包名/cache/目录。上面演示一下向公有空间和缓存空间别离存入一个文件:

// 存储一个字符串到公有内部存储空间 Downloadspublic void saveToPrivate(View view) {    File externalPrivateDir = MainActivity.this.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS);    File myDownloadTxt = new File(externalPrivateDir, "myDownload.txt");    try {        BufferedWriter writer = new BufferedWriter(new FileWriter(myDownloadTxt));        writer.write("这是下载目录的文件内容!");        writer.close();    } catch (IOException e) {        e.printStackTrace();    }}// 存储一个字符串到公有内部存储空间 cachepublic void saveToCache(View view) {    File externalPrivateDir = MainActivity.this.getExternalCacheDir();    File myCacheTxt = new File(externalPrivateDir, "myCache.txt");    try {        BufferedWriter writer = new BufferedWriter(new FileWriter(myCacheTxt));        writer.write("这是缓存文件内容!");        writer.close();    } catch (IOException e) {        e.printStackTrace();    }}

所以总结一下就是:要获取内部存储就专用空间就用Environment,获取内部存储公有空间就用Context对象。

革除缓存与革除数据

革除缓存

反射调用接口:PackageManager.deleteApplicationCacheFiles

它会革除以下我的项目:

1、革除data/data/利用包名/cache/下的所有文件

2、革除data/data/利用包名/code_cache/下的所有文件

3、革除mnt/sdcard/Android/data/利用包名/下的cache文件夹

革除数据

反射调用接口:ActivityManager.clearApplicationUserData

它会革除以下我的项目:

1、革除data/data/利用包名/下的所有文件和文件夹

2、革除mnt/sdcard/Android/data/利用包名

3、革除mnt/sdcard/Android/media/利用包名

4、革除利用包名对应的App所有运行时权限的受权

总结一下外部存储与内部存储

原文地址:https://zouchanglin.cn/2020/1...