Камера CWAC: почему мой файл сохранения SimpleCameraHost работает так медленно, я что-то не так делаю?

Как оптимизировать этот кусок кода? Метод saveImage занимает около минуты.

class ObrolSimpleHost extends SimpleCameraHost {
  private final String[] SCAN_TYPES = {"image/webp"};
  private Context context = null;

  public ObrolSimpleHost(Context _ctxt) {
    super(_ctxt);
    this.context = getActivity();
  }

  @Override public void saveImage(PictureTransaction xact, Bitmap bitmap) {
    File photo = getPhotoPath();
    if (photo.exists()) {
      photo.delete();
    }
    try {
      FileOutputStream fos = new FileOutputStream(photo.getPath());
      bitmap.compress(Bitmap.CompressFormat.WEBP, 70, fos);
      fos.flush();
      fos.getFD().sync();
      if (scanSavedImage()) {
        MediaScannerConnection.scanFile(context, new String[]{photo.getPath()}, SCAN_TYPES, null);
      }
    } catch (java.io.IOException e) {
      handleException(e);
    }
  }

  @Override public void saveImage(PictureTransaction xact, byte[] image) {
    // do nothing
  }
}

Я звоню ObrolSimpleHost из CameraFragment:

PictureTransaction xact = new PictureTransaction(getHost());
xact.needBitmap(true);
takePicture(xact);

person Kamol Mavlonov    schedule 05.08.2014    source источник
comment
Используйте Traceview и узнайте, в чем именно заключается ваша проблема. Я бы рекомендовал вам не писать в ByteArrayOutputStream, затем конвертировать в byte[], а затем записывать byte[] в FileOutputStream. Просто передайте FileOutputStream в compress(). Если ничего другого, это поможет с управлением памятью.   -  person CommonsWare    schedule 05.08.2014
comment
@CommonsWare Спасибо, я отредактировал код. Теперь он выглядит лучше?   -  person Kamol Mavlonov    schedule 05.08.2014
comment
Это улучшение. Вы можете захотеть flush() FileOutputStream непосредственно перед sync().   -  person CommonsWare    schedule 05.08.2014
comment
@CommonsWare спасибо, я только что отредактировал код. Да, выглядит намного лучше.   -  person Kamol Mavlonov    schedule 06.08.2014
comment
@CommonsWare выглядит так, как будто это проблема Android с bitmap.compress(Bitmap.CompressFormat.WEBP, 70, fos); Один из вариантов, который я могу рассмотреть, - это уменьшить размер изображения. Знайте, размер изображения на моем устройстве превышает 2–3 МБ. Вопрос в том, как уменьшить сам этот bitmap, чтобы конечное изображение было меньше и чтобы процесс сжатия был быстрее?   -  person Kamol Mavlonov    schedule 07.08.2014
comment
как уменьшить само это растровое изображение, чтобы -- если вы хотите, чтобы изображение имело меньше пикселей, используйте createScaledBitmap() на Bitmap, я думаю. Я лично с этим не играл.   -  person CommonsWare    schedule 07.08.2014
comment
@CommonsWare это работает. Изменяя размер растрового изображения, время сжатия уменьшается. Спасибо за советы и библиотеку.   -  person Kamol Mavlonov    schedule 08.08.2014
comment
@CommonsWare Я добавил свой код в качестве ответа ниже. Имеет ли смысл часть createScaledBitmap()?   -  person Kamol Mavlonov    schedule 08.08.2014
comment
имеет смысл? -- Понятия не имею. Как я уже писал, я не использовал createScaledBitmap().   -  person CommonsWare    schedule 08.08.2014
comment
В любом случае @CommonsWare большое спасибо за вашу библиотеку cwac-camera. Это превосходно!   -  person Kamol Mavlonov    schedule 08.08.2014


Ответы (1)


Вот мой собственный ответ.

Исправлены проблемы, о которых упоминал CommonsWare, и изменение размера bitmap перед сжатием createScaledBitmap:

class ObrolSimpleHost extends SimpleCameraHost {
  private final String[] SCAN_TYPES = {"image/" + imputType};
  private Context context = null;

  public ObrolSimpleHost(Context _ctxt) {
    super(_ctxt);
    this.context = getActivity();
  }

  @Override public void saveImage(PictureTransaction xact, Bitmap bitmap) {
    File photo = getPhotoPath();
    String path = photo.getPath().replace("jpg", imputType);
    if (photo.exists()) {
      photo.delete();
    }

    /**
     * Resizing bitmap, so save some ms in compression
     * http://stackoverflow.com/questions/17839388/creating-a-scaled-bitmap-with-createscaledbitmap-in-android
     */
    final int maxSize = 960;
    int outWidth;
    int outHeight;
    int inWidth = bitmap.getWidth();
    int inHeight = bitmap.getHeight();
    if(inWidth > inHeight){
      outWidth = maxSize;
      outHeight = (inHeight * maxSize) / inWidth;
    } else {
      outHeight = maxSize;
      outWidth = (inWidth * maxSize) / inHeight;
    }
    Bitmap resizedBitmap = Bitmap.createScaledBitmap(bitmap, outWidth, outHeight, false);

    try {
      FileOutputStream fos = new FileOutputStream(path);
      if (imputType.equals("jpeg")) {
        resizedBitmap.compress(Bitmap.CompressFormat.JPEG, 70, fos);
      } else {
        resizedBitmap.compress(Bitmap.CompressFormat.WEBP, 70, fos);
      }
      fos.flush();
      fos.getFD().sync();
      if (scanSavedImage()) {
        MediaScannerConnection.scanFile(context, new String[]{photo.getPath()}, SCAN_TYPES, null);
      }
    } catch (java.io.IOException e) {
      handleException(e);
    }
    EventBus.getDefault().postSticky(new Events.PreparingBitmapEvent(path));
    getActivity().finish();
  }

  @Override public void saveImage(PictureTransaction xact, byte[] image) {
    // do nothing
  }
}

Вместо стандартной bitmap используйте другую библиотеку, которая собирается с помощью JNI.

В моем случае я собираюсь попробовать Roid-WebP.

person Kamol Mavlonov    schedule 08.08.2014