以编程方式从 Android 的内置图库应用程序中获取/选择图像
Posted
技术标签:
【中文标题】以编程方式从 Android 的内置图库应用程序中获取/选择图像【英文标题】:Get/pick an image from Android's built-in Gallery app programmatically 【发布时间】:2011-01-11 07:06:58 【问题描述】:我正在尝试从我的应用程序内部打开图库内置应用程序中的图像/图片。
我有图片的 URI(图片位于 SD 卡上)。
你有什么建议吗?
【问题讨论】:
我已更新我的答案以提供更多测试代码以确保您正确检索结果。 看看我的回答,它是对 hcpl 代码的更新,它也适用于 astro 文件管理器和 oi 文件管理器。 有人应该更新问题“从 android 的...获取/选择图像”。当前问题解释为我有图像,我想通过默认图库应用显示它。 @Vikas,看来你是对的。我不记得一年多前我到底试图完成什么,以及为什么所有答案(包括我选择作为解决方案的答案)实际上都回答了不同的问题...... 其实我也不知道完全换个问题对不对。有 36 人将该问题添加到他们的收藏夹... 【参考方案1】:这是一个完整的解决方案。我刚刚使用@mad 在下面的答案中提供的信息更新了这个示例代码。另请查看@Khobaib 提供的以下解决方案,说明如何处理 picasa 图像。
更新
我刚刚查看了我的原始答案并创建了一个简单的 Android Studio 项目,您可以从 github 签出并直接在您的系统上导入。
https://github.com/hanscappelle/SO-2169649
(请注意,多文件选择仍然需要工作)
单张图片选择
感谢用户 mad,支持来自文件浏览器的图像。
public class BrowsePictureActivity extends Activity
// this is the action code we use in our intent,
// this way we know we're looking at the response from our own action
private static final int SELECT_PICTURE = 1;
private String selectedImagePath;
public void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
findViewById(R.id.Button01)
.setOnClickListener(new OnClickListener()
public void onClick(View arg0)
// in onCreate or any event where your want the user to
// select a file
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent,
"Select Picture"), SELECT_PICTURE);
);
public void onActivityResult(int requestCode, int resultCode, Intent data)
if (resultCode == RESULT_OK)
if (requestCode == SELECT_PICTURE)
Uri selectedImageUri = data.getData();
selectedImagePath = getPath(selectedImageUri);
/**
* helper to retrieve the path of an image URI
*/
public String getPath(Uri uri)
// just some safety built in
if( uri == null )
// TODO perform some logging or show user feedback
return null;
// try to retrieve the image from the media store first
// this will only work for images selected from gallery
String[] projection = MediaStore.Images.Media.DATA ;
Cursor cursor = managedQuery(uri, projection, null, null, null);
if( cursor != null )
int column_index = cursor
.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
String path = cursor.getString(column_index);
cursor.close();
return path;
// this is our fallback here
return uri.getPath();
选择多张图片
由于有人在评论中要求提供该信息,因此最好收集信息。
在意图上设置一个额外的参数EXTRA_ALLOW_MULTIPLE
:
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
并在结果处理中检查该参数:
if (Intent.ACTION_SEND_MULTIPLE.equals(data.getAction()))
&& Intent.hasExtra(Intent.EXTRA_STREAM))
// retrieve a collection of selected images
ArrayList<Parcelable> list = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM);
// iterate over these images
if( list != null )
for (Parcelable parcel : list)
Uri uri = (Uri) parcel;
// TODO handle the images one by one here
请注意,这仅受 API 级别 18+ 支持。
【讨论】:
使用 Astro 文件管理器时它不起作用。任何想法为什么? @hcpl 谢谢你的回答。你能告诉我如何获取多张图片吗...? 获取单张图片似乎不再适用于最新的 Android 版本 4.4 (KitKat)。查询中的 _data 列返回空值。 @hcpl 你的意思不是'Intent.hasExtra',你的意思是'data.hasExtra' - 假设数据是onActivityResult()中的Intent参数。 这段代码在Kitkat之前运行良好,但从那时起就有了文档提供者。在我的回答中,我写了在 kitkat 中做什么。【参考方案2】:这是对 hcpl 发布的精细代码的更新。但这也适用于 OI 文件管理器、astro 文件管理器和媒体库(已测试)。所以我想它适用于每个文件管理器(除了提到的那些之外,还有很多其他的吗?)。对他写的代码做了一些更正。
public class BrowsePicture extends Activity
//YOU CAN EDIT THIS TO WHATEVER YOU WANT
private static final int SELECT_PICTURE = 1;
private String selectedImagePath;
//ADDED
private String filemanagerstring;
public void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
((Button) findViewById(R.id.Button01))
.setOnClickListener(new OnClickListener()
public void onClick(View arg0)
// in onCreate or any event where your want the user to
// select a file
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent,
"Select Picture"), SELECT_PICTURE);
);
//UPDATED
public void onActivityResult(int requestCode, int resultCode, Intent data)
if (resultCode == RESULT_OK)
if (requestCode == SELECT_PICTURE)
Uri selectedImageUri = data.getData();
//OI FILE Manager
filemanagerstring = selectedImageUri.getPath();
//MEDIA GALLERY
selectedImagePath = getPath(selectedImageUri);
//DEBUG PURPOSE - you can delete this if you want
if(selectedImagePath!=null)
System.out.println(selectedImagePath);
else System.out.println("selectedImagePath is null");
if(filemanagerstring!=null)
System.out.println(filemanagerstring);
else System.out.println("filemanagerstring is null");
//NOW WE HAVE OUR WANTED STRING
if(selectedImagePath!=null)
System.out.println("selectedImagePath is the right one for you!");
else
System.out.println("filemanagerstring is the right one for you!");
//UPDATED!
public String getPath(Uri uri)
String[] projection = MediaStore.Images.Media.DATA ;
Cursor cursor = managedQuery(uri, projection, null, null, null);
if(cursor!=null)
//HERE YOU WILL GET A NULLPOINTER IF CURSOR IS NULL
//THIS CAN BE, IF YOU USED OI FILE MANAGER FOR PICKING THE MEDIA
int column_index = cursor
.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
else return null;
【讨论】:
如何从 OI 路径中检索位图图像? 看代码。在带有评论的行//现在我们有我们想要的字符串......这就是你所需要的。然后使用 BitmapFactory 类从路径中检索位图 谢谢!你说得很好,从未尝试过其他文件管理器:)。 我也想关闭光标:) 还可以将getPath(Uri uri)
中的else return null;
更改为return uri.getPath();
并去掉第一个filemanagerstring = selectedImageUri.getPath();
检查。这样,您只需拨打一个电话 getPath(Uri)
并取回路径(无论使用的是图库还是文件管理器)。【参考方案3】:
hcpl 的方法在 KitKat 之前完美运行,但不适用于 DocumentsProvider API。为此,只需遵循文档提供者的官方 Android 教程:https://developer.android.com/guide/topics/providers/document-provider.html -> 打开文档,位图部分。
我只是使用了 hcpl 的代码并对其进行了扩展:如果具有检索到的图像路径的文件抛出异常,我将调用此函数:
private Bitmap getBitmapFromUri(Uri uri) throws IOException
ParcelFileDescriptor parcelFileDescriptor =
getContentResolver().openFileDescriptor(uri, "r");
FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
Bitmap image = BitmapFactory.decodeFileDescriptor(fileDescriptor);
parcelFileDescriptor.close();
return image;
在 Nexus 5 上测试。
【讨论】:
真正有用的答案,应该用于从“照片”应用中选择图像。 我在本地和服务器的文件上都试过这个,对两者都有效。【参考方案4】:根据上面的代码,我反映的代码如下,可能更合适:
public String getPath(Uri uri)
String selectedImagePath;
//1:MEDIA GALLERY --- query from MediaStore.Images.Media.DATA
String[] projection = MediaStore.Images.Media.DATA ;
Cursor cursor = managedQuery(uri, projection, null, null, null);
if(cursor != null)
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
selectedImagePath = cursor.getString(column_index);
else
selectedImagePath = null;
if(selectedImagePath == null)
//2:OI FILE Manager --- call method: uri.getPath()
selectedImagePath = uri.getPath();
return selectedImagePath;
【讨论】:
【参考方案5】:我查看了@hcpl 和@mad 的解决方案。 hcpl 的解决方案很好地支持图库中的本地图像,并且 mad 在此之上提供了更好的解决方案 - 它也有助于加载 OI/Astro/Dropbox 图像。但在我的应用中,在处理现已集成到 Android 图库中的 picasa 库时,两种解决方案都失败了。
我进行了一些搜索和分析,最终提出了一个更好、更优雅的解决方案来克服这个限制。感谢Dimitar Darazhanski 的博客,在这种情况下帮助了我,我做了一些修改以使其更容易理解。这是我的解决方案-
public class BrowsePicture extends Activity
//YOU CAN EDIT THIS TO WHATEVER YOU WANT
private static final int SELECT_PICTURE = 1;
private String selectedImagePath;
//ADDED
private String filemanagerstring;
public void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
((Button) findViewById(R.id.Button01))
.setOnClickListener(new OnClickListener()
public void onClick(View arg0)
// in onCreate or any event where your want the user to
// select a file
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent,
"Select Picture"), SELECT_PICTURE);
);
public void onActivityResult(int requestCode, int resultCode, Intent data)
if (resultCode == RESULT_OK)
if (requestCode == SELECT_PICTURE)
Uri selectedImageUri = data.getData();
Log.d("URI VAL", "selectedImageUri = " + selectedImageUri.toString());
selectedImagePath = getPath(selectedImageUri);
if(selectedImagePath!=null)
// IF LOCAL IMAGE, NO MATTER IF ITS DIRECTLY FROM GALLERY (EXCEPT PICASSA ALBUM),
// OR OI/ASTRO FILE MANAGER. EVEN DROPBOX IS SUPPORTED BY THIS BECAUSE DROPBOX DOWNLOAD THE IMAGE
// IN THIS FORM - file:///storage/emulated/0/Android/data/com.dropbox.android/...
System.out.println("local image");
else
System.out.println("picasa image!");
loadPicasaImageFromGallery(selectedImageUri);
// NEW METHOD FOR PICASA IMAGE LOAD
private void loadPicasaImageFromGallery(final Uri uri)
String[] projection = MediaColumns.DATA, MediaColumns.DISPLAY_NAME ;
Cursor cursor = getContentResolver().query(uri, projection, null, null, null);
if(cursor != null)
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(MediaColumns.DISPLAY_NAME);
if (columnIndex != -1)
new Thread(new Runnable()
// NEW THREAD BECAUSE NETWORK REQUEST WILL BE MADE THAT WILL BE A LONG PROCESS & BLOCK UI
// IF CALLED IN UI THREAD
public void run()
try
Bitmap bitmap = android.provider.MediaStore.Images.Media.getBitmap(getContentResolver(), uri);
// THIS IS THE BITMAP IMAGE WE ARE LOOKING FOR.
catch (Exception ex)
ex.printStackTrace();
).start();
cursor.close();
public String getPath(Uri uri)
String[] projection = MediaColumns.DATA;
Cursor cursor = getContentResolver().query(uri, projection, null, null, null);
if(cursor != null)
//HERE YOU WILL GET A NULLPOINTER IF CURSOR IS NULL
//THIS CAN BE, IF YOU USED OI FILE MANAGER FOR PICKING THE MEDIA
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndexOrThrow(MediaColumns.DATA);
String filePath = cursor.getString(columnIndex);
cursor.close();
return filePath;
else
return uri.getPath(); // FOR OI/ASTRO/Dropbox etc
检查一下,如果有问题,请告诉我。我已经对其进行了测试,并且在每种情况下都运行良好。
希望对大家有所帮助。
【讨论】:
【参考方案6】:假设您的 SD 卡目录中有一个 image 文件夹,仅用于图片。
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
// tells your intent to get the contents
// opens the URI for your image directory on your sdcard
intent.setType("file:///sdcard/image/*");
startActivityForResult(intent, 1);
然后,您可以决定要对活动中的内容做什么。
这是一个检索图像路径名的示例,使用您的代码对此进行测试,以确保您可以处理返回的结果。您可以根据需要更改代码以更好地满足您的需求。
protected final void onActivityResult(final int requestCode, final int
resultCode, final Intent i)
super.onActivityResult(requestCode, resultCode, i);
// this matches the request code in the above call
if (requestCode == 1)
Uri _uri = i.getData();
// this will be null if no image was selected...
if (_uri != null)
// now we get the path to the image file
cursor = getContentResolver().query(_uri, null,
null, null, null);
cursor.moveToFirst();
String imageFilePath = cursor.getString(0);
cursor.close();
我的建议是尝试让检索图像正常工作,我认为问题在于访问 sdcard 上的图像的内容。看看Displaying images on sd card。
如果您可以启动并运行它,可能通过提供正确提供程序的示例,您应该能够为您的代码找到解决方法。
通过使用您的进度更新此问题来让我了解最新情况。祝你好运
【讨论】:
@Anthony,感谢您的回复。不幸的是,它对我不起作用。我得到下一个错误:android.content.ActivityNotFoundException: No Activity found to handle Intent act=android.intent.action.GET_CONTENT typ=file:///sdcard/images/*
您需要致电startActivityforResult
并提供活动。这就是我所说的决定下一步做什么,我的错。
它仍然不起作用...我检查该文件夹是否存在并且该文件夹内是否有一个图像文件。我打电话给startActivityForResult(intent, 1);
,但仍然出现此错误...此代码位于活动之外,但我有对该活动的引用并在该引用上调用startActivityForResult
方法-也许这就是原因?
不,不应该是这个原因,你传入的1
是什么?试试IMAGE_PICK
第二个参数对我来说只是一些东西,不是吗?这只是一个 int,将与结果一起传回给我。还尝试了Intent.ACTION_PICK
而不是Intent.ACTION_GET_CONTENT
。 IMAGE_PICK
是什么意思?没有这样的常数。我也试过intent.setData(Uri.fromFile(new File("/sdcard/image/")));
。我尝试了所有可能的组合,但似乎没有任何效果......【参考方案7】:
这是我对这个主题的重新审视,在这里收集所有信息,以及其他相关的堆栈溢出问题。它从一些提供者返回图像,同时处理内存不足的情况和图像旋转。它支持图库、picasa 和文件管理器,如 drop box。用法很简单:作为输入,构造函数接收内容解析器和 uri。输出是最终的位图。
/**
* Creates resized images without exploding memory. Uses the method described in android
* documentation concerning bitmap allocation, which is to subsample the image to a smaller size,
* close to some expected size. This is required because the android standard library is unable to
* create a reduced size image from an image file using memory comparable to the final size (and
* loading a full sized multi-megapixel picture for processing may exceed application memory budget).
*/
public class UserPicture
static int MAX_WIDTH = 600;
static int MAX_HEIGHT = 800;
Uri uri;
ContentResolver resolver;
String path;
Matrix orientation;
int storedHeight;
int storedWidth;
public UserPicture(Uri uri, ContentResolver resolver)
this.uri = uri;
this.resolver = resolver;
private boolean getInformation() throws IOException
if (getInformationFromMediaDatabase())
return true;
if (getInformationFromFileSystem())
return true;
return false;
/* Support for gallery apps and remote ("picasa") images */
private boolean getInformationFromMediaDatabase()
String[] fields = Media.DATA, ImageColumns.ORIENTATION ;
Cursor cursor = resolver.query(uri, fields, null, null, null);
if (cursor == null)
return false;
cursor.moveToFirst();
path = cursor.getString(cursor.getColumnIndex(Media.DATA));
int orientation = cursor.getInt(cursor.getColumnIndex(ImageColumns.ORIENTATION));
this.orientation = new Matrix();
this.orientation.setRotate(orientation);
cursor.close();
return true;
/* Support for file managers and dropbox */
private boolean getInformationFromFileSystem() throws IOException
path = uri.getPath();
if (path == null)
return false;
ExifInterface exif = new ExifInterface(path);
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_NORMAL);
this.orientation = new Matrix();
switch(orientation)
case ExifInterface.ORIENTATION_NORMAL:
/* Identity matrix */
break;
case ExifInterface.ORIENTATION_FLIP_HORIZONTAL:
this.orientation.setScale(-1, 1);
break;
case ExifInterface.ORIENTATION_ROTATE_180:
this.orientation.setRotate(180);
break;
case ExifInterface.ORIENTATION_FLIP_VERTICAL:
this.orientation.setScale(1, -1);
break;
case ExifInterface.ORIENTATION_TRANSPOSE:
this.orientation.setRotate(90);
this.orientation.postScale(-1, 1);
break;
case ExifInterface.ORIENTATION_ROTATE_90:
this.orientation.setRotate(90);
break;
case ExifInterface.ORIENTATION_TRANSVERSE:
this.orientation.setRotate(-90);
this.orientation.postScale(-1, 1);
break;
case ExifInterface.ORIENTATION_ROTATE_270:
this.orientation.setRotate(-90);
break;
return true;
private boolean getStoredDimensions() throws IOException
InputStream input = resolver.openInputStream(uri);
Options options = new Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(resolver.openInputStream(uri), null, options);
/* The input stream could be reset instead of closed and reopened if it were possible
to reliably wrap the input stream on a buffered stream, but it's not possible because
decodeStream() places an upper read limit of 1024 bytes for a reset to be made (it calls
mark(1024) on the stream). */
input.close();
if (options.outHeight <= 0 || options.outWidth <= 0)
return false;
storedHeight = options.outHeight;
storedWidth = options.outWidth;
return true;
public Bitmap getBitmap() throws IOException
if (!getInformation())
throw new FileNotFoundException();
if (!getStoredDimensions())
throw new InvalidObjectException(null);
RectF rect = new RectF(0, 0, storedWidth, storedHeight);
orientation.mapRect(rect);
int width = (int)rect.width();
int height = (int)rect.height();
int subSample = 1;
while (width > MAX_WIDTH || height > MAX_HEIGHT)
width /= 2;
height /= 2;
subSample *= 2;
if (width == 0 || height == 0)
throw new InvalidObjectException(null);
Options options = new Options();
options.inSampleSize = subSample;
Bitmap subSampled = BitmapFactory.decodeStream(resolver.openInputStream(uri), null, options);
Bitmap picture;
if (!orientation.isIdentity())
picture = Bitmap.createBitmap(subSampled, 0, 0, options.outWidth, options.outHeight,
orientation, false);
subSampled.recycle();
else
picture = subSampled;
return picture;
参考资料:
http://developer.android.com/training/displaying-bitmaps/index.html Get/pick an image from Android's built-in Gallery app programmatically Strange out of memory issue while loading an image to a Bitmap object Set image orientation using ExifInterface https://gist.github.com/9re/1990019 how to get bitmap information and then decode bitmap from internet-inputStream?【讨论】:
【参考方案8】:这里有两个关于图像选择器的有用教程和可下载的源代码:
How to Create Android Image Picker
How to Select and Crop Image on Android
但是,应用程序有时会被强制关闭,您可以通过在 Manifest 文件的主要活动中添加 android:configChanges 属性来修复它,如下所示:
<activity android:name=".MainActivity"
android:label="@string/app_name" android:configChanges="keyboardHidden|orientation" >
似乎相机 API 失去了对方向的控制,所以这会有所帮助。 :)
【讨论】:
【参考方案9】:要显示图像和视频,试试这个:
Intent intent = new Intent();
intent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, 1);
startActivityForResult(Intent.createChooser(intent,"Wybierz plik"), SELECT_FILE);
【讨论】:
【参考方案10】:以下解决方案也适用于 2.3(Gingerbread)-4.4(Kitkat)、5.0(Lollipop) 和 6.0(Marshmallow):-
第一步打开图库选择图片的代码:
public static final int PICK_IMAGE = 1;
private void takePictureFromGalleryOrAnyOtherFolder()
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent, "Select Picture"), PICK_IMAGE);
第二步获取onActivityResult
中数据的代码:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == Activity.RESULT_OK)
if (requestCode == PICK_IMAGE)
Uri selectedImageUri = data.getData();
String imagePath = getRealPathFromURI(selectedImageUri);
//Now you have imagePath do whatever you want to do now
//end of inner if
//end of outer if
public String getRealPathFromURI(Uri contentUri)
//Uri contentUri = Uri.parse(contentURI);
String[] projection = MediaStore.Images.Media.DATA ;
Cursor cursor = null;
try
if (Build.VERSION.SDK_INT > 19)
// Will return "image:x*"
String wholeID = DocumentsContract.getDocumentId(contentUri);
// Split at colon, use second item in the array
String id = wholeID.split(":")[1];
// where id is equal to
String sel = MediaStore.Images.Media._ID + "=?";
cursor = context.getContentResolver().query(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
projection, sel, new String[] id , null);
else
cursor = context.getContentResolver().query(contentUri,
projection, null, null, null);
catch (Exception e)
e.printStackTrace();
String path = null;
try
int column_index = cursor
.getColumnIndex(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
path = cursor.getString(column_index).toString();
cursor.close();
catch (NullPointerException e)
e.printStackTrace();
return path;
【讨论】:
它对我有用 我正在使用 Nexus 5 和 Marshmallow。您使用的是哪部手机。 我也使用了 google nexus,但无法获取我的画廊选择的图像的图像名称或路径我得到了 null java.lang.SecurityException: Permission Denial: 从 pid=31332 读取 com.android.providers.media.MediaProvider uri content://media/external/images/media,uid=11859 需要 android。 permission.READ_EXTERNAL_STORAGE 或 grantUriPermission() 收到此错误 您已经添加了显示READ_EXTERNAL_STORAGE
的权限
是的,我已经在清单中添加了权限,但我没有在运行时在 java 文件中添加任何权限【参考方案11】:
以防万一;我这样做是为了获取位图:
InputStream is = context.getContentResolver().openInputStream(imageUri);
Bitmap bitmap = BitmapFactory.decodeStream(is);
【讨论】:
这是最简单的答案(也是唯一对我有用的答案)。做得很好!【参考方案12】:以上答案是正确的。我遇到了一个不同的问题,在 HTC M8 中,我的应用程序在从图库中选择图像时崩溃。我得到图像路径的空值。我使用以下解决方案进行了修复和优化。在 onActivityResult 方法中
protected void onActivityResult(int requestCode, int resultCode, Intent data)
super.onActivityResult(requestCode, resultCode, data);
if ((requestCode == RESULT_LOAD_IMAGE) && (resultCode == RESULT_OK))
if (data != null)
Uri selectedImageUri = null;
selectedImageUri = data.getData();
String[] filePathColumn = MediaStore.Images.Media.DATA ;
Cursor imageCursor = mainActivity.getContentResolver().query(
selectedImageUri, filePathColumn, null, null, null);
if (imageCursor == null)
return;
imageCursor.moveToFirst();
int columnIndex = imageCursor.getColumnIndex(filePathColumn[0]);
picturePath = imageCursor.getString(columnIndex);
if (picturePath == null)
picturePath = selectedImageUri.getPath();
String wholeID = DocumentsContract
.getDocumentId(selectedImage);
// Split at colon, use second item in the array
String id = wholeID.split(":")[1];
String[] column = MediaStore.Images.Media.DATA ;
// where id is equal to
String sel = MediaStore.Images.Media._ID + "=?";
Cursor cursor = mainActivity.getContentResolver().query(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
column, sel, new String[] id , null);
columnIndex = cursor.getColumnIndex(column[0]);
if (cursor.moveToFirst())
picturePath = cursor.getString(columnIndex);
cursor.close();
picturePathAbs = new File(picturePath).getAbsolutePath();
imageCursor.close();
【讨论】:
我遇到了类似的问题,并且 picturePath 始终为 null 。我尝试了你的解决方案但不起作用,而且 getDocumentId 需要> API 19【参考方案13】:package com.ImageConvertingDemo;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.util.Log;
import android.widget.EditText;
import android.widget.ImageView;
public class MyActivity extends Activity
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
EditText tv = (EditText)findViewById(R.id.EditText01);
ImageView iv = (ImageView)findViewById(R.id.ImageView01);
FileInputStream in;
BufferedInputStream buf;
try
in = new FileInputStream("/sdcard/smooth.png");
buf = new BufferedInputStream(in,1070);
System.out.println("1.................."+buf);
byte[] bMapArray= new byte[buf.available()];
tv.setText(bMapArray.toString());
buf.read(bMapArray);
Bitmap bMap = BitmapFactory.decodeByteArray(bMapArray, 0, bMapArray.length);
/*for (int i = 0; i < bMapArray.length; i++)
System.out.print("bytearray"+bMapArray[i]);
*/
iv.setImageBitmap(bMap);
//tv.setText(bMapArray.toString());
//tv.setText(buf.toString());
if (in != null)
in.close();
if (buf != null)
buf.close();
catch (Exception e)
Log.e("Error reading file", e.toString());
【讨论】:
您在回答之前没有理解问题。此外,您没有包含有关您尝试做什么的任何描述。此外,您的代码违反了一些完善的 Java 编程标准。【参考方案14】:public class BrowsePictureActivity extends Activity
// this is the action code we use in our intent,
// this way we know we're looking at the response from our own action
private static final int SELECT_PICTURE = 1;
private String selectedImagePath;
public void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
((Button) findViewById(R.id.Button01))
.setOnClickListener(new OnClickListener()
public void onClick(View arg0)
// in onCreate or any event where your want the user to
// select a file
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent,
"Select Picture"), SELECT_PICTURE);
);
public void onActivityResult(int requestCode, int resultCode, Intent data)
if (resultCode == RESULT_OK)
if (requestCode == SELECT_PICTURE)
Uri selectedImageUri = data.getData();
selectedImagePath = getPath(selectedImageUri);
/**
* helper to retrieve the path of an image URI
*/
public String getPath(Uri uri)
// just some safety built in
if( uri == null )
// TODO perform some logging or show user feedback
return null;
// try to retrieve the image from the media store first
// this will only work for images selected from gallery
String[] projection = MediaStore.Images.Media.DATA ;
Cursor cursor = managedQuery(uri, projection, null, null, null);
if( cursor != null )
int column_index = cursor
.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
// this is our fallback here
return uri.getPath();
【讨论】:
【参考方案15】:检索特定类型的文件
此示例将获取图像的副本。
static final int REQUEST_IMAGE_GET = 1;
public void selectImage()
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
if (intent.resolveActivity(getPackageManager()) != null)
startActivityForResult(intent, REQUEST_IMAGE_GET);
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
if (requestCode == REQUEST_IMAGE_GET && resultCode == RESULT_OK)
Bitmap thumbnail = data.getParcelable("data");
Uri fullPhotoUri = data.getData();
// Do work with photo saved at fullPhotoUri
...
打开特定类型的文件
在 4.4 或更高版本上运行时,您请求打开由其他应用管理的文件
static final int REQUEST_IMAGE_OPEN = 1;
public void selectImage()
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.setType("image/*");
intent.addCategory(Intent.CATEGORY_OPENABLE);
// Only the system receives the ACTION_OPEN_DOCUMENT, so no need to test.
startActivityForResult(intent, REQUEST_IMAGE_OPEN);
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
if (requestCode == REQUEST_IMAGE_OPEN && resultCode == RESULT_OK)
Uri fullPhotoUri = data.getData();
// Do work with full size photo saved at fullPhotoUri
...
Original source
【讨论】:
【参考方案16】:除了以前的答案,如果您在获取正确路径(如 AndroZip)时遇到问题,您可以使用:
public String getPath(Uri uri ,ContentResolver contentResolver)
String[] projection = MediaStore.MediaColumns.DATA;
Cursor cursor;
try
cursor = contentResolver.query(uri, projection, null, null, null);
catch (SecurityException e)
String path = uri.getPath();
String result = tryToGetStoragePath(path);
return result;
if(cursor != null)
//HERE YOU WILL GET A NULLPOINTER IF CURSOR IS NULL
//THIS CAN BE, IF YOU USED OI FILE MANAGER FOR PICKING THE MEDIA
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA);
String filePath = cursor.getString(columnIndex);
cursor.close();
return filePath;
else
return uri.getPath(); // FOR OI/ASTRO/Dropbox etc
private String tryToGetStoragePath(String path)
int actualPathStart = path.indexOf("//storage");
String result = path;
if(actualPathStart!= -1 && actualPathStart< path.length())
result = path.substring(actualPathStart+1 , path.length());
return result;
【讨论】:
这里需要知道图片的uri吗?如果我只想从图库中选择任意图像怎么办? 您将从图库中收到的 Intent 将为您提供网址【参考方案17】:请找到从图库中选择单个图像的答案
import android.app.Activity;
import android.net.Uri;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
public class PickImage extends Activity
Button btnOpen, btnGet, btnPick;
TextView textInfo1, textInfo2;
ImageView imageView;
private static final int RQS_OPEN_IMAGE = 1;
private static final int RQS_GET_IMAGE = 2;
private static final int RQS_PICK_IMAGE = 3;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.image_pick);
btnOpen = (Button)findViewById(R.id.open);
btnGet = (Button)findViewById(R.id.get);
btnPick = (Button)findViewById(R.id.pick);
textInfo1 = (TextView)findViewById(R.id.info1);
textInfo2 = (TextView)findViewById(R.id.info2);
imageView = (ImageView) findViewById(R.id.image);
btnOpen.setOnClickListener(btnOpenOnClickListener);
btnGet.setOnClickListener(btnGetOnClickListener);
btnPick.setOnClickListener(btnPickOnClickListener);
View.OnClickListener btnOpenOnClickListener = new View.OnClickListener()
@Override
public void onClick(View v)
Intent intent = new Intent();
intent.setAction(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("image/*");
startActivityForResult(intent, RQS_OPEN_IMAGE);
;
View.OnClickListener btnGetOnClickListener = new View.OnClickListener()
@Override
public void onClick(View v)
Intent intent = new Intent();
intent.setAction(Intent.ACTION_GET_CONTENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("image/*");
startActivityForResult(intent, RQS_OPEN_IMAGE);
;
View.OnClickListener btnPickOnClickListener = new View.OnClickListener()
@Override
public void onClick(View v)
Intent intent = new Intent(Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, RQS_PICK_IMAGE);
;
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
if (resultCode == Activity.RESULT_OK)
if (requestCode == RQS_OPEN_IMAGE ||
requestCode == RQS_GET_IMAGE ||
requestCode == RQS_PICK_IMAGE)
imageView.setImageBitmap(null);
textInfo1.setText("");
textInfo2.setText("");
Uri mediaUri = data.getData();
textInfo1.setText(mediaUri.toString());
String mediaPath = mediaUri.getPath();
textInfo2.setText(mediaPath);
//display the image
try
InputStream inputStream = getBaseContext().getContentResolver().openInputStream(mediaUri);
Bitmap bm = BitmapFactory.decodeStream(inputStream);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
byte[] byteArray = stream.toByteArray();
imageView.setImageBitmap(bm);
catch (FileNotFoundException e)
e.printStackTrace();
【讨论】:
【参考方案18】:从图库或相机中打开图像的最快方式。
原文参考:get image from gallery in android programmatically
以下方法将从图库或相机接收图像并将其显示在 ImageView 中。选定的图像将在内部存储。
xml 代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_
android:layout_
android:orientation="vertical"
tools:context="com.exampledemo.parsaniahardik.uploadgalleryimage.MainActivity">
<Button
android:layout_
android:layout_
android:id="@+id/btn"
android:layout_gravity="center_horizontal"
android:layout_marginTop="20dp"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="Capture Image and upload to server" />
<TextView
android:layout_
android:layout_
android:text="Below image is fetched from server"
android:layout_marginTop="5dp"
android:textSize="23sp"
android:gravity="center"
android:textColor="#000"/>
<ImageView
android:layout_
android:layout_
android:layout_gravity="center"
android:layout_marginTop="10dp"
android:scaleType="fitXY"
android:src="@mipmap/ic_launcher"
android:id="@+id/iv"/>
</LinearLayout>
JAVA类
import android.content.Intent;
import android.graphics.Bitmap;
import android.media.MediaScannerConnection;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;
import com.androidquery.AQuery;
import org.json.JSONException;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Calendar;
import java.util.HashMap;
public class MainActivity extends AppCompatActivity implements AsyncTaskCompleteListener
private ParseContent parseContent;
private Button btn;
private ImageView imageview;
private static final String IMAGE_DIRECTORY = "/demonuts_upload_camera";
private final int CAMERA = 1;
private AQuery aQuery;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
parseContent = new ParseContent(this);
aQuery = new AQuery(this);
btn = (Button) findViewById(R.id.btn);
imageview = (ImageView) findViewById(R.id.iv);
btn.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
Intent intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, CAMERA);
);
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data)
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == this.RESULT_CANCELED)
return;
if (requestCode == CAMERA)
Bitmap thumbnail = (Bitmap) data.getExtras().get("data");
String path = saveImage(thumbnail);
try
uploadImageToServer(path);
catch (IOException e)
e.printStackTrace();
catch (JSONException e)
e.printStackTrace();
private void uploadImageToServer(final String path) throws IOException, JSONException
if (!AndyUtils.isNetworkAvailable(MainActivity.this))
Toast.makeText(MainActivity.this, "Internet is required!", Toast.LENGTH_SHORT).show();
return;
HashMap<String, String> map = new HashMap<String, String>();
map.put("url", "https://demonuts.com/Demonuts/JsonTest/Tennis/uploadfile.php");
map.put("filename", path);
new MultiPartRequester(this, map, CAMERA, this);
AndyUtils.showSimpleProgressDialog(this);
@Override
public void onTaskCompleted(String response, int serviceCode)
AndyUtils.removeSimpleProgressDialog();
Log.d("res", response.toString());
switch (serviceCode)
case CAMERA:
if (parseContent.isSuccess(response))
String url = parseContent.getURL(response);
aQuery.id(imageview).image(url);
public String saveImage(Bitmap myBitmap)
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
myBitmap.compress(Bitmap.CompressFormat.JPEG, 90, bytes);
File wallpaperDirectory = new File(
Environment.getExternalStorageDirectory() + IMAGE_DIRECTORY);
// have the object build the directory structure, if needed.
if (!wallpaperDirectory.exists())
wallpaperDirectory.mkdirs();
try
File f = new File(wallpaperDirectory, Calendar.getInstance()
.getTimeInMillis() + ".jpg");
f.createNewFile();
FileOutputStream fo = new FileOutputStream(f);
fo.write(bytes.toByteArray());
MediaScannerConnection.scanFile(this,
new String[]f.getPath(),
new String[]"image/jpeg", null);
fo.close();
Log.d("TAG", "File Saved::--->" + f.getAbsolutePath());
return f.getAbsolutePath();
catch (IOException e1)
e1.printStackTrace();
return "";
【讨论】:
【参考方案19】:这是我的例子,可能与你的情况不完全一样。
假设你从你的 API 提供者那里得到 base64 格式,给它一个文件名和文件扩展名,把它保存到文件系统中的某个位置。
public static void shownInBuiltInGallery(final Context ctx, String strBase64Image, final String strFileName, final String strFileExtension)
new AsyncTask<String, String, File>()
@Override
protected File doInBackground(String... strBase64Image)
Bitmap bmpImage = convertBase64StringToBitmap(strBase64Image[0], Base64.NO_WRAP);
if(bmpImage == null)
cancel(true);
return null;
byte[] byImage = null;
if(strFileExtension.compareToIgnoreCase(FILE_EXTENSION_JPG) == 0)
byImage = convertToJpgByte(bmpImage); // convert bitmap to binary for latter use
else if(strFileExtension.compareToIgnoreCase(FILE_EXTENSION_PNG) == 0)
byImage = convertToPngByte(bmpImage); // convert bitmap to binary for latter use
else if(strFileExtension.compareToIgnoreCase(FILE_EXTENSION_BMP) == 0)
byImage = convertToBmpByte(bmpImage); // convert bitmap to binary for latter use
else
cancel(true);
return null;
if(byImage == null)
cancel(true);
return null;
File imageFolder = ctx.getExternalCacheDir();
if(imageFolder.exists() == false)
if(imageFolder.mkdirs() == false)
cancel(true);
return null;
File imageFile = null;
try
imageFile = File.createTempFile(strFileName, strFileExtension, imageFolder);
catch (IOException e)
e.printStackTrace();
if(imageFile == null)
cancel(true);
return null;
if (imageFile.exists() == true)
if(imageFile.delete() == false)
cancel(true);
return null;
FileOutputStream fos = null;
try
fos = new FileOutputStream(imageFile.getPath());
fos.write(byImage);
fos.flush();
fos.close();
catch (java.io.IOException e)
e.printStackTrace();
finally
fos = null;
return imageFile;
@Override
protected void onPostExecute(File file)
super.onPostExecute(file);
String strAuthority = ctx.getPackageName() + ".provider";
Uri uriImage = FileProvider.getUriForFile(ctx, strAuthority, file);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(uriImage, "image/*");
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
ctx.startActivity(intent);
.execute(strBase64Image);
不要忘记首先在 AndroidManifest.xml 中设置适当的文件提供程序
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="$applicationId.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths"/>
</provider>
文件路径是.../res/xml/file_path.xml中的xml
<?xml version="1.0" encoding="utf-8"?>
<external-files-path name="external_files" path="Accessory"/>
<external-path name="ex_Download" path="Download/" />
<external-path name="ex_Pictures" path="Pictures/" />
<external-files-path name="my_Download" path="Download/" />
<external-files-path name="my_Pictures" path="Pictures/" />
<external-cache-path name="my_cache" path="." />
<files-path name="private_Download" path="Download/" />
<files-path name="private_Pictures" path="Pictures/" />
<cache-path name="private_cache" path="." />
长话短说,首先准备好文件提供程序,将 Uri 传递给 Intent 以获得已知且可访问的图片源,否则,将图片保存在所需位置,然后将位置(作为 Uri)传递给 Intent。
【讨论】:
以上是关于以编程方式从 Android 的内置图库应用程序中获取/选择图像的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Android 中以编程方式将图像文件从图库复制到另一个文件夹