介绍
这篇文章主要关于我学习SD卡的动态获取权限时的一些问题。
Android的目录结构
参考自解析Android内部存储、外部存储的区别 图: 以我的手机为例,可以看到: 与adb shell的ls命令相结合: 可见,一般的手机用户(即非程序员用户)在手机的文件管理所能看到、操纵的文件都是手机的/storage/emulated/0目录下文件。
数据的主要存储方式
在疯狂Android讲义–第四版中,主要提到的几种存储方式中:
- 使用数据文件夹。即内存储
- 使用SharedPreferences与Editor
数据总保持在/data/data/< package name>/shared_prefs中 - 使用openFileOutput和openFileInput
数据总保持在/data/data/< package name>/files中 - 读取SD卡上文件
数据总保存在/storage/emulated/0目录下。 - SQLite数据库
嗯,存储的位置大概是比较随意。 而这篇文章主要是关于SD卡的
疑惑
在学习教科书时,我发现课本的8.2.2节中,用Genymotion模拟器(google nexus 5,API 23)可以基本还原实验效果,但用我本人的真机(红米k30)以及Android Studio(Pixel_XL_API_30)自带的就不行了。 同时每次访问SD卡,都要来个: 你说这谁顶得住啊? 我搜了一下,说什么Android 6.0+需要动态申请。尤其是我发现,平时的文件也是放在所谓的SD卡目录下的,为什么其他应用就不用说什么动态申请?
原来的代码:MainActivity.java
package com.example.android.filetest;
import android.Manifest;
import android.app.Activity;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;
public class MainActivity extends Activity {
private static final String FILE_NAME = "/crazy.bin";
private EditText edit1;
private TextView edit2;
File f1;
File f2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button read = findViewById(R.id.read);
Button write = findViewById(R.id.write);
edit1 = findViewById(R.id.edit1);
edit2 = findViewById(R.id.edit2);
write.setOnClickListener(view ->
requestPermissions(new String[]
{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 0x123));
read.setOnClickListener(view ->
requestPermissions(new String[]
{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 0x456));
}
private String read() {
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
System.out.println(Environment.getExternalStorageState());
File sdCardDir = Environment.getExternalStorageDirectory();
try (
FileInputStream fis = new FileInputStream(sdCardDir.getCanonicalPath() + FILE_NAME);
BufferedReader br = new BufferedReader(new InputStreamReader(fis))
) {
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = br.readLine()) != null) {
sb.append(line);
}
return sb.toString();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
private void write(String content) {
File sdCardDir = Environment.getExternalStorageDirectory();
try {
System.out.println(sdCardDir.getCanonicalPath() + FILE_NAME);
File targetFile = new File(sdCardDir.getCanonicalPath() + FILE_NAME);
System.out.println("file is exist: " + targetFile.exists());
RandomAccessFile raf = new RandomAccessFile(targetFile, "rw");
raf.seek(targetFile.length());
raf.write(content.getBytes());
raf.close();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void onRequestPermissionsResult(int requestCode,
String[] permissions, int[] grantResults) {
if (requestCode == 0x123) {
if (grantResults != null && grantResults[0] ==
PackageManager.PERMISSION_GRANTED) {
write(edit1.getText().toString());
edit1.setText("");
} else {
Toast.makeText(this, R.string.writesd_tip, Toast.LENGTH_LONG)
.show();
}
}
if (requestCode == 0x456) {
if (grantResults != null && grantResults[0] ==
PackageManager.PERMISSION_GRANTED) {
edit2.setText(read());
} else {
Toast.makeText(this, R.string.writesd_tip, Toast.LENGTH_LONG)
.show();
}
}
}
}
我觉得说可能是教材没说,就找了找,最终找了个参考:Android无法在SD卡写入文件(Android6.0+需要动态申请 解决了。
修改后代码:
package com.example.android.sdtest_my_1;
import android.Manifest;
import android.app.Activity;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;
public class MainActivity extends Activity {
private static final String FILE_NAME = "/crazy.bin";
private EditText edit1;
private TextView edit2;
File f1;
File f2;
private static final int REQUEST_EXTERNAL_STORAGE = 1;
private static String[] PERMISSIONS_STORAGE = {
"android.permission.READ_EXTERNAL_STORAGE",
"android.permission.WRITE_EXTERNAL_STORAGE" };
public static void verifyStoragePermissions(Activity activity) {
try {
int permission = ActivityCompat.checkSelfPermission(activity,
"android.permission.WRITE_EXTERNAL_STORAGE");
if (permission != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(activity, PERMISSIONS_STORAGE,REQUEST_EXTERNAL_STORAGE);
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button read = findViewById(R.id.read);
Button write = findViewById(R.id.write);
edit1 = findViewById(R.id.edit1);
edit2 = findViewById(R.id.edit2);
write.setOnClickListener(view ->
write());
read.setOnClickListener(view ->
read());
verifyStoragePermissions(this);
}
private void read() {
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
System.out.println(Environment.getExternalStorageState());
File sdCardDir = Environment.getExternalStorageDirectory();
try (
FileInputStream fis = new FileInputStream(sdCardDir.getCanonicalPath() + FILE_NAME);
BufferedReader br = new BufferedReader(new InputStreamReader(fis))
) {
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = br.readLine()) != null) {
sb.append(line);
}
edit2.setText(sb.toString());
} catch (IOException e) {
e.printStackTrace();
}
} else {
edit2.setText(null);
}
}
private void write() {
String content = edit1.getText().toString();
edit1.setText("");
File sdCardDir = Environment.getExternalStorageDirectory();
try {
System.out.println(sdCardDir.getCanonicalPath() + FILE_NAME);
File targetFile = new File(sdCardDir.getCanonicalPath() + FILE_NAME);
System.out.println("file is exist: " + targetFile.exists());
RandomAccessFile raf = new RandomAccessFile(targetFile, "rw");
raf.seek(targetFile.length());
raf.write(content.getBytes());
raf.close();
System.out.println("ok, writedc");
} catch (IOException e) {
e.printStackTrace();
}
}
}
一次申请,永久ok……吧。
作者:Andrew Detmer(当然是假名了。) 原文链接
|