0
votes

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

4
It depend on what doing inside onPhotoTaken method. show code from onPhotoTaken methodρяσѕρєя K
all interaction with UI should called from "onPostExecute", "onPreExecute" or "onProgressUpdate" methods. This methods runs in UI thread. Please show your "onPhotoTaken" methodant
@ρяσѕρєяK Check my editBlaze

4 Answers

3
votes

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

1
votes

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.

1
votes

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.

0
votes

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.