安卓開發之關於外部存儲不可用的解決辦法(Android studio)

在這裏插入圖片描述
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></mainfest>中直接添加的讀取和寫入的權限

<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;

        }
    }
}

下面是自己畫的界面,額,有點醜
在這裏插入圖片描述
實現代碼:(採用的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", "外部存儲不可用");
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章