Android问题解决--“StorageManager.getVolumeList NullPointerException”空指针再现,getExternalDirs

问题:

在获取外部存储目录时,在某些低版本Android手机上发生StorageManager.getVolumeList 空指针错误,具体如下:

Caused by: java.lang.NullPointerException: Attempt to invoke interface method 'android.os.storage.StorageVolume[] android.os.storage.IStorageManager.getVolumeList(int, java.lang.String, int)' on a null object reference
        at android.os.storage.StorageManager.getVolumeList(StorageManager.java:1267)
        at android.os.Environment$UserEnvironment.getExternalDirs(Environment.java:109)
        at android.os.Environment.getExternalStorageState(Environment.java:1026)

 

分析:

getExternalDirs作用是获取sdcard的目录,在Android低版本(4.4以前),sdcard目录是指设备插入的真正的可插拔存储卡的目录;

在高版本(Android4.4以后),由于手机的存储空器越来越大,即使没有插入外部存储卡,系统也会默认创建sdcard,如果有卡插入,getExternalDirs就会返回多个File数组。

所以,上面的问题,应该发生在比较旧的设备上。

getExternalDirs 和getExternalDirs源码如下:

Environment.java:
     /**
     * Returns the current state of the primary shared/external storage media.
     *
     * @see #getExternalStorageDirectory()
     * @return one of {@link #MEDIA_UNKNOWN}, {@link #MEDIA_REMOVED},
     *         {@link #MEDIA_UNMOUNTED}, {@link #MEDIA_CHECKING},
     *         {@link #MEDIA_NOFS}, {@link #MEDIA_MOUNTED},
     *         {@link #MEDIA_MOUNTED_READ_ONLY}, {@link #MEDIA_SHARED},
     *         {@link #MEDIA_BAD_REMOVAL}, or {@link #MEDIA_UNMOUNTABLE}.
     */
    public static String getExternalStorageState() {
        final File externalDir = sCurrentUser.getExternalDirs()[0];
        return getExternalStorageState(externalDir);
    }

    /** {@hide} */
    public static class UserEnvironment {
        private final int mUserId;

        @UnsupportedAppUsage
        public UserEnvironment(int userId) {
            mUserId = userId;
        }

        @UnsupportedAppUsage
        public File[] getExternalDirs() {
            final StorageVolume[] volumes = StorageManager.getVolumeList(mUserId,
                    StorageManager.FLAG_FOR_WRITE);
            final File[] files = new File[volumes.length];
            for (int i = 0; i < volumes.length; i++) {
                files[i] = volumes[i].getPathFile();
            }
            return files;
        }

        @UnsupportedAppUsage
        @Deprecated
        public File getExternalStorageDirectory() {
            return getExternalDirs()[0];
        }

        @UnsupportedAppUsage
        @Deprecated
        public File getExternalStoragePublicDirectory(String type) {
            return buildExternalStoragePublicDirs(type)[0];
        }
        。。。
    }

可见,getExternalDirs被注解为@UnsupportedAppUsage, 表示该api已经不被支持App使用了。

getExternalDirs调用了StorageManager.getVolumeList, 而正是在这里发生了NullPointerException。

StorageManager.getVolumeList代码定义在StorageManager.java:



/** {@hide} */
    @UnsupportedAppUsage
    public static @NonNull StorageVolume[] getVolumeList(int userId, int flags) {
        final IStorageManager storageManager = IStorageManager.Stub.asInterface(
                ServiceManager.getService("mount"));
        try {
            String packageName = ActivityThread.currentOpPackageName();
            if (packageName == null) {
                // Package name can be null if the activity thread is running but the app
                // hasn't bound yet. In this case we fall back to the first package in the
                // current UID. This works for runtime permissions as permission state is
                // per UID and permission realted app ops are updated for all UID packages.
                String[] packageNames = ActivityThread.getPackageManager().getPackagesForUid(
                        android.os.Process.myUid());
                if (packageNames == null || packageNames.length <= 0) {
                    return new StorageVolume[0];
                }
                packageName = packageNames[0];
            }
            final int uid = ActivityThread.getPackageManager().getPackageUid(packageName,
                    PackageManager.MATCH_DEBUG_TRIAGED_MISSING, userId);
            if (uid <= 0) {
                return new StorageVolume[0];
            }
            return storageManager.getVolumeList(uid, packageName, flags); //1267行
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

再对比错误信息和代码行数:

错误信息:

“at android.os.storage.StorageManager.getVolumeList(StorageManager.java:1267)”

代码行数截图:

storageManager.getVolumeList调用

 

问题解决:

1. 在api调用的时候,进行try catch异常的捕获,以及null的判空;

2. 进行sdk level的判断,在低版本和高版本进行区别对待。

 


 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

liranke

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值