Не удается загрузить общие настройки из файла ТОЛЬКО на Android Oreo (API 26)
РЕДАКТИРОВАТЬ
Пожалуйста, прокрутите вниз до этой темы для обновления. Я сосредоточился на проблеме, но мне все еще нужна помощь в ее решении.
Фон
В моем приложении для 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) Я явно прошу у пользователя разрешения через код для записи на внешнее хранилище, что также упоминается в манифесте
2) Если какая-то разница, то сохраненный файл настроек, который я пытаюсь загрузить, был успешно создан тем же экземпляром приложения (то есть версией Oreo), это не какой-то внешний файл.
РЕДАКТИРОВАТЬ:
Я пытался загрузить файл, минуя диалоговое окно файла - т.е. просто передавая определенный объект файла (путь и имя файла) в 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();
Итак, как мне адаптировать эту часть к этому решению?