且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

如何让用户点击 5 张图片并在 android 的不同图像视图中显示它

更新时间:2023-01-03 22:23:16

根据我的经验,您的问题没有简单的解决方案.使用 和 Intent 访问相机应用,您有两个与您的问题相关的选择:

It is my experience that there is no easy solution to your problem. Using and Intent to access a camera app, you have two choices related to your issue:

  1. 通过意图请求允许用户只拍摄一张照片.在这种情况下,您可以提供将存储图片的文件 URI.要使用此方法拍摄多张照片,应用程序必须多次启动 Intent.每次用户拍照时,相机应用程序都会退出并将用户返回到您的应用程序.这可能不是您想要的体验.

  1. Request, via the intent, to allow the user to take just one picture. In this case, you can provide the file URI where the picture will be stored. To take multiple pictures using this method, the app will have to start the intent multiple times. Each time the user takes a picture, the camera app will exit and return the user to your app. This is probably not the experience you want.

通过意图请求无限期地调用相机.在此模式下,用户可以在不退出相机的情况下拍摄多张照片.但是,您的应用无法指定图片的去向.相反,它们将去任何相机应用程序决定存储它们的地方.然后,您可以找到这些图片文件并在您的应用程序中使用它们.我将在下面提供如何实现这一点的草图.

Request, via the intent, to invoke the camera indefinitely. In this mode, the user can take multiple pictures without exiting the camera. However, your app cannot specify where the pictures go. Instead, they will go wherever the camera app decides to store them. You can then find those picture files and use them in your app. I will provide a sketch of how to implement this, below.

您可以说有第三种选择,正如 Neo 所回答的那样,然后编写自己的相机应用程序.如果你想要各种控制,比如亮度、缩放等,那肯定会做很多工作!

You could say there's a third choice, as Neo answered, and write your own camera app. That would certainly be a lot of work if you want the various controls, such as brightness, zoom, etc.!

背景:

首先,您需要了解 MediaStore.这是一个跟踪您设备上可用的所有照片(以及许多其他媒体文件和流)的 Android 提供程序.每次相机应用程序拍摄一张照片时,它都会将它的引用添加到 MediaStore.因此,对于上面的选项 2,当用户使用相机应用程序拍摄多张照片时,每张照片都会记录在 MediaStore 中.这似乎会立即发生,尽管我不知道有任何支持这一点的文档.(因此,可能有一个相机应用程序会延迟更新 MediaStore,直到拍照后的一段时间.但可能不会.)

First, you need to know about the MediaStore. This is an Android provider that keeps track of all photos (and many other media files and streams) available on your device. Each time the camera app takes a picture, it adds a reference of it to the MediaStore. So, for option 2 above, when the user takes several pictures using the camera app, each picture will be recorded in the MediaStore. This appears to happen immediately, though I don't know of any documentation that supports that. (Thus, there could be a camera app that defers updating MediaStore until some period of time after a picture is taken. Probably not, though.)

除其他外,MediaStore 记录了

Among other things, the MediaStore records the

方法

首先,记下当前时间.您将需要这个,如下所示.

First, note the current time. You will need this, as you will see below.

long invokeTime = System.currentTimeMillis ();

为 MediaStore 的更改注册一个观察者.创建 ContentObserver 的子类并使用此代码将其注册到 MediaStore.

Register an observer for changes to the MediaStore. Create a subclass of ContentObserver and use this code to register it with MediaStore.

Uri IMAGES_URI = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
getContentResolver().registerContentObserver (IMAGES_URI, true, this);

您的观察者子类需要重写 onChange() 方法:

Your observers subclass will need will need to override the onChange() methods:

@Override public void onChange (boolean selfChage)
{
  onChange (selfChage, null);
}

@Override public void onChange (boolean selfChange, Uri uri)
{
  listener.onContentChange (selfChange, uri);
}

而且,正如您在上面看到的,您将需要一个侦听器,或者某种对您的应用程序的回调,以便在 onChange() 发生时执行某些操作.

And, as you can see above, you will need a listener, or some kind of call back to your app, to do something when an onChange() occurs.

在我的监听器中,我将新图像的 URI 保存在我的 ArrayList 中.这是困难的部分.每次拍照时都会调用 onChange().对 MediaStore 的任何其他更改也会调用它,因此您仅在保存新图片时才注意.查询最近一张图片的时间和文件路径:

In my listener, I save the URIs for the new images in my ArrayList. This is the hard part. onChange() will be called each time a picture is taken. It will be called for any other change to MediaStore as well, so you pay attention only when a new picture was saved. Query the time and file path for the most recent picture:

String[] projection = { MediaStore.Images.Media.DATA, MediaStore.Images.Media.DATE_ADDED };
String selection = null;
String[] selectionArgs = null;
order = MediaStore.Images.ImageColumns.DATE_ADDED + " DESC limit 1";
Cursor cursor = context.getContentResolver().query(
        MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
        projection,
        selection,
        selectionArgs,
        order);

并获取第一行

if (cursor.moveToNext())
{
  int dateColumn = cursor.getColumnIndex (MediaStore.Images.Media.DATE_ADDED);
  int pathColumn = cursor.getColumnIndex (MediaStore.Images.Media.DATA);
  dateAddedMillis = cursor.getLong (dateColumn) * 1000;
  path = new File (cursor.getString (pathColumn));
}
cursor.close();

如果是最新的图片,如上图:

If the latest image, as fetched above:

  • 具有dateAddedMillis">invokeTime,并且
  • 尚未在 captureImageArray 中,并且
  • 其文件存在(可能是已删除文件的通知)

然后把它放在你的 ImageView 中,或者你想用它做什么.

then put it in your ImageView, or whatever you may wish to do with it.

create bitmap from image stored at "path";

最后,一切准备就绪后,调用相机:

Finally, once all this is prepared, invoke the camera:

static private int ACTIVITY_REQUEST_CAMERA = 2;
...
Intent intent = new Intent();
intent.setAction (MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA););
startActivityForResult (intent, ACTIVITY_REQUEST_CAMERA);

当用户退出摄像头时,请务必取消注册您的观察者.否则,它将继续从用户碰巧使用的任何其他应用程序中获取对 MediaStore 的更改.

When the user exits the camera, be sure to unregister your observer. Otherwise, it will continue to pick up changes to MediaStore from any other app the user happens to use.

上面的方法是为了解释这个过程的核心.此外,您需要获得 READ_EXTERNAL_STORAGE 权限.此外,如果用户有 SD 卡,您可能需要确保已安装它.可能还有其他考虑因素.

The above method is meant to explain the core of this process. In addition, you will need to get the READ_EXTERNAL_STORAGE permission. Also, if the user has an SD card, you may need to ensure that it is mounted. There are probably other considerations.

它也不是万无一失的.它工作得很好,但用户可能会调用其他创建图像的应用程序,你也会捕获"这些图像.你也可以想象其他的失败案例.

Nor is it fail safe. It works very well but the user may invoke other apps which create images and you will "capture" those, too. You can probably imagine other failure cases, too.