很多人都看过在文件管理器中点击一个文件,会弹出很多可供选择的打开方式

有时候我们也想让我们自己的应用去打开/查看该文件,这应该怎么实现?要想知道答案,我们先来看看文件管理器是怎么处理这个点击事件的?具体的实现方法如下(小米的文件管理器已经开源,可以到网上下载他的源码看,我这只做简单的实现):


/** 
 * 根据文件后缀名获得对应的MIME类型。 
 * @param file 
 */  
private String getMIMEType(File file)  
{  
    String type="*/*";  
    String fName=file.getName();  
    //获取后缀名前的分隔符"."在fName中的位置。  
    int dotIndex = fName.lastIndexOf(".");  
    if(dotIndex < 0){  
        return type;  
    }  
    /* 获取文件的后缀名 */  
    String end=fName.substring(dotIndex,fName.length()).toLowerCase();  
    if(end=="")return type;  
    //在MIME和文件类型的匹配表中找到对应的MIME类型。  
    for(int i=0;i<MIME_MapTable.length;i++){  
        if(end.equals(MIME_MapTable[i][0]))  
            type = MIME_MapTable[i][1];  
    }  
    return type;  
}
/** 
 * 打开文件 
 * @param file 
 */  
private void openFile(File file){  
    //Uri uri = Uri.parse("file://"+file.getAbsolutePath());  
    Intent intent = new Intent();  
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);  
    //设置intent的Action属性  
    intent.setAction(Intent.ACTION_VIEW);  
    //获取文件file的MIME类型  
    String type = getMIMEType(file);  
    //设置intent的data和Type属性。  
    intent.setDataAndType(/*uri*/Uri.fromFile(file), type);  
    //跳转  
    startActivity(intent);      
}

MIME类型和文件类型的匹配表(表不是很全,可自由补充):

//建立一个MIME类型与文件后缀名的匹配表  
private final String[][] MIME_MapTable={  
    //{后缀名,    MIME类型}  
    {".3gp",    "video/3gpp"},  
    {".apk",    "application/vnd.android.package-archive"},  
    {".asf",    "video/x-ms-asf"},  
    {".avi",    "video/x-msvideo"},  
    {".bin",    "application/octet-stream"},  
    {".bmp",      "image/bmp"},  
    {".c",        "text/plain"},  
    {".class",    "application/octet-stream"},  
    {".conf",    "text/plain"},  
    {".cpp",    "text/plain"},  
    {".doc",    "application/msword"},  
    {".exe",    "application/octet-stream"},  
    {".gif",    "image/gif"},  
    {".gtar",    "application/x-gtar"},  
    {".gz",        "application/x-gzip"},  
    {".h",        "text/plain"},  
    {".htm",    "text/html"},  
    {".html",    "text/html"},  
    {".jar",    "application/java-archive"},  
    {".java",    "text/plain"},  
    {".jpeg",    "image/jpeg"},  
    {".jpg",    "image/jpeg"},  
    {".js",        "application/x-javascript"},  
    {".log",    "text/plain"},  
    {".m3u",    "audio/x-mpegurl"},  
    {".m4a",    "audio/mp4a-latm"},  
    {".m4b",    "audio/mp4a-latm"},  
    {".m4p",    "audio/mp4a-latm"},  
    {".m4u",    "video/vnd.mpegurl"},  
    {".m4v",    "video/x-m4v"},      
    {".mov",    "video/quicktime"},  
    {".mp2",    "audio/x-mpeg"},  
    {".mp3",    "audio/x-mpeg"},  
    {".mp4",    "video/mp4"},  
    {".mpc",    "application/vnd.mpohun.certificate"},          
    {".mpe",    "video/mpeg"},      
    {".mpeg",    "video/mpeg"},      
    {".mpg",    "video/mpeg"},      
    {".mpg4",    "video/mp4"},      
    {".mpga",    "audio/mpeg"},  
    {".msg",    "application/vnd.ms-outlook"},  
    {".ogg",    "audio/ogg"},  
    {".pdf",    "application/pdf"},  
    {".png",    "image/png"},  
    {".pps",    "application/vnd.ms-powerpoint"},  
    {".ppt",    "application/vnd.ms-powerpoint"},  
    {".prop",    "text/plain"},  
    {".rar",    "application/x-rar-compressed"},  
    {".rc",        "text/plain"},  
    {".rmvb",    "audio/x-pn-realaudio"},  
    {".rtf",    "application/rtf"},  
    {".sh",        "text/plain"},  
    {".tar",    "application/x-tar"},      
    {".tgz",    "application/x-compressed"},   
    {".txt",    "text/plain"},  
    {".wav",    "audio/x-wav"},  
    {".wma",    "audio/x-ms-wma"},  
    {".wmv",    "audio/x-ms-wmv"},  
    {".wps",    "application/vnd.ms-works"},  
    //{".xml",    "text/xml"},  
    {".xml",    "text/plain"},  
    {".z",        "application/x-compress"},  
    {".zip",    "application/zip"},  
    {"",        "*/*"}      
};

我们可以看到打开文件的那个方法openFile,他就是发送了一个隐式的intent,包含了文件的MIME类型和URI,我们都知道在Android中是通过文件的MIME类型来判断有哪些应用程序可以处理这些文件,所以我们只要在自己应用的manifest文件中对应的activity里添加一些过滤信息:

<intent-filter>
     <action android:name="android.intent.action.VIEW" />
     <category android:name="android.intent.category.DEFAULT" />
     <data android:scheme="file" />
     <data android:mimeType="*/*">
</intent-filter>

这样就把我们的程序注册为:可以打开/查看所有类型的文件,如果你要想要查看txt文件,只要将mimeType改为:text/plain就可以,现在当在文件管理器中点击txt文件,系统就会试图去执行你的程序。这里只是在文件管理器中弹出你的应用程序,当选择用你的程序打开时,这里没做处理逻辑,所以啥都看不到,你可以自己尝试着去处理。这里还要注意一点的是,在Android7.0以后,更新了一些新特性,具体的自己去官网查看7.0的新特性,其中的一点就是应用间共享文件,Android 框架强制执行了 StrictMode API 政策禁止向你的应用外公开 file:// URI。也就是说如果一项包含文件 file:// URI类型 的 Intent 离开你的应用(这里指文件管理器),应用失败,并出现 FileUriExposedException 异常,对策是在应用间共享文件发送content://URI类型的URI,并授予临时访问的权限。所以我们还要添加一些信息:

<intent-filter>
     <action android:name="android.intent.action.VIEW" />
     <category android:name="android.intent.category.DEFAULT" />
     <data android:scheme="file" />
     <data android:scheme="content" />
     <data android:mimeType="*/*">
</intent-filter>

这样就可以接收到了,具体的处理逻辑以后会更新。如果有什么错误的地方请指出,我会尽快更正。