共计 8552 个字符,预计需要花费 22 分钟才能阅读完成。
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 应用形式:
// 取数据
@Override
protected 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/ 目录。上面演示一下向公有空间和缓存空间别离存入一个文件:
// 存储一个字符串到公有内部存储空间 Downloads
public 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();
}
}
// 存储一个字符串到公有内部存储空间 cache
public 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…