2015-11-23 6 views
0

Я пытаюсь внедрить AsyncTak, чтобы информировать пользователя о том, что фоновая операция выполняется при съемке. AyncTask способен отображать функцию setMessage, но вдоль линии приложение падает и выводит следующее сообщение об ошибкеРеализация AsyncTask: ошибка при выполнении doInBackground() throws Исключение времени выполнения

Caused by: android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views. 

Это полная кодовая моего AsyncTask

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


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

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

       //don't touch dialog here it'll break the application 
       //do some lengthy stuff like calling login webservice 
       onPhotoTaken(); 

       return null; 
      } 

      @Override 
      protected void onPostExecute(Void result) { 
       //hide the dialog 
       asyncDialog.dismiss(); 

       super.onPostExecute(result); 
      } 

    } 

Тогда я звоню AsyncTask в onActivity результат таким образом:

if (resultCode == -1) { 

      //onPhotoTaken(); 
      (new MainActivity.CheckTypesTask()).execute(); 

     } else { 
      Log.v(TAG, "User cancelled"); 
     } 
    } 

Editted: Это код onPhotoTaken и определяется в классе MainActivity.

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()); 
     } 

Пожалуйста, что может быть неправильным?

+1

Показать метод 'onPhotoTaken' код –

+0

почтовый индекс onPhotoTaken и где вы определяете его метод в подклассе или основном классе? – curiousMind

+0

Пожалуйста, взгляните на функцию onPhotoTaken – Blaze

ответ

1

Вы пытаетесь получить доступ к компонентам пользовательского интерфейса (Вид) из фонового потока в вашем случае внутри метода doInBackground(). Вы - not allowed to do that.

Обратитесь к функции из onPostExecute()

+0

Итак, где я должен назвать функцию onPhotoTaken – Blaze

+0

Проверка Отредактированный ответ –

+0

Где этот дескриптор, исходящий от >>>> runOnUiThread – Blaze

0

Попробуйте этот код

Это макет, который содержит триггер для захвата изображения и ImageView, чтобы отобразить захваченное изображение: -

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:tools="http://schemas.android.com/tools" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:fillViewport="true" 
    android:orientation="vertical" 
    tools:context="com.serveroverload.cube.ui.HomeActivity" > 

    <ImageView 
     android:id="@+id/preview" 
     android:layout_width="match_parent" 
     android:layout_height="match_parent" 
     android:layout_above="@+id/take_picture" 
     android:layout_alignParentTop="true" 
     android:layout_margin="5dp" /> 

    <ImageView 
     android:id="@+id/take_picture" 
     android:layout_width="50dp" 
     android:layout_height="50dp" 
     android:layout_alignParentBottom="true" 
     android:layout_centerHorizontal="true" 
     android:layout_gravity="center" 
     android:layout_margin="10dp" 
     android:background="@drawable/flat_selector" 
     android:padding="5dp" 
     android:scaleType="fitXY" 
     android:src="@drawable/take_pic" /> 

</RelativeLayout> 

Это ваш андроид с требуемыми разрешениями

<?xml version="1.0" encoding="utf-8"?> 
<manifest xmlns:android="http://schemas.android.com/apk/res/android" 
    package="com.example.camtest" 
    android:versionCode="1" 
    android:versionName="1.0" > 

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> 
    <uses-permission android:name="android.permission.CAMERA" /> 
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> 

    <uses-sdk 
     android:minSdkVersion="8" 
     android:targetSdkVersion="21" /> 

    <application 
     android:allowBackup="true" 
     android:icon="@drawable/ic_launcher" 
     android:label="@string/app_name" 
     android:theme="@style/AppTheme" > 
     <activity 
      android:name="com.serveroverload.cube.ui.HomeActivity" 
      android:label="@string/app_name" > 
      <intent-filter> 
       <action android:name="android.intent.action.MAIN" /> 

       <category android:name="android.intent.category.LAUNCHER" /> 
      </intent-filter> 
     </activity> 
    </application> 

</manifest> 

Это камера класс обработчика повторно размера и поворачивать изображения, если это необходимо в данный момент он будет пробовать изображение в 1024x1280 для UI

public class CamerHandler { 

    private CamerHandler() { 

     getAllImages(); 
    } 

    private static CamerHandler camerHandler; 

    public static CamerHandler GetCamerHandlerInstance() { 
     if (null == camerHandler) { 
      camerHandler = new CamerHandler(); 
     } 
     return camerHandler; 
    } 

    private static final String CAM_DIRECTORY = "CamDirectory"; 
    private static final int MAX_HEIGHT = 1024; 
    private static final int MAX_WIDTH = 1280; 

    private ArrayList<File> imageURL = new ArrayList<File>(); 

    public ArrayList<File> getImageURL() { 
     return imageURL; 
    } 

    public void setImageURL(ArrayList<File> imageURL) { 
     this.imageURL = imageURL; 
    } 

    public void getAllImages() { 

     imageURL.clear(); 

     File folder = new File(getImageDirectory()); 
     File[] listOfFiles = folder.listFiles(); 

     if (null != listOfFiles && listOfFiles.length != 0) { 

      for (int i = 0; i < listOfFiles.length; i++) { 
       if (listOfFiles[i].isFile()) { 

        imageURL.add(listOfFiles[i]); 

        System.out.println("File " + listOfFiles[i].getName()); 
       } else if (listOfFiles[i].isDirectory()) { 
        System.out.println("Directory " + listOfFiles[i].getName()); 
       } 
      } 
     } 
    } 

    /** 
    * This method is responsible for solving the rotation issue if exist. Also 
    * scale the images to 1024x1024 resolution 
    * 
    * @param context 
    *   The current context 
    * @param selectedImage 
    *   The Image URI 
    * @return Bitmap image results 
    * @throws IOException 
    */ 
    public Bitmap handleSamplingAndRotationBitmap(Context context, Uri selectedImage) throws IOException { 

     // First decode with inJustDecodeBounds=true to check dimensions 
     final BitmapFactory.Options options = new BitmapFactory.Options(); 
     options.inJustDecodeBounds = true; 

     InputStream imageStream = context.getContentResolver().openInputStream(selectedImage); 
     BitmapFactory.decodeStream(imageStream, null, options); 
     imageStream.close(); 

     // Calculate inSampleSize 
     options.inSampleSize = calculateInSampleSize(options, MAX_WIDTH, MAX_HEIGHT); 

     // Decode bitmap with inSampleSize set 
     options.inJustDecodeBounds = false; 
     imageStream = context.getContentResolver().openInputStream(selectedImage); 
     Bitmap img = BitmapFactory.decodeStream(imageStream, null, options); 

     // img = rotateImageIfRequired(img, selectedImage); 

     img = rotateBitmap(context, img, selectedImage); 
     return img; 
    } 

    public Bitmap rotateBitmap(Context context, Bitmap bitmap, Uri selectedImage) { 

     ExifInterface exif; 
     try { 
      exif = new ExifInterface(selectedImage.getPath()); 

      int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED); 

      Matrix matrix = new Matrix(); 
      switch (orientation) { 
      case ExifInterface.ORIENTATION_NORMAL: 
       return bitmap; 
      case ExifInterface.ORIENTATION_FLIP_HORIZONTAL: 
       matrix.setScale(-1, 1); 
       break; 
      case ExifInterface.ORIENTATION_ROTATE_180: 
       matrix.setRotate(180); 
       break; 
      case ExifInterface.ORIENTATION_FLIP_VERTICAL: 
       matrix.setRotate(180); 
       matrix.postScale(-1, 1); 
       break; 
      case ExifInterface.ORIENTATION_TRANSPOSE: 
       matrix.setRotate(90); 
       matrix.postScale(-1, 1); 
       break; 
      case ExifInterface.ORIENTATION_ROTATE_90: 
       matrix.setRotate(90); 
       break; 
      case ExifInterface.ORIENTATION_TRANSVERSE: 
       matrix.setRotate(-90); 
       matrix.postScale(-1, 1); 
       break; 
      case ExifInterface.ORIENTATION_ROTATE_270: 
       matrix.setRotate(-90); 
       break; 
      default: 
       return bitmap; 
      } 
      // try { 
      Bitmap bmRotated = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); 
      bitmap.recycle(); 
      return bmRotated; 

     } catch (IOException e) { 

      e.printStackTrace(); 

      return null; 
     } catch (OutOfMemoryError e) { 
      e.printStackTrace(); 
      return null; 
     } 
    } 

    /** 
    * Calculate an inSampleSize for use in a {@link BitmapFactory.Options} 
    * object when decoding bitmaps using the decode* methods from 
    * {@link BitmapFactory}. This implementation calculates the closest 
    * inSampleSize that will result in the final decoded bitmap having a width 
    * and height equal to or larger than the requested width and height. This 
    * implementation does not ensure a power of 2 is returned for inSampleSize 
    * which can be faster when decoding but results in a larger bitmap which 
    * isn't as useful for caching purposes. 
    * 
    * @param options 
    *   An options object with out* params already populated (run 
    *   through a decode* method with inJustDecodeBounds==true 
    * @param reqWidth 
    *   The requested width of the resulting bitmap 
    * @param reqHeight 
    *   The requested height of the resulting bitmap 
    * @return The value to be used for inSampleSize 
    */ 
    private int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { 
     // Raw height and width of image 
     final int height = options.outHeight; 
     final int width = options.outWidth; 
     int inSampleSize = 1; 

     if (height > reqHeight || width > reqWidth) { 

      // Calculate ratios of height and width to requested height and 
      // width 
      final int heightRatio = Math.round((float) height/(float) reqHeight); 
      final int widthRatio = Math.round((float) width/(float) reqWidth); 

      // Choose the smallest ratio as inSampleSize value, this will 
      // guarantee a final image 
      // with both dimensions larger than or equal to the requested height 
      // and width. 
      inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio; 

      // This offers some additional logic in case the image has a strange 
      // aspect ratio. For example, a panorama may have a much larger 
      // width than height. In these cases the total pixels might still 
      // end up being too large to fit comfortably in memory, so we should 
      // be more aggressive with sample down the image (=larger 
      // inSampleSize). 

      final float totalPixels = width * height; 

      // Anything more than 2x the requested pixels we'll sample down 
      // further 
      final float totalReqPixelsCap = reqWidth * reqHeight * 2; 

      while (totalPixels/(inSampleSize * inSampleSize) > totalReqPixelsCap) { 
       inSampleSize++; 
      } 
     } 
     return inSampleSize; 
    } 

    public void openGallery(Context context) { 
     Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("content://media/internal/images/media")); 
     intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 
     context.startActivity(intent); 
    } 

    private void convertToBase64(Bitmap bitmap) { 
     ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); 
     bitmap.compress(CompressFormat.JPEG, 30, byteArrayOutputStream); 
     byte[] byteArray = byteArrayOutputStream.toByteArray(); 
     String encoded = Base64.encodeToString(byteArray, Base64.NO_WRAP); 

     // bitmap.recycle(); 

     encoded = null; 
     byteArray = null; 
    } 

    public String getImageDirectory() { 

     return createDirIfNotExists().getAbsolutePath(); 
    } 

    public File createDirIfNotExists() { 

     File imageDirectory = new File(Environment.getExternalStorageDirectory(), CAM_DIRECTORY); 
     if (!imageDirectory.exists()) { 

      if (!imageDirectory.mkdirs()) { 

       Log.e("imageDirectory:: ", "Problem creating Image folder"); 
      } 
     } 
     return imageDirectory; 
    } 
} 

и это код деятельности, которые фотографируют и выполнять все вниз выборку и поворот изображения в фоновом режиме, прежде чем обновления на пользовательском интерфейсе

public class HomeActivity extends Activity { 

    static final int REQUEST_IMAGE_CAPTURE = 1; 
    private ImageView previewLayout; 
    private static final String TAG = "MainActivity"; 

    static Uri capturedImageUri = null; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_home); 

     // Imageview to display Image 
     previewLayout = (ImageView) findViewById(R.id.preview); 

     findViewById(R.id.take_picture).setOnClickListener(
       new OnClickListener() { 

        @Override 
        public void onClick(View v) { 
         dispatchTakePictureIntent(); 

        } 
       }); 

    } 

    private void dispatchTakePictureIntent() { 

     Intent intent = new Intent("android.media.action.IMAGE_CAPTURE"); 

     if (intent.resolveActivity(getPackageManager()) != null) { 

      Calendar cal = Calendar.getInstance(); 

      // store image in new File in image directory 
      File file = new File(CamerHandler.GetCamerHandlerInstance() 
        .getImageDirectory(), (cal.getTimeInMillis() + ".png")); 

      if (!file.exists()) { 
       try { 
        file.createNewFile(); 
       } catch (IOException e) { 
        // TODO Auto-generated catch block 
        e.printStackTrace(); 
        Toast.makeText(getApplicationContext(), 
          "Failed to make file", 500).show(); 
       } 
      } else { 
       file.delete(); 
       try { 
        file.createNewFile(); 
       } catch (IOException e) { 
        // TODO Auto-generated catch block 
        e.printStackTrace(); 
        Toast.makeText(getApplicationContext(), 
          "Failed to make file", 500).show(); 
       } 
      } 

      capturedImageUri = Uri.fromFile(file); 
      intent.putExtra(MediaStore.EXTRA_OUTPUT, capturedImageUri); 
      startActivityForResult(intent, REQUEST_IMAGE_CAPTURE); 
     } 

    } 

    @SuppressLint("NewApi") 
    @Override 
    public void onActivityResult(int requestCode, int resultCode, Intent data) { 
     super.onActivityResult(requestCode, resultCode, data); 

     if (resultCode == RESULT_OK && requestCode == REQUEST_IMAGE_CAPTURE) { 

      // update file in gallery 
      sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, 
        capturedImageUri)); 

      // Downsample image before displaying in imageview to avoi OOM 
      // exception 
      new LoadBitMap(previewLayout, HomeActivity.this) 
        .execute(capturedImageUri); 

     } else { 
      Log.e(TAG, "FAILED TO TAKE IMAGE"); 
     } 
    } 

} 

class LoadBitMap extends AsyncTask<Uri, Void, Void> { 

    public LoadBitMap(ImageView preview, Context context) { 
     this.prevImageView = preview; 
     this.mContext = context; 
    } 

    private Bitmap bitmap = null; 
    private ImageView prevImageView; 
    private Context mContext; 

    @Override 
    protected Void doInBackground(Uri... params) { 
     try { 

      bitmap = CamerHandler.GetCamerHandlerInstance() 
        .handleSamplingAndRotationBitmap(mContext, params[0]); 

     } catch (IOException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
     return null; 
    } 

    @Override 
    protected void onPostExecute(Void result) { 
     if (null != bitmap) { 

    prevImageView.setBackground(new BitmapDrawable(mContext 
        .getResources(), bitmap)); 
     } 
     super.onPostExecute(result); 
    } 
} 

Очки отметить здесь вы можете использовать Picasso или Glide для загрузки изображения задачи, как мы уже Uri путь в captureuri переменной.

Смежные вопросы