1. Data storage methods

Android uses a file system similar to disk-based file systems on other platforms. The system gives you the following options for saving application data:

  • Application-specific storage space: Stores files only for use. Files can be stored in a dedicated directory in an internal storage volume or another dedicated directory in an external storage space. Use directories in the internal storage space to store sensitive information that should not be accessed by other applications.
  • Shared storage: Stores files that your application intends to share with other applications, including media, documents, and other files.
  • Preferences: Store private raw data as key-value pairs.
  • Database: Use the Room persistence library to store structured data in a dedicated database.

The following table summarizes the features of these options:

Content type Access methods The required permissions Whether other applications can be accessed Uninstallation Indicates whether to remove the application
A file for your application only To access from internal storage, use the getFilesDir() or getCacheDir() methods;



To access from external storage, use the getExternalFilesDir() or getExternalCacheDir() methods
Access from internal storage space does not require any permissions



If the application is running on a device running Android 4.4 (API level 19) or higher, access from external storage space does not require any permissions
If the file is stored in a directory in internal storage space, it cannot be accessed

If the file is stored in a directory in external storage space, it can be accessed
is
Shareable media files (images, audio files, videos) MediaStore API In Android 10 (API level 29) or later, access to files of other applications requires the READ_EXTERNAL_STORAGE or WRITE_EXTERNAL_STORAGE permission



On Android 9 (API level 28) or lower, permissions are required to access all files
Yes, but other applications require the READ_EXTERNAL_STORAGE permission no
Key/value pair SharedPreferences There is no no is
Structured data Database Room There is no no is
External shared storage space file Access by path or Uri The READ_EXTERNAL_STORAGE or WRITE_EXTERNAL_STORAGE permission is required



Android 11 Add the MANAGE_EXTERNAL_STORAGE permission
is no

Two, different storage mode of use

2.1 Application-Specific Storage Space

Internal storage: / data/data/packagename/external storage: / sdcard/Android/data/packagename /

The App can use these two directories without applying for access permission. Use is also very simple, directly through the path access.

  public static String readFile(Context context, String fileName) {
    File file = new File(context.getCacheDir(), fileName);
    try {
      FileInputStream fis = new FileInputStream(file);
      BufferedReader br = new BufferedReader(new InputStreamReader(fis));
      Log.d(TAG, "readFile: " + br.readLine());
      return br.readLine();
    } catch (Exception e) {
      e.printStackTrace();
    }
    return "";

  }

  public static void writeFile(Context context, String fileName, String content) {
    File file = new File(context.getCacheDir(), fileName);
    try {
      FileOutputStream fos = new FileOutputStream(file);
      fos.write(content.getBytes());
      fos.close();
    } catch(Exception e) { e.printStackTrace(); }}Copy the code

2.2 Sharing media Files

To apply for permission

Androidmanifest.xml: Androidmanifest.xml: androidmanifest.xml: androidmanifest.xml: androidmanifest.xml:

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
Copy the code

After Android 6.0, in addition to declaring storage permissions in androidmanifest.xml, you also need to apply permissions dynamically.

  // Check permissions and return a list of permissions to apply for
  private List<String> checkPermission(Context context, String[] checkList) {
    List<String> list = new ArrayList<>();
    for (int i = 0; i < checkList.length; i++) {
      if (PackageManager.PERMISSION_GRANTED != ActivityCompat
          .checkSelfPermission(context, checkList[i])) {
        list.add(checkList[i]);
      }
    }
    return list;
  }

  // Request permission
  private void requestPermission(Activity activity, String requestPermissionList[]) {
    ActivityCompat.requestPermissions(activity, requestPermissionList, 100);
  }

  // After the user makes a choice, the result of the application is returned
  @Override
  public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
      @NonNull int[] grantResults) {
    if (requestCode == 100) {
      for (int i = 0; i < permissions.length; i++) {
        if (permissions[i].equals(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
          if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
            Toast.makeText(MainActivity.this."Storage permission applied successfully", Toast.LENGTH_SHORT).show();
          } else {
            Toast.makeText(MainActivity.this."Storage permission application failed", Toast.LENGTH_SHORT).show();
          }
        }
      }
    }
  }

  // Test applying for storage permission
  private void testPermission(Activity activity) {
    String[] checkList = new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE,
        Manifest.permission.READ_EXTERNAL_STORAGE};
    List<String> needRequestList = checkPermission(activity, checkList);
    if (needRequestList.isEmpty()) {
      Toast.makeText(MainActivity.this."No permission required", Toast.LENGTH_SHORT).show();
    } else {
      requestPermission(activity, needRequestList.toArray(newString[needRequestList.size()])); }}Copy the code

access

1. Access through a path

In images, for example, suppose that picture is stored in the/sdcard/Pictures/test. The JPG

  private Bitmap getBitmap(String fileName) {
    // Obtain directory: /storage/emulated/0/
    File rootFile = Environment.getExternalStorageDirectory();
    String imagePath = rootFile.getAbsolutePath() + File.separator + Environment.DIRECTORY_PICTURES + File.separator + fileName;
    return BitmapFactory.decodeFile(imagePath);
  }
