EDIT
Пожалуйста, прокрутите вниз до этой темы для обновления. Я сосредоточился на проблеме, но мне все еще нужна помощь в ее решении.
Фон
В моем приложении для Android я использую следующий код для запуска диалогового окна файла и загрузки ранее сохраненного набора общих настроек:
public void load (){
Intent intent = new Intent()
.setType("*/*")
.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent, "Select a file"), 123);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode==123 && resultCode==RESULT_OK) {
Uri selectedfile = data.getData(); //The uri with the location of the file
File file = new File(selectedfile.getPath());
loadSharedPreferencesFromFile(file);
}
}
@SuppressWarnings({ "unchecked" })
private boolean loadSharedPreferencesFromFile(File src) {
SharedPreferences shared = getActivity().getSharedPreferences("mypref", getActivity().MODE_PRIVATE);
SharedPreferences.Editor editor = shared.edit();
//
boolean res = false;
ObjectInputStream input = null;
try {
input = new ObjectInputStream(new FileInputStream(src));
editor.clear();
Map<String, ?> entries = (Map<String, ?>) input.readObject();
for (Map.Entry<String, ?> entry : entries.entrySet()) {
Object v = entry.getValue();
String key = entry.getKey();
if (v instanceof Boolean)
editor.putBoolean(key, ((Boolean) v).booleanValue());
else if (v instanceof Float)
editor.putFloat(key, ((Float) v).floatValue());
else if (v instanceof Integer)
editor.putInt(key, ((Integer) v).intValue());
else if (v instanceof Long)
editor.putLong(key, ((Long) v).longValue());
else if (v instanceof String)
editor.putString(key, ((String) v));
}
editor.commit();
res = true;
Toast toast = Toast.makeText(getActivity().getApplicationContext(), "Load successful", Toast.LENGTH_LONG);
toast.show();
restartActivity();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}finally {
try {
if (input != null) {
input.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
return res;
}
Код работает так, как задумано в старых API (я пробовал его с Kitkat и Lollipop): открывается диалоговое окно файла, файл выбирается пользователем, и (если это файл общих настроек), настройки успешно загружается в приложение.
Проблема
Приведенный выше код не работает с Oreo (API 26)!
Диалоговое окно файла успешно запускается, но как только я выбираю ранее сохраненный файл общих настроек, диалоговое окно исчезает без загрузки настроек в приложение. Очевидно, что-то ломается по пути (возможно, в loadSharedPreferencesFromFile
?), Но я не могу понять, что.
Мой вопрос
Что-то изменилось в Oreo, о котором я должен знать, в отношении кода, который я использую - например, общие настройки, ObjectInputStream
или что-то в этом роде? Я взглянул на официальную документацию для Oreo и не увидел ничего уместного.
Две ноты:
1) Я do явно запрашиваю у пользователя разрешение через код для записи на внешнее хранилище, что также упоминается в манифесте
2) Если какая-то разница, то сохраненный файл настроек, который я пытаюсь загрузить, был , успешно создан тем же экземпляром приложения (то есть версией Oreo), это не какой-то внешний файл, сохраненный извне.
EDIT:
Я попытался загрузить файл, минуя диалоговое окно файла - т.е. просто передавая определенный файловый объект (путь и имя файла) в loadSharedPreferencesFromFile
- и это работает . Это означает, что проблема заключается в диалоге файла. Есть идеи?
РЕДАКТИРОВАТЬ 2
Из того, что я понимаю, похоже, проблема с линиями
Uri selectedfile = data.getData(); //The uri with the location of the file
File file = new File(selectedfile.getPath());
loadSharedPreferencesFromFile(file);
как Орео (или на самом деле Зефир и выше), похоже, не нравится Uri
. Я искал решения, включая этот ответ, реализующий FileProvider
:
Intent.ACTION_SEND не работает на Oreo
Я не смог понять, как изменить свой код. Я знаю, что мне нужно реализовать if-statement
следующим образом:
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
Uri selectedfile = data.getData(); //The uri with the location of the file
}
else {
// code for higher versions
}
Но я не уверен, что делать дальше.
- Я добавил тег FileProvider в AndroidManifest.xml
- Я создал provider_paths.xml
Но когда дело доходит до замены
Uri uri = Uri.fromFile(fileImagePath);
с
Uri uri = FileProvider.getUriForFile(MainActivity.this,
BuildConfig.APPLICATION_ID + ".provider",fileImagePath);
Я заблудился, потому что в своем собственном коде я использовал Uri selectedfile = data.getData();
, как мне адаптировать эту часть к этому решению?