从文件加载共享首选项仅在Android Oreo(API 26)上失败

时间:2018-09-03 04:17:33

标签: java android sharedpreferences android-8.0-oreo android-fileprovider

编辑

请滚动到该线程的底部,以进行更新。我已经解决了这个问题,但是仍然需要帮助来解决。



背景
在我的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 not working on 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
}


但我不确定如何进行。

  • 我在AndroidManifest.xml中添加了FileProvider标记
  • 我创建了provider_paths.xml

但是要更换

  Uri uri = Uri.fromFile(fileImagePath);

使用

  Uri uri = FileProvider.getUriForFile(MainActivity.this, 
  BuildConfig.APPLICATION_ID + ".provider",fileImagePath);


我迷路了,因为在我自己的代码中我使用过Uri selectedfile = data.getData();,那么如何使这一部分适应该解决方案?

0 个答案:

没有答案