Восстановить изображение в ImageView при изменении ориентации

Я пишу простое приложение, которое устанавливает изображение в ImageView через Intent, вызывающее камеру. Но когда я меняю ориентацию, изображение исчезает. Я уже пробовал эти вопросы Q1, Q2. В предыдущих вопросах предлагается либо использовать onSaveInstanceState, либо Сохранение объекта во время изменения конфигурации.

Но в документах по Android я прочитал:

вы можете столкнуться с ситуацией, в которой перезапуск вашего приложения и восстановление значительных объемов данных могут быть дорогостоящими и создавать плохое взаимодействие с пользователем.

Таким образом, если Bitmap считается значительным объемом данных, мне нужно будет использовать setRetainInstance, но в документации сказано:

Хотя вы можете хранить любой объект, вы никогда не должны передавать объект, связанный с действием, например Drawable, адаптер, представление или любой другой объект, связанный с контекстом.

Какой подход я должен использовать, чтобы иметь возможность восстановить изображение при изменении ориентации?

Что я сделал до сих пор

private ImageView mPhotoImgage;
private Bitmap mCameraData;

onCreate {
    mPhotoImgage = (ImageView) findViewById(R.id.photoResultImage);

    if (savedInstanceState != null){
        mPhotoImgage.setImageBitmap((Bitmap)savedInstanceState.getParcelable(IMAGE_RESOURCE));
    }
}

onResume{
    if (mCameraData != null){
        mPhotoImgage.setImageBitmap(mCameraData);
    }
    super.onResume();
}

onSaveInstanceState{
    outState.putParcelable(IMAGE_RESOURCE, mCameraData);
    super.onSaveInstanceState(outState);
}

Но после двух смен ориентации изображение исчезает.


person ElBaulP    schedule 30.05.2014    source источник


Ответы (2)


Вместо этого вы можете попросить камеру сохранить захваченное изображение в файл на внешнем хранилище (если оно доступно). Вы сообщаете ему, где сохранить изображение, и это означает, что вы можете сохранить URI файла в onSaveInstanceState и загрузить его из этого URI при восстановлении состояния.

Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(context.getExternalFilesDir(null), "randomfilename")));
startActivityForResult(cameraIntent, RC_CAMERA);

Вы должны отслеживать, когда файл больше не нужен, и удалять его.

Еще одним преимуществом этого подхода является то, что вы можете узнать размеры изображения до того, как оно будет загружено в память.

person Dave Morrissey    schedule 30.05.2014
comment
Я не знаю, почему, помещая эту строку putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(this.getCacheDir(), "randomfilename"))), приложение камеры никогда не возвращается. Я делаю фото, а кнопка принять фото и закрыть приложение камеры ничего не делает - person ElBaulP; 31.05.2014
comment
Я отредактировал свой ответ, чтобы удалить предложение использовать кеш приложения, который является частным, поэтому камера не может писать в него. Должна быть возможность предоставить разрешение, но мне не удалось заставить это работать. Код, который вы разместили, не завершен, но я думаю, что вы, возможно, не устанавливаете mCameraData в onCreate, что объясняет, почему изображение исчезает при втором изменении ориентации. - person Dave Morrissey; 31.05.2014
comment
Теперь я получаю NPE при получении данных на onActivityResult, должен ли я получить фотографию там с mPhotoImgage.setImageURI((Uri)data.getExtras().get("data")) - person ElBaulP; 31.05.2014
comment
Насколько я знаю, URI не будет возвращен в данных намерения (отладка для подтверждения), вам нужно запомнить URI, который вы отправили в намерении, и сохранить его во фрагменте или действии, восстанавливая его после изменения ориентации с помощью onSaveInstanceState . - person Dave Morrissey; 31.05.2014
comment
Ок, спасибо, попробую - person ElBaulP; 31.05.2014

Вы должны использовать метод onResume для установки изображения при возобновлении активности.

@Override
protected void onResume() {
    //your code here
    super.onResume();
}

Вам не нужен сохраненный экземпляр, просто скопируйте код, который вы используете в onCreate, чтобы установить изображение в onResume, и оно должно работать.

например, если у вас есть onCreate :

 imageView im.setImageResource(R.drawable.image);

Используйте его для onResume:

@Override
protected void onResume() {
    imageView im.setImageResource(R.drawable.image);
    super.onResume();
}
person mremremre1    schedule 30.05.2014
comment
Я получаю изображение через камеру с помощью data.getExtras().get("data"). - person ElBaulP; 31.05.2014
comment
Вы можете попробовать сохранить изображение в формате jpeg и загрузить его. Я даю вам ссылку, чтобы загрузить мой простой тестовый проект, чтобы увидеть, как вы можете снимать в формате jpeg, не открывая приложение камеры. Используйте код по своему усмотрению и модифицируйте его, чтобы он делал то, что вам нужно 4shared.com/ rar/v-ZQPybcce/Test.html - person mremremre1; 31.05.2014