在 Android 的默认图库图像查看器中使用 URI 打开图像

Posted

技术标签:

【中文标题】在 Android 的默认图库图像查看器中使用 URI 打开图像【英文标题】:Open an image using URI in Android's default gallery image viewer 【发布时间】:2011-07-20 00:29:33 【问题描述】:

我已经提取了图像 uri,现在我想用 android 的默认图像查看器打开图像。或者更好的是,用户可以选择使用什么程序来打开图像。如果您尝试打开文件,文件资源管理器之类的工具会为您提供。

【问题讨论】:

【参考方案1】:

接受的答案对我不起作用,

什么有效:

Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse("file://" + "/sdcard/test.jpg"), "image/*");
startActivity(intent);

【讨论】:

是的,但是你如何避免在 android 2.2 和 2.3 上等待 10 秒黑屏,而画廊说它正在搜索新照片和专辑? @max4ever : 找到解决问题的方法了吗? 是的,File f = new File(..., ...); if (f.isFile()) MediaScannerConnection.scanFile(SchedaActivity.this, new String[] f.toString() , null, new MediaScannerConnection.OnScanCompletedListener() @Override public void onScanCompleted(String path, Uri uri) Intent intent = new Intent(Intent.ACTION_VIEW); intent.setDataAndType(uri, "image/*"); SchedaActivity.this.startActivityForResult(intent, SchedaActivity.this.ACTIVITY_CODE); ); 如果您只指定“image/*”,Android 4.1 将向您显示图像。这不适用于 Android 2.3。您必须指定 mime 类型:“image/jpeg”。 这个答案以file:///sdcard... 结尾——这是故意的吗?【参考方案2】:

如果您的应用面向 Android N (7.0) 及更高版本,则不应使用上述答案(“Uri.fromFile”方法),因为它不适合您。

相反,您应该使用 ContentProvider。

例如,如果您的图像文件在外部文件夹中,您可以使用这个(类似于我制作的代码here):

File file = ...;
final Intent intent = new Intent(Intent.ACTION_VIEW)//
                                    .setDataAndType(VERSION.SDK_INT >= VERSION_CODES.N ?
                                                    FileProvider.getUriForFile(this,getPackageName() + ".provider", file) : Uri.fromFile(file),
                            "image/*").addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

清单:

<provider
    android:name="androidx.core.content.FileProvider"
    android:authorities="$applicationId.provider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/provider_paths"/>
</provider>

res/xml/provider_paths.xml:

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <!--<external-path name="external_files" path="."/>-->
    <external-path
        name="files_root"
        path="Android/data/$applicationId"/>
    <external-path
        name="external_storage_root"
        path="."/>
</paths>

如果您的图片在应用的私有路径中,您应该创建自己的 ContentProvider,因为我在链接上创建了“OpenFileProvider”。

【讨论】:

是的,只有这样才能解决我在 Android N 和 Oreo 上的问题。非常感谢。你完全正确! 非常感谢!!仅此解决方案适用于 android 较新版本 它是否也适用于保存在共享空间(SD卡)中的文件? @Albert221 应该,但我认为我没有测试过。请尝试告诉我。 不适用于 Android 10,以防我将 Uri 保存到图库中的图像【参考方案3】:

问自己,也回答自己:

startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("content://media/external/images/media/16"))); /** replace with your own uri */

它还会询问使用什么程序来查看文件。

【讨论】:

嗨,hari,您的代码对于打开图像很有用。你能有一个打开画廊文件夹的解决方案吗?这是我的问题***.com/questions/6519024/… @djk 我只是在这里回答这个问题***.com/questions/6074270/… 看看它是否与你的问题有关。 以防其他人遇到与我相同的问题 - 我添加了 intent.setType("image/png") (我知道图像将是 png 文件)并且它阻止了画廊从打开图像!所以 .setType 在这里适得其反:) 另外,您可以使用intent.setDataAndType(uri, "image/*");强制Android使用图像查看应用程序。 这个方法可以用来避免创建一个新的布局只是为了查看图像吗?【参考方案4】:

尝试使用它:

Uri uri =  Uri.fromFile(entry);
Intent intent = new Intent(android.content.Intent.ACTION_VIEW);
String mime = "*/*";
MimeTypeMap mimeTypeMap = MimeTypeMap.getSingleton();
if (mimeTypeMap.hasExtension(
    mimeTypeMap.getFileExtensionFromUrl(uri.toString())))
    mime = mimeTypeMap.getMimeTypeFromExtension(
        mimeTypeMap.getFileExtensionFromUrl(uri.toString()));
intent.setDataAndType(uri,mime);
startActivity(intent);

【讨论】:

这太完美了!它打开基于android os的弹出/布局,以便用户可以根据用户选择选择播放器或查看器。例如,显示图像、音乐、视频、应用程序甚至任何文件。 我得到了“通过 Intent.getData() 暴露在应用程序之外”错误。 如果您遇到“通过 Intent.getData() 暴露在应用程序之外”错误,您可以查看此链接以解决问题***.com/a/45751453/10619147【参考方案5】:

基于Vikas answer,但稍作修改:Uri由参数接收:

private void showPhoto(Uri photoUri)
    Intent intent = new Intent();
    intent.setAction(Intent.ACTION_VIEW);
    intent.setDataAndType(photoUri, "image/*");
    startActivity(intent);

【讨论】:

这仅显示单个选定的图像,而不显示同一文件夹中的其他图像(以便用户可以向左/向右滑动以查看其他图像)。知道如何实现这一目标吗? @Atul 在这种情况下,用例完全不同。 OP 希望使用其 URI 显示 X 图像。您似乎想要 a) 在确定的位置打开图库或 b) 在图库中打开您拥有 URI 的照片子集。在网络上进行一些研究或提出新问题,因为您的用例完全不同。 感谢您的快速回复。我需要达到 OP 的要求。您(和 Vikas 的)的答案很好地实现了它,唯一的问题是,一旦它显示图像,它就不允许滚动浏览同一文件夹中的其他图像(当用户向左或向右滑动时)。我见过许多应用程序(例如 WhatsApp)在图库查看器中显示图像(就像您所做的一样),但它们也允许用户滚动浏览同一文件夹中的左右图像。 @Atul OP 想要打开 one 图像,其中包含给定 URI 的 Gallery。 WhatsApp 的实现完全不同。我不知道 Gallery 是否支持接收具有许多 URI 的 Intent。无论如何,check out this, 可能会对您有所帮助。 我已经看过你给的链接了。不管怎么说,多谢拉。但我发现有人已经posted a question 我想要什么。但是,他的回答太简短,无法理解。【参考方案6】:

如果您使用 android N 及以下版本,这可能会有所帮助

 File file=new File(Environment.getExternalStorageDirectory()+"/directoryname/"+filename);
        Uri path= FileProvider.getUriForFile(MainActivity.this,BuildConfig.APPLICATION_ID + ".provider",file);

        Intent intent=new Intent(Intent.ACTION_VIEW);
        intent.setDataAndType(path,"image/*");
        intent.setFlags(FLAG_GRANT_READ_URI_PERMISSION | FLAG_GRANT_WRITE_URI_PERMISSION); //must for reading data from directory

【讨论】:

FLAG_GRANT_READ_URI_PERMISSION 帮助使用 Intent.ACTION_VIEW 查看图像 为我工作。请记住,如果您使用的是“intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);”那么你必须添加“intent.setFlags(FLAG_GRANT_READ_URI_PERMISSION | FLAG_GRANT_WRITE_URI_PERMISSION);”之后..感谢您提供的出色解决方案。【参考方案7】:

对这个问题的更清晰、更安全的答案(你真的不应该对字符串进行硬编码):

public void openInGallery(String imageId) 
  Uri uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI.buildUpon().appendPath(imageId).build();
  Intent intent = new Intent(Intent.ACTION_VIEW, uri);
  startActivity(intent);

您所要做的就是将图像 ID 附加到 EXTERNAL_CONTENT_URI 路径的末尾。然后使用 View 操作和 Uri 启动 Intent。

图片id来自查询内容解析器。

【讨论】:

它是否允许用户滑动和滚动同一文件夹中的其他图像?【参考方案8】:

以上所有答案都没有打开图片..当我第二次尝试打开它时显示画廊没有图片。

我从各种 SO 答案中得到了解决方案..

Intent galleryIntent = new Intent(Intent.ACTION_VIEW, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
galleryIntent.setDataAndType(Uri.fromFile(mImsgeFileName), "image/*");
galleryIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(galleryIntent);

这个只对我有用..

【讨论】:

【参考方案9】:

使用Intent.ACTION_VIEW 显示文件的问题在于,如果您通过Uri 解析路径。并非在所有情况下都有效。要解决该问题,您需要使用:

Uri.fromFile(new File(filePath));

代替:

Uri.parse(filePath);

编辑

这是我的完整代码:

Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(new File(mediaFile.filePath)), mediaFile.getExtension());
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);

信息

MediaFile 是我的域类,用于将数据库中的文件包装在对象中。 MediaFile.getExtension() 返回一个 StringMimetype 作为文件扩展名。示例:"image/png"


附加代码:需要显示任何文件(扩展名)

import android.webkit.MimeTypeMap;

public String getExtension () 
    MimeTypeMap myMime = MimeTypeMap.getSingleton();
    return myMime.getMimeTypeFromExtension(MediaFile.fileExtension(filePath));


public static String fileExtension(String path) 
    if (path.indexOf("?") > -1) 
        path = path.substring(0, path.indexOf("?"));
    
    if (path.lastIndexOf(".") == -1) 
        return null;
     else 
        String ext = path.substring(path.lastIndexOf(".") + 1);
        if (ext.indexOf("%") > -1) 
            ext = ext.substring(0, ext.indexOf("%"));
        
        if (ext.indexOf("/") > -1) 
            ext = ext.substring(0, ext.indexOf("/"));
        
        return ext.toLowerCase();
    

如果您需要更多代码,请告诉我。

【讨论】:

【参考方案10】:

我用这个对我有用

Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent,
"Select Picture"), 1);

【讨论】:

【参考方案11】:

我使用文件提供程序的解决方案

    private void viewGallery(File file) 

 Uri mImageCaptureUri = FileProvider.getUriForFile(
  mContext,
  mContext.getApplicationContext()
  .getPackageName() + ".provider", file);

 Intent view = new Intent();
 view.setAction(Intent.ACTION_VIEW);
 view.setData(mImageCaptureUri);
 List < ResolveInfo > resInfoList =
  mContext.getPackageManager()
  .queryIntentActivities(view, PackageManager.MATCH_DEFAULT_ONLY);
 for (ResolveInfo resolveInfo: resInfoList) 
  String packageName = resolveInfo.activityInfo.packageName;
  mContext.grantUriPermission(packageName, mImageCaptureUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
 
 view.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
 Intent intent = new Intent();
 intent.setAction(Intent.ACTION_VIEW);
 intent.setDataAndType(mImageCaptureUri, "image/*");
 mContext.startActivity(intent);

【讨论】:

【参考方案12】:

几乎没有机会使用照片或画廊应用程序(可能存在),但您可以尝试内容查看器。

请查看类似问题的另一个答案here

【讨论】:

【参考方案13】:

我的解决方案

Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(new File(Environment.getExternalStorageDirectory().getPath()+"/your_app_folder/"+"your_picture_saved_name"+".png")), "image/*");
context.startActivity(intent);

【讨论】:

【参考方案14】:

uri 必须是内容 uri 而不是文件 uri, 您可以通过 FileProvider 获取 contentUri 为

Uri contentUri = FileProvider.getUriForFile(getContext(),"com.github.myApp",curFile);

不要忘记在 Manifest 文件中添加提供者。

<provider
        android:name="androidx.core.content.FileProvider"
        android:authorities="com.github.myApp"
        android:exported="false"
        android:grantUriPermissions="true">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/provider_paths" />
</provider>

【讨论】:

以上是关于在 Android 的默认图库图像查看器中使用 URI 打开图像的主要内容,如果未能解决你的问题,请参考以下文章

React-native-android - 如何将图像保存到Android文件系统并在手机的“图库”中查看

android 的默认图库和相机意图是不是适用于所有设备?

如何使用 jCIFS 在 Android 中使用默认查看器打开文件

Android : 将图库功能与相机捕捉相结合

Android:在捕获或从图库中挑选后裁剪图像

Android Image Picker 从图库中选择多个图像,最大限制为 5