0

I am implementing an AsyncTask in my project. The onPrexecute displays the dialog but along the line the app crashes with the error.

java.lang.RuntimeException: An error occured while executing doInBackground()
Caused by: android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

This is my AsycTask task code

private class CheckTypesTask extends AsyncTask<Void, Void, Void>{
             ProgressDialog asyncDialog = new ProgressDialog(MainActivity.this);
             String typeStatus;


             @Override
             protected void onPreExecute() {
                 //set message of the dialog
                 asyncDialog.setMessage("Please wait");
                 //show dialog
                 asyncDialog.show();
                 super.onPreExecute();
             }

             @Override
             protected Void doInBackground(Void... arg0) {

                 onPhotoTaken(); 

                return null;
             }

             @Override
             protected void onPostExecute(Void result) {

                 //hide the dialog
                 asyncDialog.dismiss();
                 asyncDialog = null;
                 super.onPostExecute(result);
             }

     }

After research I modified my code to this

@Override
             protected Void doInBackground(Void... arg0) {
                 runOnUiThread(new Runnable() {

                        @Override
                        public void run() {
                            onPhotoTaken();     
                        }
                    });
                return null;
             }

EDITTED: This is the onPhoto taken method

public void onPhotoTaken() {

        _taken = true;

        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inSampleSize = 4;

        Bitmap bitmap = BitmapFactory.decodeFile(_path, options);

        try {
            //ProgressDialog dialog = ProgressDialog.show(this, "Loading", "Please wait...", true);
            ExifInterface exif = new ExifInterface(_path);
            int exifOrientation = exif.getAttributeInt(
                    ExifInterface.TAG_ORIENTATION,
                    ExifInterface.ORIENTATION_NORMAL);

            Log.v(TAG, "Orient: " + exifOrientation);

            int rotate = 0;

            switch (exifOrientation) {
            case ExifInterface.ORIENTATION_ROTATE_90:
                rotate = 90;
                break;
            case ExifInterface.ORIENTATION_ROTATE_180:
                rotate = 180;
                break;
            case ExifInterface.ORIENTATION_ROTATE_270:
                rotate = 270;
                break;
            }

            Log.v(TAG, "Rotation: " + rotate);

            if (rotate != 0) {

                // Getting width & height of the given image.
                int w = bitmap.getWidth();
                int h = bitmap.getHeight();

                // Setting pre rotate
                Matrix mtx = new Matrix();
                mtx.preRotate(rotate);

                // Rotating Bitmap
                bitmap = Bitmap.createBitmap(bitmap, 0, 0, w, h, mtx, false);


            }

            // Convert to ARGB_8888, required by tess
            bitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true);
            //dialog.dismiss();

        } catch (IOException e) {
            Log.e(TAG, "Couldn't correct orientation: " + e.toString());
        }
        _image.setImageBitmap(bitmap);

It works well at this point, but my code display a blank screen. Thanks in anticipation

Blaze
  • 2,269
  • 11
  • 40
  • 82
  • 1
    It depend on what doing inside `onPhotoTaken ` method. show code from `onPhotoTaken ` method – ρяσѕρєя K Nov 23 '15 at 13:19
  • all interaction with UI should called from "onPostExecute", "onPreExecute" or "onProgressUpdate" methods. This methods runs in UI thread. Please show your "onPhotoTaken" method – ant Nov 23 '15 at 13:22
  • @ρяσѕρєяK Check my edit – Blaze Nov 23 '15 at 13:25

4 Answers4

4

Create the Bitmap in doInBackground.

@Override
protected Bitmap doInBackground(Void... arg0) {
    return onPhotoTaken(); 
}

...

public Bitmap onPhotoTaken() {
    ....
    return bitmap;
}

and do the UI tasks in onPostExecute:

@Override 
protected void onPostExecute(Bitmap result){
    ...
    _image.setImageBitmap(result);
}

Change AsyncTask<Void, Void, Void> to AsyncTask<Void, Void, Bitmap> also

daemmie
  • 6,361
  • 3
  • 29
  • 45
  • @Override protected Bitmap doInBackground(Void... arg0) { return onPhotoTaken(); } – Blaze Nov 23 '15 at 13:40
  • The return type is incompatible with AsyncTask.doInBackground(Void[]) – Blaze Nov 23 '15 at 13:40
  • change AsyncTask to AsyncTask – daemmie Nov 23 '15 at 13:42
  • Yeah. I have done that, now I am having a leaked window exception – Blaze Nov 23 '15 at 13:45
  • Please where is this bitmap parameter declared... _image.setImageBitmap(bitmap); – Blaze Nov 23 '15 at 13:48
  • Sry didn't change the name. check my edited answer. leaked window exceptions are usually caused by a dialog dismiss call, when the activity is already closing/closed. – daemmie Nov 23 '15 at 13:52
  • So how can I fix this leaked window issue. This is the only issue I am having for now – Blaze Nov 23 '15 at 13:55
  • Check [this](http://stackoverflow.com/questions/2850573/activity-has-leaked-window-that-was-originally-added) out. Also check the log for other exceptions. (Before that one) – daemmie Nov 23 '15 at 13:57
  • Have seen the thread before and my window and dialog is dismissed based on that – Blaze Nov 23 '15 at 14:02
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/95938/discussion-between-oberflansch-and-jng). – daemmie Nov 23 '15 at 14:03
1

You could try using a Handler creating it using new Handler(Looper.getMainLooper());

Use it to run a task, which will be a call to your method.

Not Gabriel
  • 531
  • 4
  • 13
1

You must use _image.setImageBitmap(bitmap); on onPostExecute method.

onPostExecute runs on the UI thread.

As a rule of thumb never modify Views outside of the main(UI) thread.

Gent Ahmeti
  • 1,559
  • 13
  • 17
0

Try this (and make your onPhotoTaken return a Bitmap instead of setting it):

private class CheckTypesTask extends AsyncTask<Void, Void, Bitmap>{
         ProgressDialog asyncDialog = new ProgressDialog(MainActivity.this);
         String typeStatus;


         @Override
         protected void onPreExecute() {
             //set message of the dialog
             asyncDialog.setMessage("Please wait");
             //show dialog
             asyncDialog.show();
             super.onPreExecute();
         }

         @Override
         protected Bitmap doInBackground(Void... arg0) {
            return onPhotoTaken();
         }

         @Override
         protected void onPostExecute(Bitmap result) {

             //hide the dialog
             asyncDialog.dismiss();
             asyncDialog = null;

             if (result != null) {
                  _image.setImageBitmap(result);
             }

             super.onPostExecute(result);
         }

 }

So your doInBackground function returns the bitmap instead of applying it to the image. onPostExecute runs in the UI Thread and you can manipulate UI elements like a Imageview without any problems.

Jörn Buitink
  • 2,906
  • 2
  • 22
  • 33