一手遮天 Android - 存儲: Android 11 通過 Storage Access Framework 管理文件


項目地址 https://github.com/webabcd/AndroidDemo
作者 webabcd

一手遮天 Android - 存儲: Android 11 通過 Storage Access Framework 管理文件

示例如下:

/storage/Android11Demo3.java

/**
 * 本例用於演示 Android 11 通過 Storage Access Framework 管理文件
 *
 * SAF(Storage Access Framework)不需要申請權限,但是需要彈出對框框,讓用戶選擇地址
 */

package com.webabcd.androiddemo.storage;

import androidx.appcompat.app.AppCompatActivity;

import android.app.Activity;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.provider.OpenableColumns;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;

import com.webabcd.androiddemo.R;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileDescriptor;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;

public class Android11Demo3 extends AppCompatActivity {

    private final String LOG_TAG = "Android11Demo3";

    private Button _button1;
    private Button _button2;
    private Button _button3;
    private Button _button4;
    private ImageView _imageView1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_storage_android11demo3);

        _button1 = findViewById(R.id.button1);
        _button2 = findViewById(R.id.button2);
        _button3 = findViewById(R.id.button3);
        _button4 = findViewById(R.id.button4);
        _imageView1 = findViewById(R.id.imageView1);

        sample();
    }

    private void sample() {
        // 通過 SAF 保存一個文本文件
        _button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                createFileText();
            }
        });

        // 通過 SAF 保存一個圖片文件
        _button2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                createFileImage();
            }
        });

        // 通過 SAF 讀取一個文本文件
        _button3.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                chooseFileText();
            }
        });

        // 通過 SAF 讀取一個圖片文件
        _button4.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                chooseFileImage();
            }
        });
    }


    // 彈出創建文件對框框,由用戶創建文本文件
    private void createFileText() {
        Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        intent.setType("text/*");
        intent.putExtra(Intent.EXTRA_TITLE, "123.txt"); // 默認文件名
        // 彈出對話框,之后可以在 onActivityResult() 中獲取用戶的操作結果
        startActivityForResult(intent, 1);
    }
    // 寫入文本數據(根據用戶選擇的 uri 地址)
    private void writeFileText(Uri uri) {
        OutputStream outputStream = null;
        BufferedWriter bufferedWriter = null;
        try {
            outputStream = this.getContentResolver().openOutputStream(uri);
            bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
            bufferedWriter.write("i am webabcd");
        } catch (Exception ex) {
            Log.d(LOG_TAG, "寫入數據失敗:" + ex.toString());
        } finally {
            try {
                if (bufferedWriter != null) {
                    bufferedWriter.close();
                }
                if (outputStream != null) {
                    outputStream.close();
                }
            } catch (Exception ex) {

            }
        }
    }


    // 彈出創建文件對框框,由用戶創建圖片文件
    private void createFileImage() {
        Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        intent.setType("image/*");
        intent.putExtra(Intent.EXTRA_TITLE, "123.jpg"); // 默認文件名
        // 彈出對話框,之后可以在 onActivityResult() 中獲取用戶的操作結果
        startActivityForResult(intent, 2);
    }
    // 寫入圖片數據(根據用戶選擇的 uri 地址)
    private void writeFileImage(Uri uri) {
        // 需要寫入的圖片數據
        BitmapDrawable bitmapDrawable = (BitmapDrawable) getResources().getDrawable(R.drawable.son01, null);
        Bitmap bitmap = bitmapDrawable.getBitmap();

        OutputStream outputStream = null;
        try {
            outputStream = this.getContentResolver().openOutputStream(uri);
            bitmap.compress(Bitmap.CompressFormat.JPEG, 85, outputStream);
        } catch (Exception ex) {
            Log.d(LOG_TAG, "寫入數據失敗:" + ex.toString());
        } finally {
            try {
                if (outputStream != null) {
                    outputStream.flush();
                    outputStream.close();
                }
            } catch (Exception ex) {

            }
        }
    }


    // 彈出選擇文件對話框,由用戶選擇文本文件
    private void chooseFileText() {
        Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        intent.setType("text/*");
        // 彈出對話框,之后可以在 onActivityResult() 中獲取用戶的操作結果
        startActivityForResult(intent, 3);
    }
    // 讀取文本數據(根據用戶選擇的 uri 地址)
    private void readFileText(Uri uri) {
        // 獲取用戶選擇的文件的文件名
        Cursor cursor = this.getContentResolver().query(uri, null, null, null, null, null);
        if (cursor != null && cursor.moveToFirst()) {
            String displayName = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
            Log.d(LOG_TAG, "file name:" + displayName);
            cursor.close();
        }

        // 讀取文本數據
        try {
            InputStream inputStream = getContentResolver().openInputStream(uri);
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
            StringBuilder sb = new StringBuilder();
            String line;
            while ((line = bufferedReader.readLine()) != null) {
                sb.append(line);
            }
            bufferedReader.close();
            inputStream.close();

            Toast.makeText(this, sb.toString(), Toast.LENGTH_LONG).show();
        } catch (Exception ex) {
            Log.d(LOG_TAG, "讀取數據失敗:" + ex.toString());
        }

    }


    // 彈出選擇文件對話框,由用戶選擇圖片文件
    private void chooseFileImage() {
        Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        intent.setType("image/*");
        startActivityForResult(intent, 4);
    }
    // 讀取圖片數據(根據用戶選擇的 uri 地址)
    private void readFileImage(Uri uri) {
        // 獲取用戶選擇的文件的文件名
        Cursor cursor = this.getContentResolver().query(uri, null, null, null, null, null);
        if (cursor != null && cursor.moveToFirst()) {
            String displayName = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
            Log.d(LOG_TAG, "file name:" + displayName);
            cursor.close();
        }

        // 讀取圖片數據並顯示
        try {
            ParcelFileDescriptor parcelFileDescriptor = getContentResolver().openFileDescriptor(uri, "r");
            FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
            Bitmap bitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor);
            parcelFileDescriptor.close();

            _imageView1.setImageBitmap(bitmap);
        } catch (Exception ex) {
            Log.d(LOG_TAG, "讀取數據失敗:" + ex.toString());
        }
    }


    // 獲取用戶在彈出的文件操作對話框中的操作結果
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        // Activity.RESULT_OK - 相關操作完成
        // Activity.DONT_FINISH_TASK_WITH_ACTIVITY - 沒有任何操作
        if (resultCode != Activity.RESULT_OK) {
            Log.d(LOG_TAG, "用戶沒有任何操作");
            return;
        }

        // 獲取用戶選擇的文件或保存的文件的 uri 地址(類似 content://com.android.providers.downloads.documents/document/3)
        Uri uri = null;
        if (data != null) {
            uri = data.getData();
            Log.d(LOG_TAG, "uri: " + uri.toString());
        }
        if (uri == null) {
            Log.d(LOG_TAG, "沒有 uri");
            return;
        }

        if (requestCode == 1) {
            // 寫入文本數據
            writeFileText(uri);
        } else if (requestCode == 2) {
            // 寫入圖片數據
            writeFileImage(uri);
        } else if (requestCode == 3) {
            // 讀取文本數據
            readFileText(uri);
        } else if (requestCode == 4) {
            // 讀取圖片數據
            readFileImage(uri);
        }
    }
}

/layout/activity_storage_android11demo3.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAllCaps="false"
        android:text="通過 SAF 保存一個文本文件" />

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAllCaps="false"
        android:text="通過 SAF 保存一個圖片文件" />

    <Button
        android:id="@+id/button3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAllCaps="false"
        android:text="通過 SAF 讀取一個文本文件" />

    <Button
        android:id="@+id/button4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAllCaps="false"
        android:text="通過 SAF 讀取一個圖片文件" />

    <ImageView
        android:id="@+id/imageView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp" />

</LinearLayout>

項目地址 https://github.com/webabcd/AndroidDemo
作者 webabcd


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM