AsyncTask не завершается после запуска doInBackground Android

#java #android #android-asynctask #android-camera

#java #Android #android-asynctask #android-камера

Вопрос:

Я запускаю AsyncTask в своем TakePic классе. В doInBackground функции я использую Camera.takePicture функцию. На данный момент все в порядке; я делаю снимок и сохраняю файл в /sdcard/%d.jpg это место.

 public class TakePic extends AsyncTask<CameraPreview, String, Integer> {

  @Override
  protected Integer doInBackground(final CameraPreview... params) {
          params[0].camera.takePicture(null,null,new Camera.PictureCallback() {
              @Override
              public void onPictureTaken(byte[] data, Camera camera) {
                  FileOutputStream outStream = null;
                  try {
                      outStream = new FileOutputStream(String.format("/sdcard/%d.jpg", System.currentTimeMillis()));
                      outStream.write(data);
                      outStream.close();
                      Log.e("picture_saved", "Picture has been saved succesfully: "   data.length);
                      camera.release();
                  } catch (FileNotFoundException e) {
                      e.printStackTrace();
                      Log.e("file_not_found: ","couldn't save the file " e.getMessage());
                  } catch (IOException e) {
                      e.printStackTrace();
                      Log.e("IOexception: ","couldn't save the file " e.getMessage());
                  }
              }
          });
      Log.e("doinback_compt:" ,"done");
      return 0;
  }

   @Override
   protected void onPostExecute(Integer integer) {
   }
}
  

Но после того, как я выполняю эту AsyncTask в своем основном классе, она не завершается. Мне нужно выполнить другую функцию, и я должен дождаться завершения этой AsyncTask. Поэтому после выполнения AsyncTask я использую цикл while для проверки состояния задачи, но статус никогда не меняется.

     TakePic backCam=new TakePic();
    backCam.execute(cameraPreview_front);
    while (backCam.getStatus()!= AsyncTask.Status.FINISHED){
        *waiting for async task to finish*
    }
  

Он застрял в цикле while, и мой logcat показывает, что doInBackground работает нормально, и файл сохраняется в этом месте.

 10-10 18:06:14.497 15975-15975/com.urun.camera_test E/clicked_capture:: ok
10-10 18:06:14.633 15975-16452/com.urun.camera_test E/doinback_compt:: done
  

Итак, что мне нужно сделать? Заранее спасибо.

Комментарии:

1. Почему вы думаете, что он не завершается?

2. Мне кажется, что у вас неправильная проверка в цикле while. И из-за этого ваш *waiting for async task to finish* компьютер работает некорректно

3. Это неправильный способ использования AsyncTask , поскольку ваш while цикл эффективно блокирует поток пользовательского интерфейса. Переместите код, который вы хотите выполнить после AsyncTask завершения onPostExecute() .

4. Я использую отладку в приложении, и я поставил точку останова в while, и я проверил, что он переходит в цикл примерно 40 раз (я останавливаюсь на этом этапе). Он завершает выполнение функции doInBackground, но статус всегда возвращается как «ВЫПОЛНЯЕТСЯ».

5. @Egor То, что ты говоришь, правда, но сейчас это не мой приоритет, мне просто нужно подождать, поэтому я использую его так, и мне нужно запустить другую AsyncTask после завершения этой задачи, поэтому я не могу сделать это с помощью onPostExecute().

Ответ №1:

