安卓开发之关于外部存储不可用的解决办法(Android studio)

安卓开发之关于外部存储不可用的解决办法(Android studio)_第1张图片
Android应用开发中,常使用Environment类去获取外部存储目录,在访问外部存储之前一定要先判断外部存储是否已经是可使用(已挂载&可使用)状态,并且需要在AndroidManifest.xml文件中添加外部存储读和写的权限
Environment类中提供了几个静态常量用于标识外部存储的状态,这些状态都是String类型

MEDIA_BAD_REMOVAL 在没有挂载前存储媒体已经被移除。 MEDIA_CHECKING 正在检查存储媒体。
MEDIA_MOUNTED 存储媒体已经挂载,并且挂载点可读/写。 MEDIA_MOUNTED_READ_ONLY
存储媒体已经挂载,挂载点只读。 MEDIA_NOFS 存储媒体是空白或是不支持的文件系统。 MEDIA_REMOVED 存储媒体被移除。
MEDIA_SHARED 存储媒体正在通过USB共享。 MEDIA_UNMOUNTABLE 存储媒体无法挂载。
MEDIA_UNMOUNTED 存储媒体没有挂载。

可以通过静态方法getExternalStorageState()
来获取外部存储的状态,如果程序需要在外部存储里面读写数据,
必须要先判断:

if(Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) 
|| !Environment.isExternalStorageRemovable());

下面这篇文章写得外部存储的注意很全面,有很大的参考价值
https://blog.csdn.net/FDGFGFDGFD/article/details/80434520

如果在Android6.0(API:23)以下的版本中申请权限只需要AndroidMainfest文件中中申请权限就行,只需要这样写就行了

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

<!--    声明权限-->
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE "/>
    <uses-permission android:name="android.permission.WRITE_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/AppTheme">


        <activity android:name=".ActivityExample">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="cn.itcast.start_activity" />
<!--                当设置为LAUNCHER的时候,应用默认打开的界面-->
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <!--        配置Activity-->
        <!---->
        <activity android:name=".SecondActivity"></activity>
    </application>
</manifest>

上面不难看出,在manifest>中直接添加的读取和写入的权限

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

安卓6.0以上的版本怎么办,就需要动态申请权限了
下面添加了一个显示跳转与隐式跳转的两种方式,是activity组件的知识,不必在意在此处

package com.example.myapplication;

import androidx.appcompat.app.AppCompatActivity;

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

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;

public class ActivityExample extends AppCompatActivity implements View.OnClickListener {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_example);
        findViewById(R.id.start).setOnClickListener(this);
        findViewById(R.id.start).setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {

        switch (v.getId()){
            case R.id.start:    //显示意图
                Intent intent = new Intent(ActivityExample.this,MainActivity.class);
                startActivity(intent);
                break;
            case  R.id.start2:   //隐示意图
                Intent intent1 = new Intent();
                intent1.setAction("cn.itcast.start_activity");
                startActivity(intent1);
                break;

        }
    }
}

下面是自己画的界面,额,有点丑
安卓开发之关于外部存储不可用的解决办法(Android studio)_第2张图片
实现代码:(采用的ConstraintLayout线性布局)

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
    tools:context=".MainActivity"
    android:gravity="center">

    <CheckBox
        android:id="@+id/isAutoLogin"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="取消用户名"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.948"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.553" />

    <CheckBox
        android:id="@+id/isRememberUsername"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="记住用户名"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.572"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.553" />

    <TextView
        android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="密码:"
        android:textSize="24sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.186"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.449" />

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="用户名:"
        android:textSize="24sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.185"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.352" />

    <EditText
        android:id="@+id/password"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:ems="10"
        android:inputType="textPassword"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.317"
        app:layout_constraintStart_toEndOf="@+id/textView2"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.457" />

    <EditText
        android:id="@+id/usename"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:ems="10"
        android:inputType="textPersonName"
        android:text="Name"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.022"
        app:layout_constraintStart_toEndOf="@+id/textView"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.358" />

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="注册"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.746"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.736" />

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="登录"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.343"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.736" />
</androidx.constraintlayout.widget.ConstraintLayout>

下面就是实现动态实现申请权限的方法:(单独一个文件)

package com.example.myapplication;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;

import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.Toast;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;


