[英]Android getting URI from Camera
I am having an issue when taking a photo with the camera on my Nexus 5. I can take photos from the gallery no problem and save them to the back end. 在Nexus 5上使用相机拍摄照片时出现问题。我可以从图库中毫无问题地拍摄照片并将其保存到后端。 However when I try to take a picture using the camera, after I take the picture and select the tick, then the app crashes... I can see that the intent passed to the onActivityResult() is empty but I don't know how to fix this. 但是,当我尝试使用相机拍照时,在拍照并选择勾号后,应用程序崩溃了。我可以看到传递给onActivityResult()的意图为空,但我不知道如何解决这个问题。 Can anyone help? 有人可以帮忙吗? thanks. 谢谢。
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.Toast;
import com.khackett.runmate.R;
import com.khackett.runmate.utils.FileHelper;
import com.khackett.runmate.utils.ParseConstants;
import com.parse.ParseException;
import com.parse.ParseFile;
import com.parse.ParseUser;
import com.parse.SaveCallback;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
public class MyProfileFragment extends Fragment implements View.OnClickListener {
public static final String TAG = MyProfileFragment.class.getSimpleName();
protected Button mTakePicture;
protected Button mChoosePicture;
/**
* Default constructor
*/
public MyProfileFragment() {
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
View rootView = inflater.inflate(R.layout.fragment_my_profile, container, false);
mTakePicture = (Button) rootView.findViewById(R.id.takePictureButton);
mChoosePicture = (Button) rootView.findViewById(R.id.choosePictureButton);
mTakePicture.setOnClickListener(this);
mChoosePicture.setOnClickListener(this);
return rootView;
}
/**
* Called when a view has been clicked.
*
* @param v The view that was clicked.
*/
@Override
public void onClick(View v) {
// Switch statement to select which action to take depending on button/text pressed
switch (v.getId()) {
case R.id.takePictureButton:
takeCameraPicture();
break;
case R.id.choosePictureButton:
chooseGalleryPicture();
break;
default:
System.out.println("Problem with input");
}
}
public static final int TAKE_PHOTO_REQUEST = 1888;
public static final int PICK_PHOTO_REQUEST = 1888;
private static final int CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE = 1888;
// member variable to store the media type as a URI, that can be stored in multiple places
// Uri = uniform resource identifier
protected Uri mMediaUri;
public void takeCameraPicture() {
// Take picture
// use an existing camera app on the phone by starting an intent
// declare intent to capture a photo using whatever camera app is available
Intent takePhotoIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// after invoking the camera,
mMediaUri = getOutputMediaFileUri();
// check that a null value is not returned
if (mMediaUri == null) {
// display an error
Toast.makeText(getActivity(), R.string.error_external_storage, Toast.LENGTH_LONG).show();
} else {
// to add extra data to an intent, use the putExtra() method
takePhotoIntent.putExtra(MediaStore.EXTRA_OUTPUT, mMediaUri);
// start an activity for a result so that the activity exits and returns a result back for us
// ie, the main activity will wait for the result
startActivityForResult(takePhotoIntent, TAKE_PHOTO_REQUEST);
}
}
public void chooseGalleryPicture() {
// Choose picture
Intent choosePhotoIntent = new Intent(Intent.ACTION_GET_CONTENT);
// need to specify which type of action we want to get - an image in this case
choosePhotoIntent.setType("image/*");
startActivityForResult(choosePhotoIntent, PICK_PHOTO_REQUEST);
}
private Uri getOutputMediaFileUri() {
// To be safe, you should check that the SD card / external storage is mounted
// using Environment.getExternalStorageState() before doing this.
// see method below...
if (isExternalStorageAvailable()) {
String appName = MyProfileFragment.this.getString(R.string.app_name);
// get the Uri
// Get the external storage directory - we want to return a file object
File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), appName);
// Create our subdirectory
if (!mediaStorageDir.exists()) {
if (!mediaStorageDir.mkdir()) {
Log.e(TAG, "Failed to create directory");
return null;
}
}
// Create a file to hold the image
File mediaFile;
// get the current date and time
Date now = new Date();
// convert the date and time into a String datetimestamp
// see http://developer.android.com/guide/topics/media/camera.html#saving-media for the methods used
// need to append a timestamp to make it unique - otherwise it will overwrite the previous photo
String timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.ENGLISH).format(now);
String path = mediaStorageDir.getPath() + File.separator;
// create a new file using the constructor that takes a name
mediaFile = new File(path + "IMG_" + timestamp + ".jpg");
Log.d(TAG, "File: " + Uri.fromFile(mediaFile));
// Return the files URI
Log.d(TAG, "Returning the files URI");
return Uri.fromFile(mediaFile);
} else {
return null;
}
}
/**
* check if external storage is available on the users device
*
* @return
*/
private boolean isExternalStorageAvailable() {
// find out what state external storage is in
String state = Environment.getExternalStorageState();
// if external storage is available, return true,
if (state.equals(Environment.MEDIA_MOUNTED)) {
return true;
} else {
return false;
}
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == Activity.RESULT_OK) {
if (requestCode == CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE) {
if (data == null) {
Log.d(TAG, "Data is null");
Toast.makeText(getActivity(), getString(R.string.general_error), Toast.LENGTH_LONG).show();
} else {
Log.d(TAG, "Data: " + data);
// the intent has data, so set the media uri
Log.d(TAG, "adding the data using the getData() method");
mMediaUri = data.getData();
Log.d(TAG, "Media Uri: " + mMediaUri);
}
// ParseUser.getCurrentUser().put("profilePic", mMediaUri);
saveImageToParse();
}
} else if (resultCode != Activity.RESULT_CANCELED) {
Log.d(TAG, "Problem getting the picture from gallery");
// Toast.makeText(getActivity(), R.string.general_error, Toast.LENGTH_LONG).show();
}
}
public void saveImageToParse() {
Log.d(TAG, "entering saveImageToParse() method");
byte[] fileBytes = FileHelper.getByteArrayFromFile(getActivity(), mMediaUri);
fileBytes = FileHelper.reduceImageForUpload(fileBytes);
String fileName = FileHelper.getFileName(getActivity(), mMediaUri, "file");
ParseFile file = new ParseFile(fileName, fileBytes);
ParseUser.getCurrentUser().put("profilePic", file);
ParseUser.getCurrentUser().saveInBackground(new SaveCallback() {
public void done(ParseException e) {
if (e == null) {
Log.d(TAG, "Image saved successfully");
// myObjectSavedSuccessfully();
} else {
Log.d(TAG, "Image not saved");
// myObjectSaveDidNotSucceed();
}
}
});
}
. 。
package com.khackett.runmate.utils;
import android.content.Context;
import android.graphics.Bitmap;
import android.net.Uri;
import android.util.Log;
import org.apache.commons.io.IOUtils;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
// https://github.com/treehouse/treehouse_android_utilities
public class FileHelper {
public static final String TAG = FileHelper.class.getSimpleName();
public static final int SHORT_SIDE_TARGET = 1280;
public static byte[] getByteArrayFromFile(Context context, Uri uri) {
byte[] fileBytes = null;
InputStream inStream = null;
ByteArrayOutputStream outStream = null;
Log.d(TAG, "in the getByteArrayFromFile() method");
if (uri.getScheme() != null && uri.getScheme().equals("content")) {
try {
Log.d(TAG, "entering try to set inputstream");
inStream = context.getContentResolver().openInputStream(uri);
outStream = new ByteArrayOutputStream();
byte[] bytesFromFile = new byte[1024 * 1024]; // buffer size (1 MB)
int bytesRead = inStream.read(bytesFromFile);
while (bytesRead != -1) {
outStream.write(bytesFromFile, 0, bytesRead);
bytesRead = inStream.read(bytesFromFile);
}
fileBytes = outStream.toByteArray();
} catch (IOException e) {
Log.e(TAG, e.getMessage());
} finally {
try {
inStream.close();
outStream.close();
} catch (IOException e) { /*( Intentionally blank */ }
}
} else {
try {
File file = new File(uri.getPath());
FileInputStream fileInput = new FileInputStream(file);
fileBytes = IOUtils.toByteArray(fileInput);
} catch (IOException e) {
Log.e(TAG, e.getMessage());
}
}
return fileBytes;
}
public static byte[] reduceImageForUpload(byte[] imageData) {
Bitmap bitmap = ImageResizer.resizeImageMaintainAspectRatio(imageData, SHORT_SIDE_TARGET);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream);
byte[] reducedData = outputStream.toByteArray();
try {
outputStream.close();
} catch (IOException e) {
// Intentionally blank
}
return reducedData;
}
public static String getFileName(Context context, Uri uri, String fileType) {
String fileName = "uploaded_file.";
if (fileType.equals(ParseConstants.TYPE_IMAGE)) {
fileName += "png";
} else {
// For video, we want to get the actual file extension
if (uri.getScheme().equals("content")) {
// do it using the mime type
String mimeType = context.getContentResolver().getType(uri);
int slashIndex = mimeType.indexOf("/");
String fileExtension = mimeType.substring(slashIndex + 1);
fileName += fileExtension;
} else {
fileName = uri.getLastPathSegment();
}
}
return fileName;
}
}
. 。
09-01 20:15:49.322 23271-23271/com.khackett.runmate E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: com.khackett.runmate, PID: 23271
java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=67424, result=-1, data=Intent { }} to activity {com.khackett.runmate/com.khackett.runmate.ui.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.net.Uri.getScheme()' on a null object reference
at android.app.ActivityThread.deliverResults(ActivityThread.java:3574)
at android.app.ActivityThread.handleSendResult(ActivityThread.java:3617)
at android.app.ActivityThread.access$1300(ActivityThread.java:151)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1352)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5254)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.net.Uri.getScheme()' on a null object reference
at com.khackett.runmate.utils.FileHelper.getByteArrayFromFile(FileHelper.java:29)
at com.khackett.runmate.ui.MyProfileFragment.saveImageToParse(MyProfileFragment.java:233)
at com.khackett.runmate.ui.MyProfileFragment.onActivityResult(MyProfileFragment.java:210)
at android.support.v4.app.FragmentActivity.onActivityResult(FragmentActivity.java:165)
at android.app.Activity.dispatchActivityResult(Activity.java:6192)
at android.app.ActivityThread.deliverResults(ActivityThread.java:3570)
at android.app.ActivityThread.handleSendResult(ActivityThread.java:3617)
at android.app.ActivityThread.access$1300(ActivityThread.java:151)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1352)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5254)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
From the log, and your code, you can track that it is mMediaUri
being null. 从日志和代码中,您可以跟踪到mMediaUri
为空。
This should be caused by activity recreate because of screen rotation, for example, if your app usually run in Portrait, while the camera force to Landscape or you rotated when you use camera. 这可能是由于屏幕旋转引起的活动重新创建引起的,例如,如果您的应用程序通常以纵向运行,而相机的力为横向,或者您使用相机时旋转了。
Anyway to solve this, you have to save the mMediaUrl
and restore it in onCreate
, modify your Fragment like this: 无论如何要解决此问题,您都必须保存mMediaUrl
并将其还原到onCreate
,如下所示修改您的Fragment:
@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
// Save the user's current state
savedInstanceState.putString("media_url", mMediaUrl.toString());
// Always call the superclass so it can save the view hierarchy state
super.onSaveInstanceState(savedInstanceState);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
mMediaUrl = Uri.parse(savedInstanceState.getString("media_url"));
}
}
Edit: 编辑:
noticed another problem, change the followings: 发现另一个问题,请更改以下内容:
public static final int TAKE_PHOTO_REQUEST = 1889;
public static final int PICK_PHOTO_REQUEST = 1888;
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == Activity.RESULT_OK) {
if (requestCode == PICK_PHOTO_REQUEST) {
if (data == null) {
Log.d(TAG, "Data is null");
Toast.makeText(getActivity(), getString(R.string.general_error), Toast.LENGTH_LONG).show();
} else {
Log.d(TAG, "Data: " + data);
// the intent has data, so set the media uri
Log.d(TAG, "adding the data using the getData() method");
mMediaUri = data.getData();
Log.d(TAG, "Media Uri: " + mMediaUri);
}
// ParseUser.getCurrentUser().put("profilePic", mMediaUri);
saveImageToParse();
} else if(requestCode == TAKE_PHOTO_REQUEST) {
saveImageToParse();
}
} else if (resultCode != Activity.RESULT_CANCELED) {
Log.d(TAG, "Problem getting the picture from gallery");
// Toast.makeText(getActivity(), R.string.general_error, Toast.LENGTH_LONG).show();
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.