This is the first time I post something here, so I apologize in advance for any mistake what-so-ever.
This is the situation:
I'm currently developing my first android app, sort of like a tracker:
1. log in
2. select weather, temperature etc
3. press the start button that activates a background GPS service and shows you a list of other attendees
4. click on an attendee and it shows you a timeline where you can add pictures etc.
Here is where the fun starts. When I open the camera it works most of the time, but once in a while the activity that opens the camera gets destroyed and when reopening (to further progress) it opens a second camera.
When I take a picture like that it completely ignores the first picture, restarts the gps-service, messes up my timeline and shows the login dialog when I go back to the the main activity (which is programmed to only show up when starting the app).
I have read an similar topic and it might be the solution, but I can't get it to work.
The code for the camera activity:
public class AddPhotoActivity extends Activity {
private SharedPreferences savedValues;
private String mCurrentPhotoPath;
private String imageName;
private int id;
private String startRideDateTime;
private SimpleDateFormat dateInSQL = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
private Date date;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add_photo);
savedValues = this.getSharedPreferences("SavedValues",
Context.MODE_PRIVATE);
id = savedValues.getInt("RideId", 0);
startRideDateTime = savedValues.getString("StartRideDateTime", "");
try {
date = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").parse(startRideDateTime);
} catch (ParseException e) {
e.printStackTrace();
}
SimpleDateFormat dateInDir
= new SimpleDateFormat("yyyyMMdd_HHmmss");
startRideDateTime = dateInDir.format(date);
if (savedInstanceState == null) {
dispatchTakePictureIntent();
}
}
#Override
protected void onResume() {
super.onResume();
savedValues = this.getSharedPreferences("SavedValues",
Context.MODE_PRIVATE);
}
private void dispatchTakePictureIntent() {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
File photoFile = null;
try {
photoFile = createImageFile();
} catch (IOException ex) {
ex.printStackTrace();
}
if (photoFile != null) {
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT,
Uri.fromFile(photoFile));
startActivityForResult(takePictureIntent, 1);
}
}
}
private File createImageFile() throws IOException {
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = "IMG_" + timeStamp;
File sdCard = Environment.getExternalStorageDirectory();
File storageDir = new File(sdCard.getAbsolutePath() + „/app/„ + id + "/" + startRideDateTime + "/photos");
storageDir.mkdirs();
File image = File.createTempFile(imageFileName, ".jpg", storageDir);
mCurrentPhotoPath = "file:" + image.getAbsolutePath();
imageName = image.getName();
return image;
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK) {
if (mCurrentPhotoPath != null) {
addPhotoToDb();
mCurrentPhotoPath = null;
}
} else if (resultCode == RESULT_CANCELED) {
finish();
}
}
private void addPhotoToDb() {
TimeLineDataSource timeLineDataSource = new TimeLineDataSource(this);
timeLineDataSource.open();
date = new Date();
String dateString = dateInSQL.format(date);
timeLineDataSource.createTimeLineItem(3, imageName, dateString);
timeLineDataSource.close();
finish();
}
public void onBackPressed() {
finish();
}
}
If anybody knows a solution to this I would be eternally grateful!
Update:
although I had better code after the previous suggestion it still didn't solve the problem. It seems that devices with less memory can get terminated at DVM-level, causing them to quit without onDestroy(). My issue is more or less resolved, but includes a lot of patchwork that I feel can be done in other, more efficient ways.
The code below is what I usually use for taking a photo/picking a photo. I normally include the ability to pick a previous photo or take a new photo, and I don't run into this issue.
Intent takePicture = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(takePicture, 0);
//zero can be replced with any action code to pick photo from gallery
Intent pickPhoto = new Intent(Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(pickPhoto , 1);
//one can be replced with any action code
protected void onActivityResult(int requestCode, int resultCode, Intent imageReturnedIntent) {
super.onActivityResult(requestCode, resultCode, imageReturnedIntent);
switch(requestCode) {
case 0:
if(resultCode == RESULT_OK){
Uri selectedImage = imageReturnedIntent.getData();
imageview.setImageURI(selectedImage);
}
break;
case 1:
if(resultCode == RESULT_OK){
Uri selectedImage = imageReturnedIntent.getData();
imageview.setImageURI(selectedImage);
}
break;
}
}
Also, I agree with the solution from the other post, this in particular:
In the case of a destroyed activity, when the activity result needs to
be processed, Android will recreate the Activity, passing a
savedInstanceState to onCreate. So, the remedy is to check the value
of savedInstanceState in your GetImageActivity.onCreate. If it is not
null then don't make any calls to startActivity because your Activity
is being recreated to call onActivityResult.
Optionally, if you need to preserve any state then override
onSaveInstanceState(Bundle outState) and put data you need into
outState.
Related
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 am starting from my fragment the standard android camera app. Everything works fine and the image gets saved as I wish. After the user has taken a picture (and only then) I would like to launch a DialogFragment.
I tried using intents and calling onActivetyResult() from the same fragment. But onActivityResult() never gets called.
How I start the camera in my fragment:
MyCamera camera = new MyCamera(getActivity());
camera.start();
Im my MyCamera class I am starting the intent like so:
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photoFile));
activity.startActivityForResult(takePictureIntent, Constants.TAKE_PHOTO);
Back in the the fragment I am calling onActivityResult():
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == Constants.TAKE_PHOTO && resultCode == Activity.RESULT_OK) {
// do something
}
}
How can I achieve this task? Thanks in advance for the help!
Here the entire MyCamera class:
public class MyCamera {
private Activity activity;
private static final String TAG = "MyCamera";
private String currentPhotoPath;
private String currentFileName;
private File currentFile;
private Uri contentUri;
public MyCamera(Activity activity) {
this.activity = activity;
}
public void start() {
dispatchPictureIntent();
addPictureToGallery();
currentPhotoPath = null;
}
private void dispatchPictureIntent() {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// check if device has camera
if (takePictureIntent.resolveActivity(activity.getPackageManager()) != null) {
File photoFile = null;
try {
photoFile = createImageFile();
currentPhotoPath = photoFile.getAbsolutePath();
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(activity, R.string.msg_picture_not_saved, Toast.LENGTH_LONG).show();
}
if (photoFile != null) {
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photoFile));
takePictureIntent.putExtra(Constants.IMAGE_FILE_NAME, currentFileName);
activity.startActivityForResult(takePictureIntent, Constants.TAKE_PHOTO);
}
}
}
private File createImageFile() throws IOException {
// set up storage dir
File storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
if (!storageDir.exists()) {
if (!storageDir.mkdirs()) {
Log.e(TAG, "failed to create directory");
return null;
}
}
// set up file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String fileName = "img_" + timeStamp + "_";
String suffix = ".jpg";
File image = File.createTempFile(fileName, suffix, storageDir);
currentFileName = image.getName();
currentFile = image;
return image;
}
private void addPictureToGallery() {
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
contentUri = getUri(currentPhotoPath);
mediaScanIntent.setData(contentUri);
activity.sendBroadcast(mediaScanIntent);
}
private Uri getUri(String currentPhotoPath) {
File f = new File(currentPhotoPath);
return Uri.fromFile(f);
}
}
Based on this post: onActivityResult is not being called in Fragment
try adding in your hosting activity
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
}
It will allow to pass unhandled activity result to your fragment.
Also, make sure you call fragment.startActivityForResult() instead of activity.startActivityForResult().
I tried using intents and calling onActivetyResult() from the same fragment. But onActivityResult() never gets called.
That is because you are calling startActivityForResult() on the Activity, not on the fragment. Your onActivityResult() method goes on the object on which you call startActivityForResult(). So, if you want the fragment to have onActivityResult(), call startActivityForResult() on the fragment.
I'm completely news on android thing and unfortunately with little few time to learn it by the right way, I have a work to release.
The problem is: I need to take a picture and process her with an algorithm that I made.
I did it by the easiest way that I could find, I know it looks like really trahsie for those who really get android (sorry)
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
takePic();
protected void takePic(){
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(takePictureIntent, 100);
}
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
Bundle extras = data.getExtras();
mImageBitmap = (Bitmap) extras.get("data");
Algorithm(mImageBitmap)
But it doesn't process, it takes a photo, ask to save or cancell and leaves the application, I have already made by different ways (creating a new activity), but nothing seems to work
Heres how I did it
To go to the camera:
Somewhere, declaire a fileUri variable and hold onto it
Uri fileUri;
final int TAKE_PICTURE=100;//this can be any int, really
public void goToCamera(){
Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
File photo;
try
{
// place where to store camera taken picture
photo = this.createTemporaryFile("picture", ".jpg");
Log.v(TAG, "Here(after createTempFile)");
photo.delete();
}
catch(Exception e)
{
Log.v(TAG, "Can't create file to take picture!" + e.getMessage());
Toast.makeText(context, "Please check SD card!", Toast.LENGTH_SHORT).show();
return;
}
fileUri = Uri.fromFile(photo);
intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);
//Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, TAKE_PICTURE);
}
Then to retreive the image
protected void onActivityResult(int requestCode, int resultCode, Intent data){
if (requestCode == TAKE_PICTURE && resultCode == RESULT_OK){
this.getContentResolver().notifyChange(uri, null);
ContentResolver cr = this.getContentResolver();
Bitmap bitmap;
try
{
BitmapFactory.Options ops = new BitmapFactory.Options();
ops.inSampleSize = 4;
bitmap = BitmapFactory.decodeFile(uri.getPath().toString(), ops);
}
catch (Exception e)
{
Toast.makeText(this, "Failed to load", Toast.LENGTH_SHORT).show();
Log.d(TAG, "Failed to load", e);
}
}
}
The create temp file mentioned above:
private File createTemporaryFile(String part, String ext) throws Exception
{
File tempDir= Environment.getExternalStorageDirectory();
tempDir=new File(tempDir.getAbsolutePath()+"/.temp/");
Log.i(TAG, tempDir.toString());
if(!tempDir.exists())
{
Log.i(TAG, "Dir doesnt exist");
tempDir.mkdirs();
}
return File.createTempFile(part, ext, tempDir);
}
I realize this isn't probably as simple as you were hoping for, but this approach seemed to be as flexible and compatible as possible. Let me know if I left anything else out
It even can't make a folder on the sdcard. When the camera takes the photo, it doesn't respond when I press the 'OK' Button. What's wrong with my code?
public static final String MACCHA_PATH = Environment.getExternalStorageDirectory().getPath() + "/Twigit";
public static final String PHOTO_PATH = MACCHA_PATH + "/camera.jpg";
public static boolean takePhoto(Activity activity) {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
File fileDir = new File(MACCHA_PATH);
boolean isSuccessful = true;
if (!fileDir.exists()) {
isSuccessful = fileDir.mkdir();
}
if(!isSuccessful) {
return false;
} else {
File file = new File(PHOTO_PATH);
Uri outputFileUri = Uri.fromFile(file);
intent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);
activity.startActivityForResult(intent, TAKEPHOTO);
return true;
}
}
do you have this? You need to override the onActivityResult. which will be called before onResume when you use startActivityForResult. The requestCode will be the code you used to start the photo taking activity. In your case it would be TAKEPHOTO..
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == TAKEPHOTO) {
if (resultCode == RESULT_OK) {
//Pic taken
} else {
//Pic not taken
}
}
}
EDIT:
take a look at this link
http://achorniy.wordpress.com/2010/04/26/howto-launch-android-camera-using-intents/
I have a little problem with my camera intent. As I know, when camera orientation is changed, activity is restarted. Okej, I am using the code bellow.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
app = (myApplication)getApplication();
if(savedInstanceState ==null ) getFullImage(null);
else{
String somevalue = savedInstanceState.getString("uri");
getFullImage(somevalue);
}
}
private void getFullImage(String testValue)
{ if(testValue == null){
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
file = new File(Environment.getExternalStorageDirectory(), UUID.randomUUID()+ ".jpg");
outputFile = Uri.fromFile(file);
intent.putExtra(MediaStore.EXTRA_OUTPUT, outputFile);
startActivityForResult(intent, TAKE_PICTURE);
}else
{
outputFile = null;
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
file = new File(testValue);
outputFile = Uri.fromFile(file);
intent.putExtra(MediaStore.EXTRA_OUTPUT, testValue);
startActivityForResult(intent, TAKE_PICTURE);
finishFromChild(getParent());
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if(resultCode == RESULT_CANCELED) {
Log.i(TAG, "Back Button");
finishFromChild(this);
}
else
if(requestCode == TAKE_PICTURE && resultCode == RESULT_OK)
{
//I'm creating new file here (for this question is irelevant)
} catch (IOException e) {
e.printStackTrace();
}
Intent myIntent = new Intent(getBaseContext(), com.test.activities.SaveFileActivity.class);
myIntent.putExtra("image", newPath);
startActivityFromChild(this, myIntent, SAVE_ITEM);
finishFromChild(this);
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("uri",outputFile.getPath());
}
After picture is captured, I press DONE button and I go to SaveFileActivity. Everyting works fine, until I try from SaveFIleActivity to go to another activity, then camera is starting again. Where should I look for the problem ? Maybe I should kill camera intent, but when ?
I suspect you want to be using the simpler startActivity() and finish() methods instead of startActivityFromChild() and finishFromChild(). I admit, however, that I'm a bit unclear as to what the use of the ones you are actually for.