前面的那些我就不一一复述了,默认各位看官都是基础相当扎实的人,前段时间要求在本地获取到Office相关文件执行上传操作,但是采用mime_type的形式执行数据库查找的时候却一直在小米手机上搜索不到docx、pptx、xlsx这类文件,纵使添加了所有的mime_type也不起作用,这个时候就需要兵行险着,来点邪的了
/**
* 文档选择的bean对象
*/
public class ChooseDocumentBean {
private String displayName; // 展示的名称
private String path; // 文件路径
private String title; // 文件的标题
private String dateAdded; // 文件的添加日期(从1970年开始,取出来的单位是秒)
private String dateModified; // 文件的修改日期(从1970年开始,取出来的单位是秒)
private String size; // 文件的存储容量
private DocumentType fileType; // 文件的类型
private int position; // 本文件在列表中的位置
/**
* 下面是这一堆私有成员变量的get和set方法,这里就不写了
*/
}
首先是单个的文档Bean对象,这里需要获取到文件的类型,最终都会在分线程中一一设置上去
/**
* 文件类型的标识类
* 注意,后缀名的添加与最终搜索结果有直接的对应关系
*/
public enum DocumentType {
// 文本文件
txt("txt"),
// pdf文件
pdf("pdf"),
// doc文件
doc("doc", "dot", "docx", "dotx", "docm", "dotm"),
// ppt文件
ppt("ppt", "pot", "pps", "ppa", "pptx", "ppsx", "potx", "ppam", "pptm", "potm", "ppsm"),
// excel文件
xls("xls", "xlt", "xla", "xlsx", "xltx", "xlsm", "xltm", "xlam", "xlsb");
private String[] suffixArray; // 文件后缀名
DocumentType(String... suffix) {
this.suffixArray = suffix;
}
public String[] getSuffix() {
return suffixArray;
}
// 根据后缀名获取到对应的文件类型
public static DocumentType getBySuffix(String suffix) {
if (OffcnDataUtil.isEmpty(suffix)) return null;
DocumentType fileType = null;
// 统一采用小写字母执行操作
switch (suffix.toLowerCase()) {
case "txt":
fileType = txt;
break;
case "pdf":
fileType = pdf;
break;
case "doc":
case "dot":
case "docx":
case "dotx":
case "docm":
case "dotm":
fileType = doc;
break;
case "ppt":
case "pot":
case "pps":
case "ppa":
case "pptx":
case "ppsx":
case "potx":
case "ppam":
case "pptm":
case "potm":
case "ppsm":
fileType = ppt;
break;
case "xls":
case "xlt":
case "xla":
case "xlsx":
case "xltx":
case "xlsm":
case "xltm":
case "xlam":
case "xlsb":
fileType = xls;
break;
}
return fileType;
}
}
根据后缀名匹配到文档的类型,用于不同种类的文档获取,当然也可能有一些是多余的
/**
* 执行按照文档类型和关键字执行查找文档的方法
* @param context 上下文对象
* @param loadingCallBack 展示和隐藏loading的回调
* @param fileTypeList 文档类型
* @param keyword 文档名称关键字
* @param resultCallBack 查询完毕的回调
*/
public static void searchDocumentListByType(Context context, BaseLoadingCallBack loadingCallBack, List<DocumentType> fileTypeList, String keyword, AsyncTaskCallBack<List<ChooseDocumentBean>> resultCallBack) {
if (context == null || fileTypeList == null || fileTypeList.size() == 0) {
if (resultCallBack != null) {
resultCallBack.onFailed("文档查询失败");
}
return;
}
if (loadingCallBack != null) {
loadingCallBack.showLoading("文档查询中...", false);
}
Observable.create(new Observable.OnSubscribe<List<ChooseDocumentBean>>() {
@Override
public void call(Subscriber<? super List<ChooseDocumentBean>> subscriber) {
List<ChooseDocumentBean> fileList = null;
ContentResolver resolver = context.getContentResolver();
Uri uri = MediaStore.Files.getContentUri("external");
// 开始构建查询条件
StringBuilder selectionBuilder = new StringBuilder("");
// 判定搜索关键字为空
boolean keyWordsEmpty = OffcnDataUtil.isEmpty(keyword);
if (!keyWordsEmpty) {
selectionBuilder.append(MediaStore.Files.FileColumns.TITLE).append(" like '%").append(keyword).append("%'");
selectionBuilder.append(" and ( ");
}
// 追加文档类型的判定
DocumentType fileType = null;
for (int i = 0; i < fileTypeList.size(); i++) {
fileType = fileTypeList.get(i);
// 根据后缀名执行匹配操作
String[] suffix = fileType.getSuffix();
for (int j = 0; j < suffix.length; j++) {
// 除了第一种文档的第一个子类型,其余的都要加上“或”这个词
if (i != 0 || j != 0) {
selectionBuilder.append(" or ");
}
selectionBuilder.append(MediaStore.Files.FileColumns.DATA).append(" like '%.").append(suffix[j]).append("'");
}
// 如果关键字不为空,那么最后一个文档类型添加完毕之后,要加上小括号
if (!keyWordsEmpty && (i == fileTypeList.size() - 1)) {
selectionBuilder.append(" ) ");
}
}
Cursor cursor = resolver.query(uri, new String[]{MediaStore.Files.FileColumns.DATA, MediaStore.Files.FileColumns.TITLE, MediaStore.Files.FileColumns.DATE_ADDED, MediaStore.Files.FileColumns.DATE_MODIFIED, MediaStore.Files.FileColumns.SIZE}, selectionBuilder.toString(), null, MediaStore.Files.FileColumns.DATE_MODIFIED + " desc");
if (cursor != null) {
fileList = new ArrayList<>(cursor.getCount());
while (cursor.moveToNext()) {
ChooseDocumentBean bean = new ChooseDocumentBean();
String path = cursor.getString(cursor.getColumnIndex(MediaStore.Files.FileColumns.DATA));
bean.setPath(path);
bean.setDisplayName(path.substring(path.lastIndexOf("/") + 1)); // cursor.getString(cursor.getColumnIndex(MediaStore.Files.FileColumns.DISPLAY_NAME))
bean.setTitle(cursor.getString(cursor.getColumnIndex(MediaStore.Files.FileColumns.TITLE)));
bean.setDateAdded(OffcnDateUtil.change2Md(cursor.getLong(cursor.getColumnIndex(MediaStore.Files.FileColumns.DATE_ADDED))));
bean.setDateModified(OffcnDateUtil.change2Md(cursor.getLong(cursor.getColumnIndex(MediaStore.Files.FileColumns.DATE_MODIFIED))));
bean.setSize(CacheCleanUtil.getFormatSize(cursor.getLong(cursor.getColumnIndex(MediaStore.Files.FileColumns.SIZE))));
bean.setPosition(fileList.size());
String fileName = bean.getDisplayName();
if (!OffcnDataUtil.isEmpty(fileName)) {
bean.setFileType(DocumentType.getBySuffix(fileName.substring(fileName.lastIndexOf(".") + 1)));
}
fileList.add(bean);
}
cursor.close();
}
subscriber.onNext(fileList);
subscriber.onCompleted();
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<List<ChooseDocumentBean>>() {
@Override
public void onCompleted() {
if (loadingCallBack != null) {
loadingCallBack.hidLoading();
}
}
@Override
public void onError(Throwable e) {
e.printStackTrace();
if (resultCallBack != null) resultCallBack.onFailed(e.getMessage());
}
@Override
public void onNext(List<ChooseDocumentBean> result) {
if (resultCallBack != null) {
resultCallBack.onSuccess(result);
}
}
});
}
查找文件这里采用的是Rxjava1.0的异步执行方案,搜索过程中采用的是文件的后缀名的匹配形式,放弃了mime_type的匹配操作,这样查找执行的操作会更慢一些(建议用loading阻断一下),但是结果更加准确,规避掉了部分机型上mime_type匹配隐藏的失败问题