Android问题解决–“StorageManager.getVolumeList NullPointerException”空指针再现,getExternalDirs[通俗易懂]

Android问题解决–“StorageManager.getVolumeList NullPointerException”空指针再现,getExternalDirs[通俗易懂]问题:在获取外部存储目录时,在某些低版本Android手机上发生StorageManager.getVolumeList空指针错误,具体如下:Causedby:java.lang.NullPointerException:Attempttoinvokeinterfacemethod’android.os.storage.StorageVolume[]android.os.storage.IStorageManager.getVolumeList(int,java.lang.S

大家好,欢迎来到IT知识分享网。

问题:

在获取外部存储目录时,在某些低版本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的判断,在低版本和高版本进行区别对待。

 


 

 

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/24822.html

(0)

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

关注微信