#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();
}
});
}
}
Пожалуйста, дайте мне знать, если это может вам помочь.