In my app allows to choose an app on user device such as 'Gallery' to select an image. This image is displayed in an imageview window on the activity screen. Unfortunately, when I turn my phone and the orientation changes, the image is lost and they have to go select it again.
How do I save the bitmap image and have it re-displayed after the orientation change?
Here is the code function I use to let the user pick an image app, pick an image, and display the image in the imageview window.
@Override
protected void onActivityResult( int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK){
Uri targetUri = data.getData();
textTargetUri.setText(targetUri.toString());
Bitmap bitmap;
try {
bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(targetUri));
targetImage.setImageBitmap(bitmap);
}
catch (FileNotFoundException e){
e.printStackTrace();
}
}
}
The above function is initialised within my onCreate in response to a button click shown in this code:
Button buttonLoadImage = (Button)findViewById(R.id.loadimage);
textTargetUri = (TextView)findViewById(R.id.targeturi);
targetImage = (ImageView)findViewById(R.id.targetimage);
buttonLoadImage.setOnClickListener(new Button.OnClickListener(){
@Override
public void onClick(View arg0) {
Intent intent = new Intent(Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, 0);
}});
Essentially, I just need to put this boolean in my onCreate and have it put the image back in the window. It also displays text showing where the image was located on the device but that is not as important to me as being able to have the image stay on the screen.
if (savedInstanceState != null) {
}
But it seems to wipe the data after the orientation change? I have no idea how to save the data and restore it to be used within that boolean. I appreciate any advice, code, or links you can provide!
UPDATE:
Using both of advises in comments, as well as some code I had found from previous research, I was able to compile a solution. However, while it solved the first issue, it spawned another which I will describe after showing the code I used to fix the initial problem.
I found that I had 2 options available for the restoration portion.
Either I could place this in the onCreate:
if (savedInstanceState != null) {
//if there is a bundle, use the saved image resource (if one is there)
image = savedInstanceState.getParcelable("BitmapImage");
targetImage.setImageBitmap(image);
textTargetUri.setText(savedInstanceState.getString("path_to_picture"));R.drawable.camera_button);
}
This allowed me to have both the image as well as the path to it on the device to be re-displayed on my activity.
Or I could have this after the onCreate
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState){
image = savedInstanceState.getParcelable("BitmapImage");
targetImage.setImageBitmap(image);
textTargetUri.setText(savedInstanceState.getString("path_to_picture"));
}
and the saving function that I used was
@Override
public void onSaveInstanceState(Bundle savedInstanceState){
super.onSaveInstanceState(savedInstanceState);
savedInstanceState.putParcelable("BitmapImage", bitmap);
savedInstanceState.putString("path_to_picture", picture_location);
}
To clarify where picture_location came from, back in my onActivityResult function I added a line and changed another to save the path string
if (resultCode == RESULT_OK){
Uri targetUri = data.getData();
picture_location = targetUri.toString();
textTargetUri.setText(picture_location);
As for variables initialized before the onCreate,
Bitmap image;
Bitmap bitmap;
String picture_location;
Now, I realize this has gotten rather lengthy but I hope it will help others who may have a similar problem. As for the new issue that I mentioned earlier, when I rotate my android device, it does in fact keep the data and re-display it as I was trying to do. However, when I rotate the screen again, the original issue arises; the data seems to be lost and is not displayed on the screen.
I would hope there is a much more simple fix so that the save and restore functions keep working no matter how many times the screen orientation changes?
Bitmap image;
public void onCreat(..){
if (savedInstanceState != null) {
image = (Bitmap) savedInstanceState.getParcelableExtra("BitmapImage");;
} else {
image = yourBitmapImage;
}
}
@Override public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putExtra("BitmapImage", bitmap);
}
I think it costs too much if you save a Bitmap
in onSaveInstanceState
,as onSaveInstanceState
will be called before onStop
every time,and Bitmap
is a big thing.
I think is better to save a URI
in onSaveInstanceState
。
Uri mUri;
ImageView mImageView;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
if (savedInstanceState != null){
mUri = savedInstanceState.getParcelable("uri");
mImageView.setImageURI(mUri);
}
}
protected void onActivityResult( int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK){
Uri targetUri = data.getData();
...
mUri = targetUri;
}
}
public void onSaveInstanceState(Bundle outState) {
if (mURI !=null) {
outState.putParcelable("uri", mUri);
}
}
We should never use the above way to save our heavy objects such as image or bitmap it is always advisable to use the fragments. Have a look at this an easy implementation of how to retain the fragment https://developer.android.com/guide/topics/resources/runtime-changes.html#RetainingAnObject
according to the developer guide https://developer.android.com/topic/performance/graphics/cache-bitmap.html.
the recommended way is to use setRetainInstance(true) in the fragment to retain images.
refer to section on "Handle Configuration Changes"
Runtime configuration changes, such as a screen orientation change, cause Android to destroy and restart the running activity with the new configuration (For more information about this behavior, see Handling Runtime Changes). You want to avoid having to process all your images again so the user has a smooth and fast experience when a configuration change occurs.
Luckily, you have a nice memory cache of bitmaps that you built in the Use a Memory Cache section. This cache can be passed through to the new activity instance using a Fragment which is preserved by calling setRetainInstance(true)). After the activity has been recreated, this retained Fragment is reattached and you gain access to the existing cache object, allowing images to be quickly fetched and re-populated into the ImageView objects.
private LruCache<String, Bitmap> mMemoryCache;
@Override
protected void onCreate(Bundle savedInstanceState) {
...
RetainFragment retainFragment =
RetainFragment.findOrCreateRetainFragment(getFragmentManager());
mMemoryCache = retainFragment.mRetainedCache;
if (mMemoryCache == null) {
mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
... // Initialize cache here as usual
}
retainFragment.mRetainedCache = mMemoryCache;
}
...
}
class RetainFragment extends Fragment {
private static final String TAG = "RetainFragment";
public LruCache<String, Bitmap> mRetainedCache;
public RetainFragment() {}
public static RetainFragment findOrCreateRetainFragment(FragmentManager fm) {
RetainFragment fragment = (RetainFragment) fm.findFragmentByTag(TAG);
if (fragment == null) {
fragment = new RetainFragment();
fm.beginTransaction().add(fragment, TAG).commit();
}
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With