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", "外部存儲不可用");
}
}
}