本篇是经过系统方法来对sd卡及U盘插拔监听及数据获取,Android盒子端开发,有系统权限,固然,这个比较简单,知道具体方法,能够经过反射来实现。java
先贴上效果图:linux
先说需求,App在引导过程当中,经过外置存储设备(U盘或者sd卡)上传指定的配置文件,开始我没打算用系统方法,网上看到 libaums 这个库文件,尝试使用了一下,可是最后发现它并不能友好的支持NTFS格式U盘,能监听到,可是好像没有办法获取到路径,最后看官方也说了不支持NTFS格式,最后索性直接使用系统方法,反正有权限,真的能够随心所欲。android
要查看具体某个功能的源码,能够经过界面定位,这样能更快的找到咱们想要的代码。
经过执行下面代码,能够直接定位当前展现界面的包名和类名。git
linux:
adb shell dumpsys activity | grep "mFocusedActivity"
windows:
adb shell dumpsys activity | findstr "mFocusedActivity"
复制代码
执行结果:
github
此时能够定位到系统设置存储界面是StorageSettingsActivity
,这个时候能够去 Android OS 这个网站搜索并查看相应的源码。web
直接查看 StorageSettings
这个界面源码,这个比较简单,大体仍是能看的清楚,由于项目时间比较紧,没有仔细去研究,只贴一些关键代码,具体能实现个人需求,等完成了这个项目,再好好来琢磨。shell
private StorageManager mStorageManager;
// 建立 StorageManager
mStorageManager = context.getSystemService(StorageManager.class);
// 注册监听
mStorageManager.registerListener(mStorageListener);
复制代码
// 监听回调
private final StorageEventListener mStorageListener = new StorageEventListener() {
@Override
public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
if (isInteresting(vol)) {
refresh();
}
}
@Override
public void onDiskDestroyed(DiskInfo disk) {
refresh();
}
};
private static boolean isInteresting(VolumeInfo vol) {
switch(vol.getType()) {
// 内置存储设备
case VolumeInfo.TYPE_PRIVATE:
// 外置存储设备
case VolumeInfo.TYPE_PUBLIC:
return true;
default:
return false;
}
}
复制代码
在源码中,直接在 onCreate
方法中建立 StorageManager
而后经过 registerListener
注册存储设备的监听,在监听回调里能够直接判断存储设备的状态,其中说一下 onVolumeStateChanged
回调中的 oldState
和 newState
参数。经过查看源码,能发如今 VolumeInfo
类中设置了存储设备的一些基本状态。windows
public static final int STATE_UNMOUNTED = 0;
public static final int STATE_CHECKING = 1;
public static final int STATE_MOUNTED = 2;
public static final int STATE_MOUNTED_READ_ONLY = 3;
public static final int STATE_FORMATTING = 4;
public static final int STATE_EJECTING = 5;
public static final int STATE_UNMOUNTABLE = 6;
public static final int STATE_REMOVED = 7;
public static final int STATE_BAD_REMOVAL = 8;
复制代码
在回调中添加打印日志:
app
STATE_UNMOUNTED
——>
STATE_CHECKING
——>
STATE_MOUNTED
STATE_EJECTING
——>
STATE_UNMOUNTED
——>
STATE_BAD_REMOVAL
onDiskDestroyed
方法。
为了不 onVolumeStateChanged
的屡次回调,我本身写了个判断方法 isMounted
,咱们能够在 onVolumeStateChanged
加入 isMounted
判断方法,只有当是外置存储设备且挂载成功后才进行ui更新。ide
public boolean isMounted(VolumeInfo vol, int oldState, int newState) {
return (isInteresting(vol) && oldState != newState && newState == VolumeInfo.STATE_MOUNTED);
}
private static boolean isInteresting(VolumeInfo vol) {
switch (vol.getType()) {
// 这里咱们只关心外置存储设备,因此直接注释掉了 TYPE_PRIVATE
// case VolumeInfo.TYPE_PRIVATE:
case VolumeInfo.TYPE_PUBLIC:
return true;
default:
return false;
}
}
复制代码
在监听回调后,能够经过StorageManager
类的 getVolumes
方法,获取全部的存储设备。
public List<VolumeInfo> getStorageDeviceList() {
if (mStorageManager == null) {
throw new RuntimeException("StorageManagerUtils not init");
}
List<VolumeInfo> volumes = mStorageManager.getVolumes();
List<VolumeInfo> publicVolumes = new ArrayList<>();
publicVolumes.clear();
for (VolumeInfo info : volumes) {
int type = info.getType();
// 获取当前存储设备的路径
File path = volumeInfo.getPath();
// 一样的,只关心外置存储设备。
if (info.getType() == VolumeInfo.TYPE_PUBLIC) {
publicVolumes.add(info);
}else if(info.getType() == VolumeInfo.TYPE_PRIVATE){
// 获取内置存储设备
}
}
return publicVolumes;
}
复制代码
当拿到设备后,经过 VolumeInfo
类的 getPath
方法就能够获取到U盘具体路径
/**
* @author Evan_zch
* @date 2018/9/17 19:13
* <p>
* 存储设备管理类
*/
public class StorageManagerUtils {
private static final String TAG = "StorageManagerUtils";
private final StorageManager mStorageManager;
private static long totalBytes = 0;
private static long usedBytes = 0;
private static final class StorageManagerHolder {
private static final StorageManagerUtils INSTANCE = new StorageManagerUtils();
}
public static StorageManagerUtils getInstance() {
return StorageManagerHolder.INSTANCE;
}
private StorageManagerUtils() {
mStorageManager = DigiTvApplication.getAppContext().getSystemService(StorageManager.class);
}
public List<VolumeInfo> getStorageDeviceList() {
if (mStorageManager == null) {
throw new RuntimeException("StorageManagerUtils not init");
}
List<VolumeInfo> volumes = mStorageManager.getVolumes();
List<VolumeInfo> publicVolumes = new ArrayList<>();
publicVolumes.clear();
for (VolumeInfo info : volumes) {
int type = info.getType();
if (info.getType() == VolumeInfo.TYPE_PUBLIC) {
Logutils.d(TAG + "--refresh type is public");
String bestVolumeDescription = mStorageManager.getBestVolumeDescription(info);
File path = info.getPath();
Logutils.d(TAG + "--refresh type=" + type + ",bestVolumeDescription=" + bestVolumeDescription + ",path=" + path);
publicVolumes.add(info);
}
}
return publicVolumes;
}
public boolean isMounted(VolumeInfo vol, int oldState, int newState) {
return (isInteresting(vol) && oldState != newState && newState == VolumeInfo.STATE_MOUNTED);
}
private static boolean isInteresting(VolumeInfo vol) {
switch (vol.getType()) {
//case VolumeInfo.TYPE_PRIVATE:
case VolumeInfo.TYPE_PUBLIC:
return true;
default:
return false;
}
}
public String getTotalSize(VolumeInfo vol) {
if (vol.isMountedReadable()) {
final File path = vol.getPath();
if (totalBytes <= 0) {
totalBytes = path.getTotalSpace();
}
}
return Formatter.formatFileSize(DigiTvApplication.getAppContext(), totalBytes);
}
public String getUsedSize(VolumeInfo vol) {
if (vol.isMountedReadable()) {
final File path = vol.getPath();
final long freeBytes = path.getFreeSpace();
usedBytes = totalBytes - freeBytes;
}
return Formatter.formatFileSize(DigiTvApplication.getAppContext(), usedBytes);
}
}
复制代码