My app is supposed to first displays an image, when a button is pressed, another image is displayed in the image view. However, when the screen is rotated, the imageView displays the old image. How should I go about fixing this? (bits is the Bitmap loaded into imageView on create)
My code is below:
RGBToBitmap(rgb.getWindow(), bits); //this loads a new image into bits
imageView.setImageBitmap(bits);
I suppose you are setting the first image of your ImageView in the onCreate or onStart method of your Activity.
Upon rotating the screen, the onCreate and onStart methods get called again, and therefore your ImageView displays the first image again.
In order to save your Activity state, have a look at this:
http://developer.android.com/reference/android/app/Activity.html#SavingPersistentState
This could be a possible solution:
Bitmap image = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
image = (Bitmap) getLastNonConfigurationInstance();
if(bitmap == null){
image = downloadImage();
}
setImage(bitmap);
}
#Override
public Object onRetainNonConfigurationInstance() {
return bitmap;
}
You can also read into this method when ur using fragments:
Fragment.setRetainInstance
Or the Bundle: (onSaveInstanceState(Bundle) is also available in your Activity)
//Save it onSaveInstanceState:
#Override
public void onSaveInstanceState(Bundle toSave) {
super.onSaveInstanceState(toSave);
toSave.putParcelable("bitmap", bitmap);
}
//nd get it back onCreate:
#Override
public void onCreate(Bundle savedState) {
super.onCreate(savedState);
if (savedState != null) bitmap = savedState.getParcelable("bitmap");
}
Related
I put an imageview to load an image of a url, it is when I click on a button it passes to the next url, thus changing the image.
the problem is that when I rotate the screen it returns to the first image displayed.
I tried to do an if with incremented counter but it deletes the variable and returns to the first one again.
someone knows how to save the value of the "next" variable so when the screen rotates it keeps the value saved, or knows another way to keep the last image saved.
api picasso
code complete
private SmartImageView smartImage;
private Button btn;
private int proxima = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_redacao_nota_1000);
if (proxima == 0) {
smartImage = (SmartImageView) findViewById(R.id.meuSmartImage);
smartImage.setImageUrl("http://gabrielmartins70.000webhostapp.com/bao.png");
proxima++;
}
btn = (Button) findViewById(R.id.button18);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
if (proxima == 1) {
smartImage.setImageUrl("http://gabrielmartins70.000webhostapp.com/2.png");
}
}
});
}}
When your activity is recreated after it was previously destroyed, you can recover your saved state from the Bundle that the system passes your activity. Both the onCreate() and onRestoreInstanceState() callback methods receive the same Bundle that contains the instance state information.
Because the onCreate() method is called whether the system is creating a new instance of your activity or recreating a previous one, you must check whether the state Bundle is null before you attempt to read it. If it is null, then the system is creating a new instance of the activity, instead of restoring a previous one that was destroyed.
Save your int variable like following example does:
static final String STATE_USER = "user";
private String mUser;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Check whether we're recreating a previously destroyed instance
if (savedInstanceState != null) {
// Restore value of members from saved state
mUser = savedInstanceState.getString(STATE_USER);
} else {
// Probably initialize members with default values for a new instance
mUser = "NewUser";
}
}
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
savedInstanceState.putString(STATE_USER, mUser);
// Always call the superclass so it can save the view hierarchy state
super.onSaveInstanceState(savedInstanceState);
}
I want to save two images, so that they are still displaying in the imageviews after screen rotation. Somehow it does not work and I don't know why. onRestoreInstanceState dind't work either. Can someone help me?
Here is my code:
private byte[] mapImage;
private byte[] photo;
private Bitmap imageBitmap;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_create_entry);
if(savedInstanceState !=null) {
photo = savedInstanceState.getByteArray(STATE_PHOTO);
viewPhoto.setImageBitmap(DbBitmapUtility.getImage(photo));
mapImage = savedInstanceState.getByteArray(STATE_MAP);
viewGPS.setImageBitmap(DbBitmapUtility.getImage(mapImage));
}
#Override
protected void onSaveInstanceState(Bundle outState) {
if(imageBitmap!=null) {
photo = DbBitmapUtility.getBytes(imageBitmap);
outState.putByteArray(STATE_PHOTO, photo);
}
if(mapImage !=null) {
outState.putByteArray(STATE_MAP, mapImage);
}
super.onSaveInstanceState(outState);
}
private void showMapView() {
Bundle getImageOfMap = getIntent().getExtras();
if (getImageOfMap != null) {
mapImage = (byte[]) getImageOfMap.get("map_image");
Bitmap showMapImage = DbBitmapUtility.getImage(mapImage);
viewGPS.setVisibility(View.VISIBLE);
viewGPS.setImageBitmap(showMapImage);
}
}
EDIT:
I put super.onSaveInstanceState(outState); on top of the onSaveInstanceState(Bundle outState) method and now mapImage is being shown after rotation but imageBitmap still isn't. I found out that the imageBitmap is saved but in onCreate it is null.
Does someone know a solution for this?
EDIT: mapImage is now somehow saved without savedInstanceState, because when I delete the mapImage part it is still there after rotation. It didn't use to be like this when I posted this question first. I give up...
I think I'll just use the not so pretty solution of the configChanges in the manifest. Thanks to everyone who tried to help!
Thanks!
IMO it is a threarding issue. Maybe your image size is more. Try saving the bytearray in some other thread. Better use an AsyncTask to save the byre array.
You have a typo. I think you should be checking for imageBitmap != null instead of photo != null:
protected void onSaveInstanceState(Bundle outState) {
if(imageBitmap!=null) {
photo = DbBitmapUtility.getBytes(imageBitmap);
outState.putByteArray(STATE_PHOTO, photo);
}
if(mapImage !=null) {
outState.putByteArray(STATE_MAP, mapImage);
}
super.onSaveInstanceState(outState);
}
EDIT:
Also, make sure that onCreate(), you initialize your viewPhoto (and other variables)
viewPhoto = (ImageView) findViewById(R.id.viewPhoto);
before access it inside the if block.
Unless your app is running on API21+ version of Android, your
public void onSaveInstanceState (Bundle outState, PersistableBundle outPersistentState);
will NOT be called as it simply does not exist on earlier versions of the platform than 21. To support pre API21 devices you must, instead of the above, override the following method:
public void onSaveInstanceState (Bundle outState);
This will work on API21+ as well, so you do not need to override both methods, of course (unless you know you need to deal with PersistableBundle the new one offers).
Can you once confirm about onSaveInstanceState calling means it's called or not?
I'm tring to open camera and take a picture and after that to store the image in a listView with image. the problem is, after i take the picture and return to my activity result the screen returns in landscape and a short while after rotates back to portrait and make me to lost the data. why this is happened? here is my code:
if (requestCode == mActions.REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {
Bitmap imageCapturred = (Bitmap) data.getExtras().get("data");
list.add(new ModelChat(null , false,null ,imageCapturred));
mChatAdapter = new ChatRowAdapter(this , list);
mChatList.setAdapter(mChatAdapter);
System.out.println("Get Image from Camera");
}
but the way..
I dont want using android:screenOrientation="portrait"
Any idea how to slove it?
make a intent as class variable and set the value of this intent when onActivityResult called like this.camaraData =data;
and also save this class variable in onsavedInstanceState() function
and restore this value in onRestoreInstanceState() or in oncreate()
eg.
public class yourActivityName extends Activity
{
Intent camaraData ;boolean chkCalled;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Check whether we're recreating a previously destroyed instance
if (savedInstanceState != null) {
// Restore value of members from saved state
camaraData =savedInstanceState.getParcelable("camaraData");
if(!chkCalled){
onActivityResult(mActions.REQUEST_IMAGE_CAPTURE,Activity.Result_OK,camaraData);
chkCalled=true;
}
}
...... /* your code goes here */ ...
}
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
// Save the user's current game state
savedInstanceState..putParcelable("camaraData", camaraData);
// Always call the superclass so it can save the view hierarchy state
super.onSaveInstanceState(savedInstanceState);
}
#Override
public void onActivityResult(int requestCode,int resultCode,Intent data)
{
camaraData=data;
if (requestCode==mActions.REQUEST_IMAGE_CAPTURE&&resultCode==RESULT_OK){
Bitmap imageCapturred = (Bitmap) data.getExtras().get("data");
list.add(new ModelChat(null , false,null ,imageCapturred));
mChatAdapter = new ChatRowAdapter(this , list);
mChatList.setAdapter(mChatAdapter);
System.out.println("Get Image from Camera");
}
}
public void onRestoreInstanceState(Bundle savedInstanceState) {
// Always call the superclass so it can restore the view hierarchy
super.onRestoreInstanceState(savedInstanceState);
// Restore state members from saved instance
camaraData = savedInstanceState.getParcelable("camaraData");
if(!chkCalled){
onActivityResult(mActions.REQUEST_IMAGE_CAPTURE,
Activity.Result_OK,camaraData);
chkCalled=true;
}
}
}
call only one way to handle this either in onCreate()or by using onRestoreInstanceState() function your problem will me solve as per your requirement or you can keep both but call of onActivityResult(...) function only from one place by checking whether its called or not by using boolean value as given in example
In general, what you need to do if you want your activity to survive screen rotation is save/restore your activites instance state.
Have a look at Recreating an Activity
Here is a re-occurring problem that I haven't found a good solution for in the past.
My application is based on a single activity that has multiple child fragments.
What i want to do:
In some of my fragments, I want to take a picture with the phones own camera-app and both show the image for the user and then upload it to my server.
What i do now
Now, i am calling StartActivityForResult with my camera intent which works fine. Then i receive what i need from onActivityResult and are able to show the taken image in an image view and also send it to my server.
The problem
Some times when my onActivityResult is called. My fragment has been uninitiated or just flushed from memory by the OS (As i understand it).
This means that variables now has null-references.
What i have read from similar issues is that OnCreateView() is supposedly to be called before OnActivityResult().
So what I am trying to do here is to save the fragments state to its Arguments in my onDestroyView() and onSaveInstanceState() and then try to restore variables such as the temporary Camera Image FilePath. Here however, the fragment seems to initiate the Fragment with a new Bundle and not the one i've created for it, and causes my app to crash due to my camera file is null.
This is also hard to test as this just happens some times at random.
Code
saveState() is called from onDestroyView() and onSaveInstanceState()
#Override
protected Bundle saveState() {
Bundle state = new Bundle();
state.putSerializable("tempCameraFile", tempCameraFile);
return state;
}
restoreStates() is called in the end by onCreateView()
private void restoreStates(){
tempCameraFile = (File)savedState.getSerializable("tempCameraFile");
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 7777 && resultCode == Activity.RESULT_OK) {
setPendingImage(tempCameraFile);
}
}
private void setPendingImage(File imageFile){
try {
Bitmap bitmap = PhotoUtils.decodeFile(imageFile.getPath(), Utils.convertDpToPixel(40, mActivity));
if(bitmap != null) {
buttonImageChooser.setImageBitmap(bitmap);
}
} catch(NullPointerException npe){
npe.printStackTrace();
Log.d(getClass().getSimpleName(), "imageFile NULLPOINTER!!!! WHYYYY!?");
}
}
#Override
public void onSaveInstanceState(Bundle outState){
super.onSaveInstanceState(outState);
saveStateToArguments();
}
#Override
public void onDestroyView() {
super.onDestroyView();
saveStateToArguments();
}
private void saveStateToArguments() {
if (getView() != null)
savedState = saveState();
if (savedState != null) {
Bundle b = getArguments();
b.putBundle("savedState", savedState);
}
}
I really hope there is an obvious thing I am doing wrong when using fragments and that someone are able to help me out.
This has been a reoccurring problem that I have solved with a really ugly implementation of destroying and re-creating fragments from my Activity, but I now want to do this the right way.
The problem is you are not saving your state at all.
#Override
public void onSaveInstanceState(Bundle outState){
super.onSaveInstanceState(outState);
saveStateToArguments();
}
The bundle outState contains all values which will be saved, but your method
saveStateToArguments(); saves the values in another bundle.
The outState and your bundle are not related, so nothing will be saved.
Besides there is no need to call the saveStateToArguments(); in the onDestroyView 'cause the onSaveInstanceState will be called.
So simply change your code to the following:
#Override
public void onSaveInstanceState(Bundle outState){
super.onSaveInstanceState(outState);
outState.putSerializable("tempCameraFile", tempCameraFile);
}
And restore the state in the method onRestoreInstanceState
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
if (savedInstanceState != null) {
tempCameraFile = (File) savedInstanceState.getSerializable("tempCameraFile");
}
}
Because the lifecycle is the following:
onCreate
onStart
onRestoreInstanceState
onActivityResult
onResume
See State of Activity while in onActivityResult question
Use activity to start the camera app and use activity's onActivityResult to make sure if the fragment exists. If it doesn't reinitialise the fragment.
getActivity().startActivityForResult(intent);
The problem is the system kill background activities on low memory.
Solution :
Save state of Activity or Fragment
/**
* Handled take camera photo on low memory maybe activity on background killed, need to save state.
*/
private Uri cameraMediaOutputUri;
#Override
public Uri getCameraMediaOutputUri() {
return cameraMediaOutputUri;
}
#Override
public void onSaveInstanceState(#NonNull Bundle outState) {
outState.putParcelable("cameraMediaOutputUri", cameraMediaOutputUri);
super.onSaveInstanceState(outState);
}
Restore the state and here is the trick as restoring state on Activity is different from Fragment.
Restoring Activity State
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
if (savedInstanceState !=null && savedInstanceState.containsKey("cameraMediaOutputUri"))
cameraMediaOutputUri = savedInstanceState.getParcelable("cameraMediaOutputUri");
}
Restoring Fragment State Fragment Life Cycle
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (savedInstanceState !=null && savedInstanceState.containsKey("cameraMediaOutputUri"))
cameraMediaOutputUri = savedInstanceState.getParcelable("cameraMediaOutputUri");
}
I've 3 fragments. Those fragments are placed into a TabsAdapter, for swipping between those fragments.
The problem, is that when the app loads, and the fragmentA view is created, it downloads the image and after it, changes a imageview:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
this.myFragmentView = inflater.inflate(R.layout.foto_setmana, container, false); //Això conté els "edittext i altres"
new DownloadImageTask(myFragmentView).execute("http://192.168.1.35/testing/fotos/foto1.jpg");
}
}
Code inside DownloadImageTask:
public class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
View myfragmentview;
public DownloadImageTask(View myfragmentview) {
this.myfragmentview=myfragmentview;
}
protected Bitmap doInBackground(String... urls) {
String urldisplay = urls[0];
Bitmap mIcon11 = null;
try {
InputStream in = new java.net.URL(urldisplay).openStream();
mIcon11 = BitmapFactory.decodeStream(in);
Log.d("debugging","mIcon11"+mIcon11.getHeight());
} catch (Exception e) {
Log.e("Error", e.getMessage());
e.printStackTrace();
}
return mIcon11;
}
protected void onPostExecute(Bitmap result) {
ImageView imv=(ImageView)this.myfragmentview.findViewById(R.id.imageView1);
imv.setImageBitmap(result);
}
So this is what is happening:
1.- I click the app
2.- The app loads. This screen is taken before the app had time to retrieve the image.
3.- As it retrieve the image, its shown.
4.- I swipe the fragment to the next one.
5.- The second fragment
6.- I swipe again to the 3rd fragment.
7. The 3rd fragment.
8. I go back to the first fragment, and the image isnt loaded anymore. Obviously I wont call to DownloadImageTask again, because it would slow so much users experience.
What should I do to preserve the image?
Oh, and by the way. If I just swipe from 1st to 2nd, the image isnt "unloaded", it just happens if I go to 3rd or further. Any idea why is this happening? I'm just curious about this.
Thank you!
Use the LruCache to create a RAM cache of your bitmaps.
This great Google IO talk explains exactly how to use it:
http://youtu.be/gbQb1PVjfqM?t=5m
I found out a way that it's working:
What we've to do, is creating a variable on the fragment to know if we downloaded, and another to save the bitmap at all, something like:
int downloaded;
Bitmap pictureSaved;
Then we initialize it on "onAttach" method from fragment.
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
this.downloaded=0;
}
And after that, on the "main code":
if (this.downloaded==0){
//we're here if we didn't download yet
new DownloadImageTask(myFragmentView, this).execute("http://192.168.1.33/testing/fotos/foto1.jpg");
this.downloaded=1;
} else if(this.downloaded==1) {
//we're here if we already downloaded.
ImageView imv=(ImageView)myFragmentView.findViewById(R.id.imageView1);
imv.setImageBitmap(this.pictureSaved);
}
DownloadImageTask code, should download the image, and as you can see, I pass to his constructor "this", so I can access the fragment methods and variables.
I create a method into the fragment to update the picture:
public void update(Bitmap updated){
ImageView imv=(ImageView)myFragmentView.findViewById(R.id.imageView1);
this.pictureSaved=updated;
imv.setImageBitmap(this.pictureSaved);
this.downloaded=1;
}
DownloadImageTask calls fragment's method like this.
Variables:
MyFragment frag;
Constructor:
public DownloadImageTask(View myfragmentview, MyFragmentA parent) {
this.myfragmentview=myfragmentview;
this.frag=parent;
}
PostExecute:
protected void onPostExecute(Bitmap result) {
frag.update(result);
}
It works perfectly.
Hope this helps someone.