Copy the code
2. Obtain the path from MediaStore
  private Bitmap getBitmap(Context context, String fileName) {
    ContentResolver contentResolver = context.getContentResolver();
    // Query conditions
    String selection = MediaStore.Images.Media.DISPLAY_NAME + "=?";
    String[] selectionArgs = new String[]{fileName};

    Cursor cursor = contentResolver
        .query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null, selection, selectionArgs, null);
    while (cursor.moveToNext()) {
      // Get the image path
      String imagePath = cursor.getString(cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA));
      return BitmapFactory.decodeFile(imagePath);
    }
    return null;
  }
Copy the code
3. Obtain the Uri through MediaStore
  private Bitmap getBitmap(Context context, String fileName) throws FileNotFoundException {
    ContentResolver contentResolver = context.getContentResolver();
    String selection = MediaStore.Images.Media.DISPLAY_NAME + "=?";

    String[] selectionArgs = new String[]{fileName};

    Cursor cursor = contentResolver
        .query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null, selection, selectionArgs, null);
    while (cursor.moveToNext()) {
      long id = cursor.getLong(cursor.getColumnIndex(MediaStore.Images.Media._ID));
	  / / get a Uri
      Uri contentUri = ContentUris.withAppendedId(
          MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
          id
      );
      // Construct InputStream through Uri
      InputStream inputStream = contentResolver.openInputStream(contentUri);
      // Get the Bitmap via InputStream
      return BitmapFactory.decodeStream(inputStream);
    }
    return null;
  }
Copy the code

Adapter Android 10

Android 10 or later cannot directly obtain the file through the path, that is, bitmapFactory. decodeFile(imagePath) cannot be used normally, indicating that there is no permission. Image resources can only be obtained through URIs.

2.3 SharedPreferences

SharedPreferences are used primarily to hold relatively small collections of key-value pairs and are simple to use.

Context context = getActivity();
/ / create the SharedPreferences
SharedPreferences sharedPref = context.getSharedPreferences(
            name, Context.MODE_PRIVATE);
    // Write data through editor
    SharedPreferences.Editor editor = sharedPref.edit();
    editor.putInt(key, value);
    editor.commit();
// Read data
int data = sharedPref.getInt(key, defaultValue);

Copy the code

2.4 database

For basic Room usage, please refer to my other article: Android Room usage

2.5 External Non-media Shared Storage Space

Storage space in addition to application-specific space.

To apply for permission

Similar to shared media files, apply for WRITE_EXTERNAL_STORAGE and READ_EXTERNAL_STORAGE

access

1. Access through a path

As with media files, a path is constructed directly for access. Through the Environment. External.getexternalstoragedirectory () the external storage path, and can be operated by the path.

    private void testPublicFile(a) {
        File rootFile = Environment.getExternalStorageDirectory();
        String imagePath = rootFile.getAbsolutePath() + File.separator + "myDir";
        File myDir = new File(imagePath);
        if (!myDir.exists()) {
            myDir.mkdir();
        }
    }
Copy the code

Create a folder for myDir under /sdcard/.

2. Access through SAF

Storage Access Framework SAF: Storage Access Framework. The system is equivalent to a built-in file selector, through which you can get the file information you want to access.

 private void startSAF(a) {
    Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
    intent.addCategory(Intent.CATEGORY_OPENABLE);
    // Select the image
    intent.setType("image/jpeg");
    // Jumps to a file selector
    startActivityForResult(intent, 100);
  }

  @Override
  protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    if (requestCode == 100&& data ! =null) {
      // Select the returned image to encapsulate in the URI
      Uri uri = data.getData();
      Bitmap bitmap = openUri(uri);
      if(bitmap ! =null) { binding.iv.setImageBitmap(bitmap); }}}private Bitmap openUri(Uri uri) {
    try {
      Construct the input stream from the URI
      InputStream fis = getContentResolver().openInputStream(uri);
      return BitmapFactory.decodeStream(fis);
    } catch (Exception e) {
      Log.e(TAG, "openUri: ", e);
    }
    return null;
  }
Copy the code

Jump to the system’s built-in file selector:

In this mode, you can access external files without applying for read/write permissions. However, you cannot directly obtain the path of external files. You need to use the Uri to convert external files.

Adapter Android 10

Android 10 has added the function of partition storage to restrict APP access to the exclusive storage space of the APP. Instead of directly accessing files in the SDcard through the path, only SAF can be used. It can avoid that each APP keeps writing data into the SDcard without integrity. The prompt for applying for file read and write permission has also been revised.

Android 6 – Android 9:

Android 10 and later:

Compare to the lower version, which only allows access to photos and media content.

Adapter Android 11

Android 11 adds a MANAGE_EXTERNAL_STORAGE permission for all files. This permission is stricter than the read and write permission for files. You need to go to the Settings page instead of a pop-up message. If granted, this permission allows the developer to access all files in the external store using a path approach. Add the following permissions to androidmanifest.xml:

    <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
Copy the code

Dynamic application permission in code:

  private void requestPermission(a) {
  	// Need to determine the version
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
      // Check whether there is permission
      if (Environment.isExternalStorageManager()) {
        // Authorized
      } else {
        Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);
        intent.setData(Uri.parse("package:" + getPackageName()));
        startActivityForResult(intent, 101); }}}@Override
  protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == 101 && Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
      if (Environment.isExternalStorageManager()) {
        Toast.makeText(this."All file access permissions have been granted.", Toast.LENGTH_SHORT).show();
      } else {
        Toast.makeText(this."All file access permissions failed", Toast.LENGTH_SHORT).show(); }}}Copy the code

The authorization mode is as follows: