【发布时间】:2021-12-28 15:50:15
【问题描述】:
您可能已经知道,Google 已经更改了外部存储访问权限的准则等。 尝试了谷歌文档中的所有提示和技巧,但它对我不起作用。一旦我单击“备份”按钮和“确定”,应用程序就会崩溃。我没有更多的想法来解决这个问题。现在我请教各位专家。我对每个提示都很满意。
- Android 11
- TargetSDK 31
我将分享相关代码以使其尽可能清晰。
清单:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" tools:ignore="ScopedStorage"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
Utils.java
public static Boolean askForReadPermission(final Activity activity, final PermissionCallback permissionCallback, View view){
if(android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.M || Nammu.checkPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)){
return true;
}
else{
final String[] permissions = {Manifest.permission.WRITE_EXTERNAL_STORAGE};
if (Nammu.shouldShowRequestPermissionRationale(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
Snackbar.make(view, activity.getString(R.string.error_permission_backup),
Snackbar.LENGTH_INDEFINITE)
.setAction("OK", new View.OnClickListener() {
@Override
public void onClick(View view) {
Nammu.askForPermission(activity, permissions, permissionCallback);
}
}).show();
} else {
Nammu.askForPermission(activity, permissions, permissionCallback);
}
return false;
}
}
public static String getStorageDir(){
String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/myApp";
File f = new File(path);
if(!f.exists()) if(!f.mkdirs()) return null;
return f.getAbsolutePath();
}
public static String getStorageDirForBackup(){
String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/My_Backup";
File f = new File(path);
if(!f.exists()) if(!f.mkdirs()) return null;
return f.getAbsolutePath();
}
Backup.java
public class RealmBackup {
private static final String TAG = "Backuplog";
private final String EXPORT_REALM_FILE_NAME = "backup.realm";
private final Activity activity;
private final Realm realm;
public RealmBackupRestore(Activity activity, Realm realm) {
this.activity = activity;
this.realm = realm;
}
@SuppressLint("StaticFieldLeak")
public void backup() {
new AsyncTask<Void, Void, Boolean>() {
private SweetAlertDialog dialog;
@Override
protected void onPreExecute() {
dialog = new SweetAlertDialog(activity, SweetAlertDialog.PROGRESS_TYPE);
dialog.setContentText(activity.getString(R.string.settings_do_backup));
dialog.setTitleText("");
dialog.show();
}
@Override
protected Boolean doInBackground(Void... params) {
Realm realm = Realm.getDefaultInstance();
File exportRealmFile;
exportRealmFile = new File(Utils.getStorageDir(), EXPORT_REALM_FILE_NAME);
realm.writeCopyTo(exportRealmFile);
File zipFile = new File(Utils.getStorageDirForBackup(), "backup_" + System.currentTimeMillis() + ".zip");
zipFile.delete();
File wholeDirectory = new File(Utils.getStorageDir() + "/");
ZipUtil.pack(wholeDirectory, zipFile);
exportRealmFile.delete();
realm.beginTransaction();
Objects.requireNonNull(Settings.getSettings(realm)).setLastBackup(new Date());
realm.commitTransaction();
realm.close();
return true;
}
@Override
protected void onPostExecute(Boolean result) {
dialog.cancel();
AlertDialog.Builder alertBuilder = new AlertDialog.Builder(activity);
alertBuilder
.setMessage(activity.getString(R.string.settings_backup_stored))
.setNeutralButton(activity.getString(R.string.generell_ok), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
}
})
.show();
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
private String dbPath(){
return realm.getPath();
}
}
FragmentBackup.java
backup.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
AlertDialog.Builder alertBuilder = new AlertDialog.Builder(getContext());
alertBuilder
.setMessage(R.string.settings_backup_store_dialog)
.setPositiveButton(R.string.generell_ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
if(!Utils.askForReadPermission(getActivity(), permissionCallbackBackup ,backup))return;
realmBackupRestore.backup();
}
})
.setNegativeButton(R.string.generell_cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
}
})
.show();
}
});
Logcat:
2021-12-28 16:38:54.375 28406-28575/devs.myApp E/AndroidRuntime: FATAL EXCEPTION: AsyncTask #1
Process: devs.myApp, PID: 28406
java.lang.RuntimeException: An error occurred while executing doInBackground()
at android.os.AsyncTask$4.done(AsyncTask.java:415)
at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:383)
at java.util.concurrent.FutureTask.setException(FutureTask.java:252)
at java.util.concurrent.FutureTask.run(FutureTask.java:271)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:923)
Caused by: io.realm.exceptions.RealmFileException: Unable to open a realm at path '/backup.realm'. Please use a path where your app has read-write permissions. (open("/backup.realm") failed: Read-only file system) (/backup.realm) in /home/cc/repo/realm/release/realm/realm-library/src/main/cpp/io_realm_internal_OsSharedRealm.cpp line 407 Kind: PERMISSION_DENIED.
at io.realm.internal.OsSharedRealm.nativeWriteCopy(Native Method)
at io.realm.internal.OsSharedRealm.writeCopy(OsSharedRealm.java:343)
at io.realm.BaseRealm.writeCopyTo(BaseRealm.java:274)
at io.realm.Realm.writeCopyTo(Realm.java:135)
at devs.myApp.utils.RealmBackupRestore$1.doInBackground(RealmBackupRestore.java:65)
at devs.myApp.utils.RealmBackupRestore$1.doInBackground(RealmBackupRestore.java:45)
at android.os.AsyncTask$3.call(AsyncTask.java:394)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:923)
【问题讨论】:
-
你在运行时获得了
MANAGE_EXTERNAL_STORAGE的权限吗?? -
写入允许写入的位置,例如
Context上的getExternalFilesDir()。 -
The app crashes, once I clicked to "Backup" button这并没有告诉我们任何事情。更好地判断哪个代码语句导致异常。 -
Utils.getStorageDir()我们不知道会是哪个目录。 -
@blackapps:添加了 Utils.getStorageDir()。 Backup.java 中的 doInBackground() 发生异常。
标签: java android realm android-permissions android-external-storage