潇洒郎: 解决Android 10 外部存储问题——专有目录创建文件无需读写权限

潇洒郎: 解决Android 10 外部存储问题

 

基于Android 10(Q),即SdkVersion > 28 

Android 10存储方式发生改变, Q版本 访问自己应用的专有目录无需读写权限。

媒体收藏(图片,视频,音频等)需要申请权限,并借助MediaStorage

下载(文档与电子书等)无需权限。

方法1—— 最简单:

在应用的专有目录创建文件无需读写权限:

应用的专有目录: 

basePath1= "/storage/emulated/0/Android/data/com.example.storage1/files/Documents/";
basePath2= getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS).getAbsolutePath()+ "/";

注意: 打印出来的basePath2字符串与basePath1的字符串一模一样。但是basePath1 不等于basePath2。

Android 10 版本中 不配置权限等 只能用 basePath2, 建议使用basePath2, 超级简单,只是

使用basePath1 这种路径的写法,是Android10 以下版本的写法,需要权限申请,配置方法如方法2.

 

方法2- 麻烦复杂:

1、 ActivityManifest.xml 配置

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.storage1">

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

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.AppCompat.DayNight.NoActionBar"
        android:requestLegacyExternalStorage="true">
        <activity android:name=".DefaultActivity"></activity>
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

关键两点:

 

2. activity_main.xml

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

    <EditText
        android:id="@+id/text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="请输入数据"
        android:layout_marginTop="30dp"
        />
    <EditText
        android:id="@+id/filepath"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="文件名路径"
        android:layout_marginTop="30dp"
        />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        >
        <Button
            android:id="@+id/save"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="wrap_content"
            android:text="保存数据"
            android:textSize="15dp"
            android:textStyle="bold"
            android:layout_marginTop="30dp"
            android:textColor="#E91E63"
            android:background="#009688"
            android:textAllCaps="false"

            />

        <Button
            android:id="@+id/show"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="wrap_content"
            android:text="显示数据"
            android:textColor="@color/teal_200"
            android:background="#B61AD1"
            android:textSize="15dp"
            android:textStyle="bold"
            android:layout_marginTop="30dp"
            android:textAllCaps="false"
            android:layout_marginLeft="20dp"
            />
    </LinearLayout>

    <EditText
        android:id="@+id/rootpath"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="手机root路径"
        android:layout_marginTop="30dp"
        />
    <EditText
        android:id="@+id/text2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="显示文件名路径中的数据"
        android:layout_marginTop="30dp" />


</LinearLayout>

视图为:

 

3. MainActivity.java

package com.example.storage1;

import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;

import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

public class MainActivity extends AppCompatActivity{

    private Button save,show;
    private EditText editText, editText2, editTextFilePath, editTextRootPath;
    private static String basePath= "/storage/emulated/0/Android/data/";
    private static String baseDir="";
    private static String fileName="";

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        save= (Button) findViewById(R.id.save);
        show= (Button) findViewById(R.id.show);
        editText=(EditText) findViewById(R.id.text);
        editText2=(EditText) findViewById(R.id.text2);
        editTextFilePath=(EditText) findViewById(R.id.filepath);
        editTextRootPath=(EditText) findViewById(R.id.rootpath);
        editTextRootPath.setText(basePath);
        // 申请权限,否则手机默认禁止存储
        ActivityCompat.requestPermissions(MainActivity.this,new String[  ]{
                "android.permission.WRITE_EXTERNAL_STORAGE",
                "android.permission.READ_EXTERNAL_STORAGE"},1);
        // 开始逻辑
        basePath= basePath + getPackageName()+"/files/";
        save.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String relatedPath= editTextFilePath.getText().toString();
                String[] allP= getBaseDirAndFileName(relatedPath);
                baseDir = allP[0];
                fileName = allP[1];
                //获取应用目录File filePictures = getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS);
                String str= editText.getText().toString();
                F.save(str,baseDir, fileName);
                ToastUtil.showMsg(MainActivity.this, "保存数据成功");
            }
        });
        show.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                editText2.setText(F.read(baseDir+fileName));
            }
        });
    }

    public static String[] getBaseDirAndFileName(String relatedPath){
        String[] dirFile= relatedPath.split("/");
        int sLength=dirFile.length;
        String fileName= dirFile[sLength-1];
        String fileDir= "";
        for (int i=0;i<sLength-1;i++){
            fileDir+=dirFile[i];
            fileDir+="/";
        }
        String[] baseDirFileName={"",""};
        baseDirFileName[0]=basePath+fileDir;
        baseDirFileName[1]=fileName;
        return baseDirFileName;
    }

4. ToastUtil.java  用于显示提示信息

package com.example.storage1;

import android.content.Context;
import android.widget.Toast;

public class ToastUtil {
    public static Toast mToast;
    public static void showMsg(Context context, String msg){
        if (mToast==null){
            mToast= Toast.makeText(context, msg, Toast.LENGTH_LONG);
        }
        else{
            mToast.setText(msg);
        }
        mToast.show();
    }
}
ToastUtil.showMsg(MainActivity.this, "保存数据成功");

5. 读取与写入文件:

package com.example.storage1;

import android.util.Log;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.File;

public class F {
    private static MainActivity mainActivity;
    // Android 10 外部存储
    // 必须存储至应用/storage/emulated/0/Android/data/包名/files/内
    public static void save(String str, String filePath, String fileName){
        try{
            File fileDir = new File(filePath);
            if (fileDir.exists()) {
                File file= new File(fileDir,fileName);
                FileOutputStream fos = new FileOutputStream(file);
                fos.write(str.getBytes());
                fos.flush();
                fos.close();
            }else if (fileDir.mkdirs()) {//如果该文件夹不存在,则新建
                File file= new File(fileDir,fileName);
                FileOutputStream fos = new FileOutputStream(file);
                fos.write(str.getBytes());
                fos.flush();
                fos.close();
            }
        }catch (IOException e) {e.printStackTrace();}
    }

    public static String read(String filePath)
    {
        try {
            File file= new File(filePath);
            if (!file.exists()){
                Log.d("读取的文件夹不存在:",file.toString());
                return null;
            }
            FileInputStream fis= new FileInputStream(file);
            byte[] buff=new byte[1024];
            StringBuilder sb= new StringBuilder();
            int len=0;
            while((len=fis.read(buff))>0)
            {
                sb.append(new String(buff,0,len));
            }
            fis.close();
            return sb.toString();
        }
        catch (IOException e) {}
        return null;
    }
}

运行: 效果展示,我用的是手机HUAWEIMate20 Android 10 系统

借鉴博客:https://blog.csdn.net/zhendong_hu/article/details/104921985

https://blog.csdn.net/zw904448290/article/details/114316496

https://blog.csdn.net/yehui928186846/article/details/101706238?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-4.control&dist_request_id=&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-4.control

 

google开发手册: https://developer.android.google.cn/training/data-storage/app-specific#java

  • 2
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

潇洒郎

您打赏我发自肺腑努力创作的心灵

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值