Это обрабатывается странным образом. Первый CameraPreview.camera.takePicture() будет выполняться в фоновом режиме, поэтому вы передаете его Camera.PictureCallback в конструктор. Вы просто укладываете туда потоки. Попробуйте это в основном потоке

 [yourCameraPreview].camera.takePicture(null,null,new Camera.PictureCallback() {
    @Override
    public void onPictureTaken(byte[] data, Camera camera) {
        camera.release();
        // Read below
    }
}
  

Теперь мы можем просто дождаться обратного вызова picture. Как только мы получим данные обратно, мы можем вызвать AsyncTask, чтобы сохранить их в файле, и применить наш собственный обратный вызов, чтобы дождаться его ответа. Мы можем использовать статический внутренний класс, чтобы все это работало.

 private static class ImageSaver extends AsyncTask<Byte, Void, Exception>{

    public interface ImageSavedListener{
        void onImageSaved(Exception e);
    }

    private ImageSavedListener mCallback;

    public ImageSaver(ImageSavedListener callback){
        mCallback = callback;
    }

    @Override
    protected void doInBackground(Byte... data){
        if(data == null || data.length == 0)
            return new Exception("Data returned from camera is invalid");

        try {
            FileOutputStream outStream = new FileOutputStream(String.format("/sdcard/%d.jpg", System.currentTimeMillis()));
            outStream.write(data);
            outStream.close();
            Log.d("picture_saved", "Picture has been saved succesfully: "   data.length);
        } catch (FileNotFoundException e) {
            Log.e("file_not_found: ","couldn't save the file " e.getMessage());
            return e;
        } catch (IOException e) {
            Log.e("IOexception: ","couldn't save the file " e.getMessage());
            return e;
        }

        return null;
    }

    @Override
    protected void onPostExecute(Exception e){
        if(mCallback != null)
            mCallback.onImageSaved(e);
    }
}
  

Затем вызовите его следующим образом (в разделе, указанном Read below выше)

 new ImageSaver(new ImageSavedListener(){
    @Override
    public void onImageSaved(Exception e){
        if(e == null){
            // do what you want
        }
        else
            e.printStackTrace();
    }
}).execute(data);
  

Это сделает снимок в фоновом режиме, дождется ответа, сохранит ответ в файл в фоновом режиме, дождется ответа, а затем сделает то, что вы хотите, на основе исключения, возвращенного после сохранения.

Ответ №2:

Если вам нужно выполнить какой-то код после AsyncTask выполнения, я могу предложить одно решение. Вставьте свой *waiting for async task to finish* код Runnable и отправьте его в качестве параметра в асинхронную задачу (но это не лучшее решение, просто быстрое)

     new AsyncTask<Object, Void, Runnable>() {
        @Override
        protected Runnable doInBackground(Object... runnables) {
            CameraPreview cp = (CameraPreview) runnables[0];
            Runnable callback = (Runnable) runnables[1];

            /**your main logic*/

            return callback;
        }

        @Override
        protected void onPostExecute(Runnable aVoid) {
            super.onPostExecute(aVoid);
            if (aVoid != null)
                aVoid.run();
        }
    }.execute( cameraPreview , new Runnable() {
        @Override
        public void run() {
            /**code to run();**/
        }
    });
  

Возможная проблема с вашим текущим кодом :

Вы не выполняете super.onPostExecute(integer);

Попробуйте изменить код на

 @Override
protected void onPostExecute(Integer integer) {
 super.onPostExecute(integer);
}
  

Комментарии:

1. Хорошо, куда я собираюсь передать свой собственный параметр CameraPreview?

2. @AhmetUrun в качестве первого параметра. Обновлена AsyncTask

3. Серьезно? 1. прочитайте обновление 2. опубликуйте отредактированный код. Это пример. Не вариант копирования / вставки

Ответ №3:

Как указывалось ранее, не имеет смысла блокировать ваш основной поток, ожидающий выполнения определенного события. Однако, если вы все еще хотите получить что-то из своей AsyncTask, я бы посоветовал вам использовать FutureTask

Ответ №4:

Как я вижу в вашем коде, AsyncTask завершается правильно. Проблема в том, что вы делаете снимок внутри AsyncTask. Так что, пока камера.PictureCallback ожидает изображения, задача завершается сразу после вызова метода «takePicture».

Что я должен сделать, это что-то вроде этого (это всего лишь подход):

   public class TakePic {

    public interface MyTakePicListener{
        void onPictureTaken();
        void onPictureError();
    }

    private MyTakePicListener myListener; 


    public void takePicture(CameraPreview cameraPreview) {
        cameraPreview.camera.takePicture(null, null, new Camera.PictureCallback() {
            @Override
            public void onPictureTaken(final byte[] data, final Camera camera) {

                new Thread(new Runnable() {
                    @Override
                    public void run() {

                        FileOutputStream outStream = null;
                        try {
                            outStream = new FileOutputStream(String.format("/sdcard/%d.jpg", System.currentTimeMillis()));
                            outStream.write(data);
                            outStream.close();
                            Log.e("picture_saved", "Picture has been saved succesfully: "   data.length);
                            camera.release();

                            HERE you should call a listener to continue with your success code
                            myListener.onPictureTaken();
                        } catch (FileNotFoundException e) {
                            e.printStackTrace();
                            Log.e("file_not_found: ", "couldn't save the file "   e.getMessage());

                            HERE you should call a listener to continue with your error code
                            myListener.onPictureError();
                        } catch (IOException e) {
                            e.printStackTrace();
                            Log.e("IOexception: ", "couldn't save the file "   e.getMessage());

                            HERE you should call a listener to continue with your error code
                            myListener.onPictureError();
                        }

                        Log.e("doinback_compt:", "done");



                    }
                }).start();
            }

        });
    }

}
  

Пожалуйста, дайте мне знать, если это может вам помочь.