使用 android 图库以便用户可以选择他们的照片作为头像,但返回的文件路径有问题
Using android gallery so user can choose their photo for avatar, having problems with the path of the file returned though
我不打算打印出整个堆栈跟踪,因为它很大,但本质上我正在尝试为文件 'document/image:136635' 创建一个 FileHandle,但我没有得到这样的文件或目录。
com.badlogic.gdx.utils.GdxRuntimeException:无法加载文件:/document/image:136635
原因:android.system.ErrnoException:打开失败:ENOENT(没有那个文件或目录)
所以我使用路径 'document/image:136635' 因为我为 android 图库应用程序启动了一个 activity 这样用户就可以 select 他们自己的照片化身。 selection 似乎工作正常,我们可以 select 一个图像,然后我的程序继续,但是当我尝试为图像创建一个文件句柄以便我可以在我的游戏中实际绘制它时,他们有问题。当我分析从 activity 返回的数据时,他们 select 编辑的照片路径返回为 'document/image:136635'。这通常是图像的有效路径吗?如果我在 phone 上使用文件查看器,我可以看到有一个文档文件夹,但里面什么也没有。
任何建议表示赞赏。谢谢
编辑:所以 URI 中的信息是(按顺序):
图片:136635
image/jpeg
IMG_20190702_175942.jpg
1562065182000
5
1285506
所以我可以得到实际的文件名,但仍然不是真正的路径?我不认为...
尝试将此代码添加到您的应用中,它工作正常
private static final int GALLERY_PICK = 1;
Intent galleryIntent = new Intent(Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(galleryIntent, PICK_IMAGE_REQUEST);
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == PICK_IMAGE_REQUEST && resultCode == RESULT_OK && data != null &&
data.getData() != null) {
Uri uri = data.getData();
try {
Bitmap bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), uri);
// Log.d(TAG, String.valueOf(bitmap));
ImageView imageView = (ImageView) findViewById(R.id.imageView);
imageView.setImageBitmap(bitmap);
} catch (IOException e) {
e.printStackTrace();
}
}
}
private static final int GALLERY_PICK = 1;
Intent galleryIntent = new Intent(Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(galleryIntent, GALLERY_PICK);
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == GALLERY_PICK && resultCode == RESULT_OK && data != null &&
data.getData() != null) {
Uri uri = data.getData();
try {
String filePath = getPathNew(this,uri); //return actual path
} catch (IOException e) {
e.printStackTrace();
}
}
}
获取实际路径--
@SuppressLint("NewApi")
public static String getPathNew(final Context context, final Uri uri) {
final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
// DocumentProvider
if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
// ExternalStorageProvider
if (isExternalStorageDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
if ("primary".equalsIgnoreCase(type)) {
return Environment.getExternalStorageDirectory() + "/" + split[1];
}
// TODO handle non-primary volumes
}
// DownloadsProvider
else if (isDownloadsDocument(uri)) {
final String id = DocumentsContract.getDocumentId(uri);
final Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"),
Long.valueOf(id));
return getDataColumn(context, contentUri, null, null);
}
// MediaProvider
else if (isMediaDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
Uri contentUri = null;
if ("image".equals(type)) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
} else if ("video".equals(type)) {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
} else if ("audio".equals(type)) {
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
}
final String selection = "_id=?";
final String[] selectionArgs = new String[]{split[1]};
return getDataColumn(context, contentUri, selection, selectionArgs);
}
}
// MediaStore (and general)
else if ("content".equalsIgnoreCase(uri.getScheme())) {
return getDataColumn(context, uri, null, null);
}
// File
else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
return null;
}
public static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {
Cursor cursor = null;
final String column = "_data";
final String[] projection = {column};
try {
cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
if (cursor != null && cursor.moveToFirst()) {
final int column_index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(column_index);
}
} finally {
if (cursor != null)
cursor.close();
}
return null;
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is ExternalStorageProvider.
*/
public static boolean isExternalStorageDocument(Uri uri) {
return "com.android.externalstorage.documents".equals(uri.getAuthority());
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is DownloadsProvider.
*/
public static boolean isDownloadsDocument(Uri uri) {
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is MediaProvider.
*/
public static boolean isMediaDocument(Uri uri) {
return "com.android.providers.media.documents".equals(uri.getAuthority());
}
在您的清单中添加文件READ WRITE
权限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
我使用 Picasso 库来简化此过程。我将图像的副本以 .png 格式保存到应用程序的内部目录中,这样我就不必担心原始文件会发生什么情况,然后可以在游戏中将其作为纹理打开。
Picasso 还包括在将图像加载为位图之前缩小图像的方法,因为您可能不希望将全分辨率照片加载为纹理。
首先添加到android依赖:
implementation 'com.squareup.picasso:picasso:2.5.2'
// might need compile keyword instead if using old build tools
然后你可以在 activity:
private static final int REQUEST_PICK_IMAGE = 1;
void getImage (){
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
startActivityForResult(intent, REQUEST_PICK_IMAGE );
}
public void onActivityResult(int requestCode, int resultCode, final Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_PICK_IMAGE && resultCode == Activity.RESULT_OK && data != null){
// Check for file availability
InputStream inputStream = null;
try {
inputStream = getContentResolver().openInputStream(data.getData());
} catch (FileNotFoundException e) {
e.printStackTrace();
Toast.makeText(this, "Image could not be accessed", Toast.LENGTH_SHORT).show();
return;
} finally {
if (inputStream != null)
inputStream.close();
}
//TODO show progress bar and disable buttons
new ImageResultTask().execute(data);
}
}
private class ImageResultTask extends AsyncTask<Intent, Void, Boolean> {
protected Boolean doInBackground (Intent... params) {
FileOutputStream os = null;
try {
Bitmap bitmap = Picasso.with(MyActivity.this)
.load(params[0].getData())
.error(R.drawable.my_backup_drawable) // shouldn't happen, checked for FNFE above
.resize(1024, 0) // the zero makes it scale to width and keep aspect ratio for height
.get();
getFilesDir(); // workaround for Android bug #10515463
File destDir = getFilesDir();
File destFile = new File(dir, "myImage.png");
destFile.createNewFile();
os = new FileOutputStream(destFile , false);
bitmap.compress(Bitmap.CompressFormat.PNG, 0, os);
os.flush();
return true;
} catch (IOException e){
e.printStackTrace();
} catch (SecurityException e){
e.printStackTrace();
} finally {
if (os != null)
os.close();
}
return false;
}
protected void onPostExecute(Boolean result) {
if (result) {
Gdx.app.postRunnable(...); //TODO call into game to tell it image is ready
// The Texture can be loaded with Gdx.files.local("myImage.png")
} else {
//TODO show some error message
}
//TODO remove progress bar and unlock buttons, etc.
}
}
我不打算打印出整个堆栈跟踪,因为它很大,但本质上我正在尝试为文件 'document/image:136635' 创建一个 FileHandle,但我没有得到这样的文件或目录。
com.badlogic.gdx.utils.GdxRuntimeException:无法加载文件:/document/image:136635
原因:android.system.ErrnoException:打开失败:ENOENT(没有那个文件或目录)
所以我使用路径 'document/image:136635' 因为我为 android 图库应用程序启动了一个 activity 这样用户就可以 select 他们自己的照片化身。 selection 似乎工作正常,我们可以 select 一个图像,然后我的程序继续,但是当我尝试为图像创建一个文件句柄以便我可以在我的游戏中实际绘制它时,他们有问题。当我分析从 activity 返回的数据时,他们 select 编辑的照片路径返回为 'document/image:136635'。这通常是图像的有效路径吗?如果我在 phone 上使用文件查看器,我可以看到有一个文档文件夹,但里面什么也没有。
任何建议表示赞赏。谢谢
编辑:所以 URI 中的信息是(按顺序):
图片:136635
image/jpeg
IMG_20190702_175942.jpg
1562065182000
5
1285506
所以我可以得到实际的文件名,但仍然不是真正的路径?我不认为...
尝试将此代码添加到您的应用中,它工作正常
private static final int GALLERY_PICK = 1;
Intent galleryIntent = new Intent(Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(galleryIntent, PICK_IMAGE_REQUEST);
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == PICK_IMAGE_REQUEST && resultCode == RESULT_OK && data != null &&
data.getData() != null) {
Uri uri = data.getData();
try {
Bitmap bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), uri);
// Log.d(TAG, String.valueOf(bitmap));
ImageView imageView = (ImageView) findViewById(R.id.imageView);
imageView.setImageBitmap(bitmap);
} catch (IOException e) {
e.printStackTrace();
}
}
}
private static final int GALLERY_PICK = 1;
Intent galleryIntent = new Intent(Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(galleryIntent, GALLERY_PICK);
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == GALLERY_PICK && resultCode == RESULT_OK && data != null &&
data.getData() != null) {
Uri uri = data.getData();
try {
String filePath = getPathNew(this,uri); //return actual path
} catch (IOException e) {
e.printStackTrace();
}
}
}
获取实际路径--
@SuppressLint("NewApi")
public static String getPathNew(final Context context, final Uri uri) {
final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
// DocumentProvider
if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
// ExternalStorageProvider
if (isExternalStorageDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
if ("primary".equalsIgnoreCase(type)) {
return Environment.getExternalStorageDirectory() + "/" + split[1];
}
// TODO handle non-primary volumes
}
// DownloadsProvider
else if (isDownloadsDocument(uri)) {
final String id = DocumentsContract.getDocumentId(uri);
final Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"),
Long.valueOf(id));
return getDataColumn(context, contentUri, null, null);
}
// MediaProvider
else if (isMediaDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
Uri contentUri = null;
if ("image".equals(type)) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
} else if ("video".equals(type)) {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
} else if ("audio".equals(type)) {
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
}
final String selection = "_id=?";
final String[] selectionArgs = new String[]{split[1]};
return getDataColumn(context, contentUri, selection, selectionArgs);
}
}
// MediaStore (and general)
else if ("content".equalsIgnoreCase(uri.getScheme())) {
return getDataColumn(context, uri, null, null);
}
// File
else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
return null;
}
public static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {
Cursor cursor = null;
final String column = "_data";
final String[] projection = {column};
try {
cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
if (cursor != null && cursor.moveToFirst()) {
final int column_index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(column_index);
}
} finally {
if (cursor != null)
cursor.close();
}
return null;
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is ExternalStorageProvider.
*/
public static boolean isExternalStorageDocument(Uri uri) {
return "com.android.externalstorage.documents".equals(uri.getAuthority());
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is DownloadsProvider.
*/
public static boolean isDownloadsDocument(Uri uri) {
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is MediaProvider.
*/
public static boolean isMediaDocument(Uri uri) {
return "com.android.providers.media.documents".equals(uri.getAuthority());
}
在您的清单中添加文件READ WRITE
权限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
我使用 Picasso 库来简化此过程。我将图像的副本以 .png 格式保存到应用程序的内部目录中,这样我就不必担心原始文件会发生什么情况,然后可以在游戏中将其作为纹理打开。
Picasso 还包括在将图像加载为位图之前缩小图像的方法,因为您可能不希望将全分辨率照片加载为纹理。
首先添加到android依赖:
implementation 'com.squareup.picasso:picasso:2.5.2'
// might need compile keyword instead if using old build tools
然后你可以在 activity:
private static final int REQUEST_PICK_IMAGE = 1;
void getImage (){
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
startActivityForResult(intent, REQUEST_PICK_IMAGE );
}
public void onActivityResult(int requestCode, int resultCode, final Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_PICK_IMAGE && resultCode == Activity.RESULT_OK && data != null){
// Check for file availability
InputStream inputStream = null;
try {
inputStream = getContentResolver().openInputStream(data.getData());
} catch (FileNotFoundException e) {
e.printStackTrace();
Toast.makeText(this, "Image could not be accessed", Toast.LENGTH_SHORT).show();
return;
} finally {
if (inputStream != null)
inputStream.close();
}
//TODO show progress bar and disable buttons
new ImageResultTask().execute(data);
}
}
private class ImageResultTask extends AsyncTask<Intent, Void, Boolean> {
protected Boolean doInBackground (Intent... params) {
FileOutputStream os = null;
try {
Bitmap bitmap = Picasso.with(MyActivity.this)
.load(params[0].getData())
.error(R.drawable.my_backup_drawable) // shouldn't happen, checked for FNFE above
.resize(1024, 0) // the zero makes it scale to width and keep aspect ratio for height
.get();
getFilesDir(); // workaround for Android bug #10515463
File destDir = getFilesDir();
File destFile = new File(dir, "myImage.png");
destFile.createNewFile();
os = new FileOutputStream(destFile , false);
bitmap.compress(Bitmap.CompressFormat.PNG, 0, os);
os.flush();
return true;
} catch (IOException e){
e.printStackTrace();
} catch (SecurityException e){
e.printStackTrace();
} finally {
if (os != null)
os.close();
}
return false;
}
protected void onPostExecute(Boolean result) {
if (result) {
Gdx.app.postRunnable(...); //TODO call into game to tell it image is ready
// The Texture can be loaded with Gdx.files.local("myImage.png")
} else {
//TODO show some error message
}
//TODO remove progress bar and unlock buttons, etc.
}
}