天使漫步IT工作室天使漫步IT工作室

android - FileProvider崩溃-attempting to invoke XmlResourceParser on a null object reference

android 6.0及以后版本写SD都需要在manifest里面配置一个provider声明。

常见的manifest配置如下:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.angel.example" <!--包名 -->
    android:versionCode="118"
    android:versionName="118" >

    <uses-sdk
        android:minSdkVersion="14"
        android:targetSdkVersion="19" />


    <application
        android:name="com.angel.example.AsdApplication"
        android:allowBackup="true"
        android:allowTaskReparenting="true"
        android:theme="@style/AsdTheme" >

        <provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="com.angel.example.fileProvider" <!--格式:报名+fileprovider-->
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/filepaths" /> <!-- 声明的路径列表 -->
        </provider>

       ...
    </application>

</manifest>

对应的路径授权声明,也就是xml/filepaths(请记住这是一个xml,且可以配置多个路径):

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <external-path path="Android/data/com.angel.example/" name="files_root" />
    <external-path path="." name="external_storage_root" />

    <!-- /storage/emulated/0/Download/${applicationId}/.beta/apk-->
    <external-path name="beta_external_path" path="Download/"/>
    <!--/storage/emulated/0/Android/data/${applicationId}/files/apk/-->
    <external-path name="beta_external_files_path" path="Android/data/"/>

    <external-path name="external_image_files_path" path="DCIM/"/>
</paths>

代码使用provider示例,也就是调用provider授权的路径进行操作:

public class MediaStoreUpdate {

    public static void updateAndBroadcast(Context context, File file) {
        Log.e("msg", "file path" + file.getAbsolutePath());
        // 其次把文件插入到系统图库
        try {
            MediaStore.Images.Media.insertImage(context.getContentResolver(), file.getAbsolutePath(), file.getName(), null);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        // 最后通知图库更新
        Uri contentUri;
        //适配不同的版本
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            contentUri = FileProvider.getUriForFile(context, "com.angel.example.fileprovider", file);
        } else {
            contentUri = Uri.parse("file://" + file.getAbsolutePath());
        }
        context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, contentUri));
    }
}

最后报了异常信息,信息如下:

java.lang.NullPointerException
Attempt to invoke virtual method 'android.content.res.XmlResourceParser android.content.pm.PackageItemInfo.loadXmlMetaData(android.content.pm.PackageManager, java.lang.String)' on a null object reference
at android.support.v4.content.FileProvider.parsePathStrategy(FileProvider.java:560)
at android.support.v4.content.FileProvider.getPathStrategy(FileProvider.java:534)
at android.support.v4.content.FileProvider.getUriForFile(FileProvider.java:376)

通过代码跟中发现,在取出了一个未赋值的provider,然后试图用这个未赋值的provider去loader路径(也就是上面配的xml)报空指针。报错代码:

ProviderInfo info = context.getPackageManager().resolveContentProvider(authority, 128);
        XmlResourceParser in = info.loadXmlMetaData(context.getPackageManager(), "android.support.FILE_PROVIDER_PATHS");//报空指针

代码分析:

  • 1.根据authorities取出的provider为空,那么就是不存在provider,但是列表里面已经配置。
  • 2.因为authorities在manifest已经配置了,但是一个是字符串,在代码中也是利用字符串,把两个值拿出来对发现:
1. contentUri = FileProvider.getUriForFile(context, "com.angel.example.fileprovider", file);
2. android:authorities="com.angel.example.fileProvider" <!--格式:报名+fileprovider-->

代码中的fileprovider是小写,而manifest中的fileProvider为大写,终于找出问题。
把其中一个改(这里全部改为小写)以后再运行,发现代码成功。

总结:authorities的配置和代码中的配置为一个字符串,名字必须一致且符合(包名+名字)的规则。

本站原创,欢迎转载,转载敬请标明出处:天使漫步IT工作室 » android - FileProvider崩溃-attempting to invoke XmlResourceParser on a null object reference
添加新评论