Tuesday, March 8, 2016

Camera not overriding old image if orientation changes

Leave a Comment

I have a RecyclerView adapter with many different ViewHolders. One of the ViewHolders contains an ImageView, which needs to be able to take a picture, resize it, then display it. For modularity, I want the ViewHolder to be self-contained: it and not the parent activity should handle everything concerning the photo taking and displaying process. Also the file path is constant (it will never change). In fact, it is /storage/emulated/0/com.company.app/myst/cat.jpg. As a result, here is my implementation of the ImageView’s onClick method.

@Override public void onClick(View v) {     final FragmentManager fm = ((MyActivity) getContext()).getSupportFragmentManager();     Fragment auxiliary = new Fragment() {         @Override         public void onActivityResult(int requestCode, int resultCode, Intent data) {             resizeResaveAndDisplayPhoto();             super.onActivityResult(requestCode, resultCode, data);             fm.beginTransaction().remove(this).commit();         }     };     fm.beginTransaction().add(auxiliary, "FRAGMENT_TAG").commit();     fm.executePendingTransactions();      Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);     if (null != takePictureIntent.resolveActivity(view.getContext().getPackageManager())) {         ((MyActivity)view.getContext()).setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);         takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photoFile));          auxFragment.startActivityForResult(takePictureIntent, Constants.REQUEST_CODE_PHOTO);     } } 

When resizeResaveAndDisplayPhoto is called it executes the following AsyncTask

public static class ResizeThenLoadImageTask extends AsyncTask<String, Void, Bitmap> {      private final WeakReference<ImageView> imageViewWeakReference;     private final WeakReference<File> fileWeakReference;     private final WeakReference<Context> weakContext;     private final int reqHeight;     private final int reqWidth;      public ResizeThenLoadImageTask(Context context, ImageView imageView, File file, int reqHeight, int reqWidth) {         weakContext = new WeakReference<Context>(context);         imageViewWeakReference = new WeakReference<>(imageView);         fileWeakReference = new WeakReference(file);         this.reqHeight = reqHeight;         this.reqWidth = reqWidth;     }      @Override     public Bitmap doInBackground(String... params) {         File file = fileWeakReference.get();         Bitmap bitmap = null;         if (null != file) {             bitmap = ImageUtils.reduceImageSize(file, reqHeight, reqWidth);             ImageUtils.saveBitmapToGivenFile(bitmap, file);         }         return bitmap;     }      @Override     public void onPostExecute(Bitmap bitmap) {         if (null != imageViewWeakReference && null != fileWeakReference) {             ImageView imageView = imageViewWeakReference.get();             File file = fileWeakReference.get();             if (null != imageView) {                 if (null != bitmap) {                     imageView.setImageBitmap(bitmap);                 }                 else {                     imageView.setImageResource(R.drawable.photo);                 }                 imageView.postDelayed(new Runnable() {                     @Override                     public void run() {                         if (null != weakContext.get()) {                             ((MyActivity) weakContext.get()).setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);                         }                     }                 }, 10000);             }         }     } } 

You may notice that I lock the orientation before taking the photo and unlock it 10 seconds after displaying the photo. That trick is part of my troubleshooting. So here is the situation. The system described above works very well. Problems happen in the following case

  • Say I already have a photo in the ImageView but want to replace it.
  • So I click on the ImageView to take a new photo.
  • If I rotate the device to take the new photo, then when I return the new photo displays briefly before the old photo returns.
  • So I lock to orientation to see what was happening. Here is what I found.
  • The new photo displays for as long as I lock the orientation. As soon as the orientation unlocks (10 sec), the old photo returns.
  • If I leave the activity and the returns, the old photo is still displaying.
  • If I close the app completely and then return, then I see the new photo.

1 Answers

Answers 1

When the device is rotated, the running activity is recreated as well the asyncTask attached to it, probably causing a leak.

You probably need to call the asyncTask inside of a service instead in an activity so the asyncTask is going to be attached to the life cycle of the service.

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment