項(xiàng)目中有下載文件的功能,但是有點(diǎn) low,就是單純的下載,下載成功提示用戶文件下載在哪,需要用戶手動(dòng)去文件管理器找這些文件,不是很人性化,于是決定新增下載文件以后讓用戶直接能打開(kāi)文件,友好型會(huì)好很多
前言
首先在實(shí)現(xiàn)打開(kāi)指定文件之前,我嘗試過(guò)打開(kāi)指定的文件夾,但是并沒(méi)有成功,研究了大半天的時(shí)間,發(fā)現(xiàn)是不可行的,這是個(gè)坑,希望不要有人再踩這個(gè)坑了,(當(dāng)然,也有可能是我沒(méi)找到打開(kāi)文件夾的方法,如果有人知道,希望能夠賜教下,先謝謝了)
文末會(huì)給出封裝好的代碼,OpenFileUtils 和 FileProviderUtils 類,可以直接使用。
判斷文件類型
我們?cè)诖蜷_(kāi)文件之前,首先得知道文件的類型,才能指定 Intent 的 Data ,才能實(shí)現(xiàn)打開(kāi)文件的功能。
常見(jiàn)的文件類型以及對(duì)應(yīng)的 DataType 如下:
/**
* 聲明各種類型文件的dataType
**/
private static final String DATA_TYPE_APK = "application/vnd.android.package-archive";
private static final String DATA_TYPE_VIDEO = "video/*";
private static final String DATA_TYPE_AUDIO = "audio/*";
private static final String DATA_TYPE_HTML = "text/html";
private static final String DATA_TYPE_IMAGE = "image/*";
private static final String DATA_TYPE_PPT = "application/vnd.ms-powerpoint";
private static final String DATA_TYPE_EXCEL = "application/vnd.ms-excel";
private static final String DATA_TYPE_WORD = "application/msword";
private static final String DATA_TYPE_CHM = "application/x-chm";
private static final String DATA_TYPE_TXT = "text/plain";
private static final String DATA_TYPE_PDF = "application/pdf";
/**
* 未指定明確的文件類型,不能使用精確類型的工具打開(kāi),需要用戶選擇
*/
private static final String DATA_TYPE_ALL = "*/*";
然后我們得根據(jù)要打開(kāi)的文件名,獲取文件的類型:
// 取得文件擴(kuò)展名
String end = file.getName().substring(file.getName().lastIndexOf(".") + 1, file.getName().length()).toLowerCase();
// 依擴(kuò)展名的類型決定MimeType
switch (end) {
case "3gp":
case "mp4":
openVideoFileIntent(mContext, file);
break;
case "m4a":
case "mp3":
case "mid":
case "xmf":
case "ogg":
case "wav":
openAudioFileIntent(mContext, file);
break;
case "doc":
case "docx":
commonOpenFileWithType(mContext, file, DATA_TYPE_WORD);
break;
case "xls":
case "xlsx":
commonOpenFileWithType(mContext, file, DATA_TYPE_EXCEL);
break;
case "jpg":
case "gif":
case "png":
case "jpeg":
case "bmp":
commonOpenFileWithType(mContext, file, DATA_TYPE_IMAGE);
break;
case "txt":
commonOpenFileWithType(mContext, file, DATA_TYPE_TXT);
break;
case "htm":
case "html":
commonOpenFileWithType(mContext, file, DATA_TYPE_HTML);
break;
case "apk":
commonOpenFileWithType(mContext, file, DATA_TYPE_APK);
break;
case "ppt":
commonOpenFileWithType(mContext, file, DATA_TYPE_PPT);
break;
case "pdf":
commonOpenFileWithType(mContext, file, DATA_TYPE_PDF);
break;
case "chm":
commonOpenFileWithType(mContext, file, DATA_TYPE_CHM);
break;
default:
commonOpenFileWithType(mContext, file, DATA_TYPE_ALL);
break;
}
根據(jù)文件名拿到 DataType 之后,我們就可以把 DataType 傳入 Intent 來(lái)打開(kāi)文件了。下面以打開(kāi) Video 為例:
/**
* Android打開(kāi)Video文件
* @param mContext
* @param file
*/
public static void openVideoFileIntent(Context mContext, File file) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.putExtra("oneshot", 0);
intent.putExtra("configchange", 0);
FileProviderUtils.setIntentDataAndType(mContext, intent, DATA_TYPE_VIDEO, file, false);
mContext.startActivity(intent);
}
只要傳入 Context 和 File 就可以使用了。
相關(guān)代碼
上面的代碼是不完整的,下面我貼出有關(guān)的類的代碼:
首先是:OpenFileUtils 類
/**
* @author SmartSean
* @date 17/12/11 16:04
*/
public class OpenFileUtils {
/**
* 聲明各種類型文件的dataType
**/
private static final String DATA_TYPE_APK = "application/vnd.android.package-archive";
private static final String DATA_TYPE_VIDEO = "video/*";
private static final String DATA_TYPE_AUDIO = "audio/*";
private static final String DATA_TYPE_HTML = "text/html";
private static final String DATA_TYPE_IMAGE = "image/*";
private static final String DATA_TYPE_PPT = "application/vnd.ms-powerpoint";
private static final String DATA_TYPE_EXCEL = "application/vnd.ms-excel";
private static final String DATA_TYPE_WORD = "application/msword";
private static final String DATA_TYPE_CHM = "application/x-chm";
private static final String DATA_TYPE_TXT = "text/plain";
private static final String DATA_TYPE_PDF = "application/pdf";
/**
* 未指定明確的文件類型,不能使用精確類型的工具打開(kāi),需要用戶選擇
*/
private static final String DATA_TYPE_ALL = "*/*";
/**
* 打開(kāi)文件
* @param mContext
* @param file
*/
public static void openFile(Context mContext, File file) {
if (!file.exists()) {
return;
}
// 取得文件擴(kuò)展名
String end = file.getName().substring(file.getName().lastIndexOf(".") + 1, file.getName().length()).toLowerCase();
// 依擴(kuò)展名的類型決定MimeType
switch (end) {
case "3gp":
case "mp4":
openVideoFileIntent(mContext, file);
break;
case "m4a":
case "mp3":
case "mid":
case "xmf":
case "ogg":
case "wav":
openAudioFileIntent(mContext, file);
break;
case "doc":
case "docx":
commonOpenFileWithType(mContext, file, DATA_TYPE_WORD);
break;
case "xls":
case "xlsx":
commonOpenFileWithType(mContext, file, DATA_TYPE_EXCEL);
break;
case "jpg":
case "gif":
case "png":
case "jpeg":
case "bmp":
commonOpenFileWithType(mContext, file, DATA_TYPE_IMAGE);
break;
case "txt":
commonOpenFileWithType(mContext, file, DATA_TYPE_TXT);
break;
case "htm":
case "html":
commonOpenFileWithType(mContext, file, DATA_TYPE_HTML);
break;
case "apk":
commonOpenFileWithType(mContext, file, DATA_TYPE_APK);
break;
case "ppt":
commonOpenFileWithType(mContext, file, DATA_TYPE_PPT);
break;
case "pdf":
commonOpenFileWithType(mContext, file, DATA_TYPE_PDF);
break;
case "chm":
commonOpenFileWithType(mContext, file, DATA_TYPE_CHM);
break;
default:
commonOpenFileWithType(mContext, file, DATA_TYPE_ALL);
break;
}
}
/**
* Android傳入type打開(kāi)文件
* @param mContext
* @param file
* @param type
*/
public static void commonOpenFileWithType(Context mContext, File file, String type) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addCategory(Intent.CATEGORY_DEFAULT);
FileProviderUtils.setIntentDataAndType(mContext, intent, type, file, true);
mContext.startActivity(intent);
}
/**
* Android打開(kāi)Video文件
* @param mContext
* @param file
*/
public static void openVideoFileIntent(Context mContext, File file) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.putExtra("oneshot", 0);
intent.putExtra("configchange", 0);
FileProviderUtils.setIntentDataAndType(mContext, intent, DATA_TYPE_VIDEO, file, false);
mContext.startActivity(intent);
}
/**
* Android打開(kāi)Audio文件
* @param mContext
* @param file
*/
private static void openAudioFileIntent(Context mContext, File file) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.putExtra("oneshot", 0);
intent.putExtra("configchange", 0);
FileProviderUtils.setIntentDataAndType(mContext, intent, DATA_TYPE_AUDIO, file, false);
mContext.startActivity(intent);
}
}
接下來(lái)是洪洋大神寫(xiě)的 Android 7.0 適配類 FileProviderUtils(使用前先需要先了解下 FileProvider 的使用)
/**
* @author SmartSean
* @date 17/12/11 14:23
*/
public class FileProviderUtils {
public static Uri getUriForFile(Context mContext, File file) {
Uri fileUri = null;
if (Build.VERSION.SDK_INT >= 24) {
fileUri = getUriForFile24(mContext, file);
} else {
fileUri = Uri.fromFile(file);
}
return fileUri;
}
public static Uri getUriForFile24(Context mContext, File file) {
Uri fileUri = android.support.v4.content.FileProvider.getUriForFile(mContext,
BuildConfig.APPLICATION_ID + ".provider",
file);
return fileUri;
}
public static void setIntentDataAndType(Context mContext,
Intent intent,
String type,
File file,
boolean writeAble) {
if (Build.VERSION.SDK_INT >= 24) {
intent.setDataAndType(getUriForFile(mContext, file), type);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
if (writeAble) {
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
}
} else {
intent.setDataAndType(Uri.fromFile(file), type);
}
}
}
調(diào)用
File file = new File(Environment.getExternalStorageDirectory()+"/AA/q.xlsx");
try {
OpenFileUtils.openFile(mContext, file);
} catch (Exception e) {
ToastUtil.toastError(mContext, "無(wú)可用打開(kāi)方式");
e.printStackTrace();
}
這樣就可以實(shí)現(xiàn)打開(kāi)文件功能了。
最后
最后,嘮叨下,好久沒(méi)寫(xiě)博客,感覺(jué)都不知道怎么寫(xiě)了,慢慢找感覺(jué)吧。。。