Reputation: 2339
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
Upvotes: 0
Views: 2025
Reputation: 2916
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.
Upvotes: 0
Reputation: 6460
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
Upvotes: 4
Reputation: 1599
You must use _image.setImageBitmap(bitmap);
on onPostExecute
method.
onPostExecute runs on the UI thread.
As a rule of thumb never modify View
s outside of the main(UI)
thread.
Upvotes: 1
Reputation: 561
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.
Upvotes: 1