This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 6 years ago.
EDIT: The discussion on this issue has been carried to another question: Image capture with camera & upload to Firebase (Uri in onActivityResult() is null) PLEASE check it out! I did some manipulations (following the android documentation) but still getting same problem.
So here I'm trying to do a simple task of capturing an image with camera and uploading it to my storage database on Firebase. I have the following button to do the job:
b_capture.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, CAMERA_REQUEST_CODE);
}
});
and the following code for the upload:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == CAMERA_REQUEST_CODE && resultCode == RESULT_OK){
progressDialog.setMessage("Uploading...");
progressDialog.show();
Uri uri = data.getData();
StorageReference filepath = storage.child("Photos").child(uri.getLastPathSegment());
filepath.putFile(uri).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
#Override
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
Toast.makeText(MainActivity.this, "Upload Successful!", Toast.LENGTH_SHORT).show();
progressDialog.dismiss();
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Toast.makeText(MainActivity.this, "Upload Failed!", Toast.LENGTH_SHORT).show();
}
});
}
}
in the app I'm able to take picture, but after I confirm the picture taken the APP CRASHES and I get the following error:
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.net.Uri.getLastPathSegment()' on a null object reference
So, I understand that the "Uri" does not have anything in it, but I'm confused about what can be done. Need help.
And yes, I've checked all permissions, Firebase connections, Gradle sync etc.
You need to re-read the documentation and follow the example to create a file and store its Uri in the image capture intent. This is the code from the documentation you need to add:
String mCurrentPhotoPath;
private File createImageFile() throws IOException {
// Create an image file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = "JPEG_" + timeStamp + "_";
File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
File image = File.createTempFile(
imageFileName, /* prefix */
".jpg", /* suffix */
storageDir /* directory */
);
// Save a file: path for use with ACTION_VIEW intents
mCurrentPhotoPath = image.getAbsolutePath();
return image;
}
private void dispatchTakePictureIntent() {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// Ensure that there's a camera activity to handle the intent
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
// Create the File where the photo should go
File photoFile = null;
try {
photoFile = createImageFile();
} catch (IOException ex) {
// Error occurred while creating the File
...
}
// Continue only if the File was successfully created
if (photoFile != null) {
Uri photoURI = FileProvider.getUriForFile(this,
"com.example.android.fileprovider",
photoFile);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO);
}
}
}
b_capture.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
dispatchTakePictureIntent()
//Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
//startActivityForResult(intent, CAMERA_REQUEST_CODE);
}
});
Question solved in the following discussion: Image capture with camera & upload to Firebase (Uri in onActivityResult() is null) Thanks to everyone who participated!
Related
I have a project witch have permission to camera and storage.
When the user click in some buttons the camera will be open by intent and take picture then saved it in the device to add it to firebase storage.
This operation was successful on most devices, but in Redmi A8(Android 10 , MIUI 12.0.1) it
was failed , the camera open then the application stop , maybe it failed to save the picture or failed to get it in ActicityResult.
Who I can solve it ?
Note: This is a part of methods in my code.
private void dispatchTakePictureIntent() {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// Ensure that there's a camera activity to handle the intent
if (takePictureIntent.resolveActivity(getActivity().getPackageManager()) != null) {
// Create the File where the photo should go
File photoFile = null;
try {
photoFile = createImageFile();
} catch (IOException ex) {
}
// Continue only if the File was successfully created
if (photoFile != null) {
Uri photoURI = FileProvider.getUriForFile(getActivity(),
"com.apps.android.fileprovider", photoFile);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
startActivityForResult(takePictureIntent, CAMERA_REQUEST_CODE);
}
}
}
private File createImageFile() throws IOException {
// Create an image file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = "JPEG_" + timeStamp + "_";
File storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
File image = File.createTempFile(
imageFileName,
".jpg",
storageDir
);
currentPhotoPath = image.getAbsolutePath();
return image;
}
#Override
public void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == CAMERA_REQUEST_CODE) {
if (resultCode == Activity.RESULT_OK) {
File f = new File(currentPhotoPath);
//showImage.setImageURI(Uri.fromFile(f));
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
Uri contentUri = Uri.fromFile(f);
mediaScanIntent.setData(contentUri);
getActivity().sendBroadcast(mediaScanIntent);
uploadImageToFirebase(f.getName(), contentUri);
}
}
}
private void uploadImageToFirebase(String name, Uri contentUri) {
final StorageReference image = storageReference.child("pictures/" + name);
image.putFile(contentUri).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
#Override
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
image.getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
#Override
public void onSuccess(Uri uri) {
FirebaseDatabase database = FirebaseDatabase.getInstance();
database.getReference().child("Shifts").child(empId+"").
child(shiftKey).child(shiftImageType).setValue(uri+"");
alertDialog.dismiss();
}
});
startActivity(new Intent(getActivity() , MainActivity.class));
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Toast.makeText(getActivity(), e.getMessage()+"", Toast.LENGTH_SHORT).show();
}
});
}
I followed the Take photo guide of the Android developer documentation to take a picture. I want to use this picture for the Firebase MLKit, but I just need it temporarily, so I saved it to my private storage and delete if after I used it (I am extracting it's text).
So, I am using an Intent to let the capture be taken for me and save it to a specific file. If the Intent is done, how do I extract that picture so I can pass the bitmap to the Firebase API?
In the earlier stated documentation, it says
Note: If you saved your photo to the directory provided by getExternalFilesDir(), the media scanner cannot access the files because they are private to your app.
But it does not say how to access that file. That's my question: How do I access it?
For all interested in my code so far:
public class MainActivity extends AppCompatActivity {
static final int REQUEST_TAKE_PHOTO = 1;
private Uri photoURI;
//ToDo: delete picture at the end of app usage [finally->delete]
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
private void dispatchTakePictureIntent() {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// Ensure that there's a camera activity to handle the intent
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
// Create the File where the photo should go
File photoFile = null;
try {
photoFile = createImageFile();
} catch (IOException ex) {
//ToDo:Logging/Toast msg
// Error occurred while creating the File
}
// Continue only if the File was successfully created
if (photoFile != null) {
photoURI = FileProvider.getUriForFile(this,
"mypackagename",
photoFile);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO);
} else {
//ToDo: logging/Toast msg
}
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(resultCode == Activity.RESULT_OK && requestCode == REQUEST_TAKE_PHOTO){
//This is where I need to access the picture I saved.
}else{
//ToDo: logging/Toast msg
}
}
public void scanText(View view) {
//Firebase stuff, not relevant
}
String mCurrentPhotoPath;
private File createImageFile() throws IOException {
// Create an image file name
#SuppressLint("SimpleDateFormat") String timeStamp = new SimpleDateFormat
("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = "JPEG_" + timeStamp + "_";
File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
File image = File.createTempFile(
imageFileName, /* prefix */
".jpg", /* suffix */
storageDir /* directory */
);
// Save a file: path for use with ACTION_VIEW intents
mCurrentPhotoPath = image.getAbsolutePath();
return image;
}
}
Add this line to get the image bitmap
if(resultCode == Activity.RESULT_OK && requestCode == REQUEST_TAKE_PHOTO)
{
//This is where I need to access the picture I saved.
// get the image bitmap from this code
Bitmap imageBitmap = (Bitmap) data.getExtras().get("data");
}
else
{
//ToDo: logging/Toast msg
}
I'm trying to write an app which takes a photo and save it into the gallery.
I've followed the Android Developers' guide, but it only shows how to same images into a private directory.
Here is the code I use to send the intent to the camera
public void dispatchTakePictureIntent(View view) {
if (ContextCompat.checkSelfPermission(MainActivity.this,
Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(MainActivity.this,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
2121);
return;
}
//File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
File storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
File image = null;
try {
image= File.createTempFile("IMG", ".jpg", storageDir);
//tempImage=image;
} catch (IOException e) {
errorMessage.setVisibility(View.VISIBLE);
Log.e("error", Log.getStackTraceString(e));
return;
}
//photoURI = FileProvider.getUriForFile(this, "prova.fileprovider", image);
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (takePictureIntent.resolveActivity(getPackageManager()) != null ) {
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(image));
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
}
}
When I run it on the Android Studio emulator (Pixel_API_27) I get the error when calling the File.createTempFile
Thank you in advance for any help.
For Android 6+ you have to add code to ask the user to confirm the read write permissions you requested in manifest.
Google for runtime permissions.
You are #1246 this year who is posting this problem.
I find a solution by working around the problem.
I make the camera intent to save the picture to the private app folder,
then I move the file to the public one. Here is the code
public void dispatchTakePictureIntent(View view) {
//ask write permission
if (ContextCompat.checkSelfPermission(MainActivity.this,
Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(MainActivity.this,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
2121);
return;
}
//get path to private folder
File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
//create temp-file where the image will be saved
File image = null;
try {
image= File.createTempFile("IMG", ".jpg", storageDir);
} catch (IOException e) {
errorMessage.setVisibility(View.VISIBLE);
Log.e("error", Log.getStackTraceString(e));
return;
}
Image = image;
//get uri of the image
Uri photoURI = FileProvider.getUriForFile(this, "prova.fileprovider", image);
//send the intent to the camera
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (takePictureIntent.resolveActivity(getPackageManager()) != null ) {
takePictureIntent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, photoURI);
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
}
}
Then when the picture is take I do
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) { //AFTER TAKING PICTURE
File publicImage = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) + "/" + Image.getName());
Image.renameTo(publicImage); //here we move the file to the public directory
Image = publicImage;
//optionally one can update the gallery, but I don't need it
}
I am trying to open camera in Marshmallow and nougat using FileProvider but not getting the bitmap to show captured image in imageview in onActivityResult method.Even i tried to get bitmap from image path. Here is my code
image_click.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
dispatchTakePictureIntent();
}
});
}
static final int REQUEST_TAKE_PHOTO = 1;
private void dispatchTakePictureIntent() {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// Ensure that there's a camera activity to handle the intent
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
// Create the File where the photo should go
File photoFile = null;
try {
photoFile = createImageFile();
} catch (IOException ex) {
// Error occurred while creating the File
}
// Continue only if the File was successfully created
if (photoFile != null) {
photoURI = FileProvider.getUriForFile(this,
"com.xyz.dummyapp.fileprovider",
photoFile);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO);
}
}
}
private File createImageFile() throws IOException {
// Create an image file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = "JPEG_" + timeStamp + "_";
File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
File image = File.createTempFile(
imageFileName, /* prefix */
".jpg", /* suffix */
storageDir /* directory */
);
// Save a file: path for use with ACTION_VIEW intents
mCurrentPhotoPath = image.getAbsolutePath();
return image;
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_TAKE_PHOTO && resultCode == RESULT_OK) {
try{
Bitmap bitmap = BitmapFactory.decodeFile(photoURI.getPath());
mImageView.setImageURI(photoURI);
File file=new File(mCurrentPhotoPath);
if (file.exists()){
if (file.delete()){
runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(getApplicationContext(),"Deleted",Toast.LENGTH_SHORT).show();
}
});
}
}
}
catch (Exception e){
e.printStackTrace();
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="my_images" path="Android/data/com.xyz.dummyapp/files/Pictures" />
</paths>
I don't know if your code doesn't contain everything. But here are some points to note:
You should save photos in the device public directory
Generally, any photos that the user captures with the device camera should be saved on the device in the public external storage so they are accessible by all apps.
(Taken from the docs)
If you do so - you need to declare the WRITE_EXTERNAL_STORAGE in your AndroidManifest.xml:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
With Android Marshmallow you have then request the permission for that. Here is a simplified version of that:
.
requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 99);
...
....
#Override
public void onRequestPermissionsResult(final int requestCode, #NonNull final String[] permissions, #NonNull final int[] grantResults) {
// Execute your code to create the file and start the camera intent here
}
(Read more here)
You have also to use the getExternalStoragePublicDirectory from Environment as storageDir
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
Your file_path.xml should now point to Pictures/:
<external-path name="my_pictures" path="Pictures/"/>
In your onActivityResult you can simply use the photoUri field which you received from FileProvider#getUriForFile to set to the image:
imageView.setImageURI(photoUri);
For me the changes helps to make a working example:
I think you have to use this library for camera and gallery : https://github.com/jrvansuita/PickImage you don't needs to convert image in to bitmap.and this library is working fine in Marshmallow and nougat.
I have a problem with "capture image with camera", and store it into Firebase. I think that the code is right, because it worked with "select image from gallery". The app stoped after capturing the image, and it didn't store it into the database. I think that it is a problem for android M and N (Android 6 and 7). There is also the error in logcat.
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == CAMERA_REQUEST_CODE && resultCode == RESULT_OK){
mPregresDialog.setMessage("Uploading...");
mPregresDialog.show();
Uri uri = data.getData();
StorageReference filepath = mStorage.child("Photo").child(uri.getLastPathSegment());
filepath.putFile(uri).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
#Override
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
mPregresDialog.dismiss();
Toast.makeText(MainActivity.this, "Upload Done", Toast.LENGTH_LONG).show();
}
});
}}
logcat:
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.net.Uri.getLastPathSegment()' on a null object reference
The problem is that your Uri does not get the image as it should so you need to create your own Uri for your image you capture.
You need to go to android documentation: https://developer.android.com/training/camera/photobasics.html#TaskPhotoView
For your app, you can also just copy and paste this code in your main activity:
String mCurrentPhotoPath;
private File createImageFile() throws IOException {
// Create an image file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = "JPEG_" + timeStamp + "_";
File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
File image = File.createTempFile(
imageFileName, /* prefix */
".jpg", /* suffix */
storageDir /* directory */
);
// Save a file: path for use with ACTION_VIEW intents
mCurrentPhotoPath = image.getAbsolutePath();
return image;
}
private void dispatchTakePictureIntent() {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// Ensure that there's a camera activity to handle the intent
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
// Create the File where the photo should go
File photoFile = null;
try {
photoFile = createImageFile();
} catch (IOException ex) {
// Error occurred while creating the File...
}
// Continue only if the File was successfully created
if (photoFile != null) {
Uri photoURI = FileProvider.getUriForFile(this,
"com.example.android.fileprovider",
photoFile);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
startActivityForResult(takePictureIntent, CAMERA_REQUEST_CODE);
}
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
storage = FirebaseStorage.getInstance().getReference();
b_gallery = (Button) findViewById(R.id.b_gallery);
b_capture = (Button) findViewById(R.id.b_capture);
iv_image = (ImageView) findViewById(R.id.iv_image);
progressDialog = new ProgressDialog(this);
b_capture.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
dispatchTakePictureIntent();
}
});
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == CAMERA_REQUEST_CODE && resultCode == RESULT_OK){
progressDialog.setMessage("Uploading...");
progressDialog.show();
Uri uri = data.getData();
StorageReference filepath = storage.child("Photos").child(uri.getLastPathSegment());
filepath.putFile(photoURI).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
#Override
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
Toast.makeText(MainActivity.this, "Upload Successful!", Toast.LENGTH_SHORT).show();
progressDialog.dismiss();
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Toast.makeText(MainActivity.this, "Upload Failed!", Toast.LENGTH_SHORT).show();
}
});
}
}
}
And make sure you follow the documentation and have added the provider in your AndroidManifest.xml:
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.example.android.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths"></meta-data>
</provider>
And the res/xml/file_paths.xml (you just make a directory under "res" folder and name it xml, then you create a resource file and name it file_paths.xml); then delete all the code inside it (it'll have some lines) and paste the following:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="my_images" path="Android/data/com.serjardovic.firebasesandbox/files/Pictures" />
</paths>
Make sure you CHANGE the com.serjardovic.firebasesandbox to your own package name!