public class MainActivity extends AppCompatActivity {
    //自定义文本、按钮、多选框的变量
    private EditText usename;
    private EditText password;
    private Button button;
    private Button button2;
    private CheckBox isRememberUsername;
    private CheckBox isAutoLogin;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        //下面的是新建程序自带的,实现父类中的onCreate方法
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //获取R文件的各种控件赋值给上面的控件
        //因为上面定义变量为成员变量,所以此处不必写类名
        //定义成员变量的目的是因为在在此文件下都可以私用
        usename = findViewById(R.id.usename);
        password = findViewById(R.id.password);
        button = findViewById(R.id.button2);
        button2 = findViewById(R.id.button);
        isRememberUsername = findViewById(R.id.isRememberUsername);
        isAutoLogin = findViewById(R.id.isAutoLogin);

        button2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
//                这里是内部存储,不需要申请权限

                这里是开启Activity跳转的写法
//                  采用的intent类进行开启的
                   // 参数一:Activity未跳转的界面
                   // 参数二:Activity将要跳转的界面
//                Intent intent = new Intent(MainActivity.this,SecondActivity.class);
//                startActivity(intent);

                文件读取,采用File流与getFilesDir()方法打开将要存储的文件
//                File fileDir = getFilesDir();
                //给文件起个名字login.data
//                File destFile = new File(fileDir,"login.data");
//                try {
//                    BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(destFile)));
                    //这里需要用包装类的valueOf()方法来进行转化,因为有的输入账号和密码是数字,需要转换为字符串
//                    writer.write(String.valueOf(usename));
                    //这里需要不断地刷新换行,一行一行的读取
//                    writer.newLine();
//
//                    writer.write(String.valueOf(password));
//                    writer.newLine();
//
//                    writer.write(String.valueOf(isRememberUsername));
//                    writer.newLine();
//
//                    writer.write(String.valueOf(isAutoLogin));
//
//                    writer.newLine();
                    //这里需要刷新一下保证全部读取成功
//                    writer.flush();
                    //严格的编码需要关闭流
//
//                    Log.d("TEST","操作成功");
//
//                } catch (Exception e) {
//                    Log.d("TEST",e.getMessage());
//                    e.printStackTrace();
//                }


                //检查是否有写入存储卡的权限
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                    //全部所需要的权限的数组,这里只添加了一个写入权限 
                    String[] permissions = {
                            Manifest.permission.WRITE_EXTERNAL_STORAGE
                    };

                    //用来表示,是否用有全部的权限,是为true,不是为false
                    boolean granted = true;
                    //对一个权限进行验证,for-Each循环
                    for (String permission : permissions) {
                        if (ContextCompat.checkSelfPermission(view.getContext(), permission) != PackageManager.PERMISSION_DENIED) {
                                granted = false;
                                break;
                        }
                    }
                    //编写两个方法,在下面,有权限就是直接写入,没有权限再
                    //验证是否拥有权限
                    if (granted) {
                        //存储用户登录信息
                        saveUserLogin();
                    } else {
                        //申请权限
                        requestPermissions(permissions, 0xA1);
                    }
                } else {
                    //存储用户登录信息
                    saveUserLogin();
                }


            }
        });
        //为登录设置一事件监听的提示
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                isRememberUsername.setChecked(false);
                isAutoLogin.setChecked(false);
                usename.setText("");
                password.setText("");
                Toast.makeText(MainActivity.this, "登录成功", Toast.LENGTH_SHORT).show();
            }
        });

//        加载上次保存的信息
        try {
            BufferedReader reader = new BufferedReader(new InputStreamReader(openFileInput("login.data")));
            String un = reader.readLine();
            String pw = reader.readLine();

        } catch (Exception e) {
            Log.d("TEST", e.getMessage());
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        //对应上面申请外部存储器的权限
        if (requestCode == 0xA1) {
            boolean granted = true;
            for (int result : grantResults) {
                if (result != PackageManager.PERMISSION_DENIED) {
                    granted = false;
                    break;
                }
            }

            if (granted) {
                //确定获取了权限则进行写入
                saveUserLogin();
            } else {
                Toast.makeText(MainActivity.this, "未能能获取权限,不能进行此操作", Toast.LENGTH_SHORT).show();
            }
        }
    }

    private void saveUserLogin() {
        //登录信息存储在外部存储器中
        if (Environment.getExternalStorageState().equalsIgnoreCase(Environment.MEDIA_BAD_REMOVAL)) {
            File root = Environment.getExternalStorageDirectory();
            Log.d("TEST", root.getAbsolutePath());
            Log.d("TEST", "外部存储可用");
        } else {
            Log.d("TEST", "外部存储不可用");
        }
    }
}

你可能感兴趣的:(安卓开发)