I have this really weird problem I can't quite wrap my head around. I have been pondering on this for hours and I have absolutely no clue why my code is behaving like this.
I have a Viewpager from which images can be deleted, in order to give the illusion of real time updating I open the same activity every time a photo is deleted so the viewpager's content will change immediately and accordingly.
For this reason I have overridden onBackPressed() to make sure that when this method is initiated the user returns to the real past activity and not the activity with the original images. I've read posts about this and tried to do things such as remove the super method and add the finish() method but nothing seems to work.
#Override
public void onBackPressed() {
//creates two instances of AccountApartementActivity
overridePendingTransition(0, 0);
add_button_view.setVisibility(View.INVISIBLE);
delete_button_view.setVisibility(View.INVISIBLE);
Intent i = new Intent(ApartementEditActivity.this, AccountAndApartementActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
i.putExtra("fromActivity", "2");
startActivity(i);
finish();
overridePendingTransition(0, 0);
}
In neither of the two activities' lifecycle methods I have overridden have I written code that tells the application to create the same activity twice, or I'm somehow overlooking it.
Weirdest thing is that this worked fine just a day ago but today I changed the data type of one of my variables inside my PagerAdapter method and ever since the onBackPressed() method has been broken.
Please let me know if I am missing something obvious, it happens a lot.
I think it is not the best practice to manipulate the activities stack this way. You could eventually run out of memory.
I don’t know how your photos are organized, maybe with a container layout like a gridview or a recyclerview?
Then you should update views with the adapter and the notifyDataSetChanged method.
Good luck !
Related
I have a snippet of code that calls startActivityForResult() to pick an image from the Android gallery. I have trouble understanding the lifecycle of the fragment from when startActivityForResult() is called and onActivityResult() is activated.
My activity retrieves and loads information onto a listview. It then allows user to insert pictures into the listview by sending an intent to the camera/gallery app using startActivityForResult(). This part works perfectly. The problem is that the list loses its data when the app returns from the intent and has to retrieve the information again. I have setRetainFragment(true) already.
My question is, is there any way to retain this data from when the intent is started and when it is returned? My guess would be to save an instance of it in onPause() and onResumse() but I don't quite understand how its lifecycle goes during this event.
Thank you in advance!
I have found a solution to my problem. To answer my question about the lifecycles, the fragment does go through the onDetach(), onAttach(), onCreateView() process. However, because i set onRetainInstance(true), it skips onDestroy() and onCreate(). The reason why my data is loss, is because I retrieve the data during onCreateView() and since onCreateView() is called everytime, so is retrieving data. From this, all I had to do was check if the list is empty before retrieving my data.
Another side problem, however, is that my variables are not retained. Although the list is retained and therefore my listview remains the same, boolean and int variables are reset and I don't know have a solution for this yet. If anyone can help, that would be great!
I currently have an activity's onCreate() method set to capture an intent the first thing it does. The intent will always have an extra int "ACTIONCODE" that determines what the activity should do.
Activity A might want activity Z to set up variables for the first time, so it calls startActivity(includedIntent) which has some extra int ActivityZ.SET_UP_FIRST_TIME (which is a constant in Activity Z.) Activity B might want to change the variables around a bit, so it does a startActivity(includedIntent) with the intent now including an extra int ActivityZ.CHANGE_VARIABLES as well as other data to change those variables.
Activity Z could just be a bunch of textviews that display what its variables are. Depending on what ACTIONCODE it receives from getIntent(), it will perform things just as it needs to.
I feel like I have a lot more control over the activities in my app my doing this, yet I fear as though it might be a really naive and inefficient implementation. I basically do not trust (nor fully understand) onStart(),onResume(),onPause(),and onStop(). From what I've heard, there is no guarantee that an activity will always return back to onResume(). While it was in its onPause() or onStop() state, it could have been killed or completely destroyed by the system, and thus would only return back to onCreate() again. It's the only method that I trust.
I even do all of my data saving from onCreate(). Why? I heard that if an activity is in onPause() or onStop(), it is liable to be killed, and may not even finish running through all the lines included in the overridden onPause() or onStop() method. I don't want to perform a data saving function from within a method that could abruptly stop!
Is my thinking wrong here? Are my fears irrational? If so, what should I do instead?
Here are my app screenshots by the way:
Thanks, Luksprog. After some reading, I think I can trust the activity lifecycle better now.
I will implement setting up in onCreate, loading in onResume, and saving in onPause! Hopefully that's correct.
Now all I need is some advice on the right way to set up activities and fragments. I just need some general rule of thumb for deciding when and when not to start a new activity, or if it may be better to use fragments.
When the user clicks a button in my application, it will alter some data in the document being worked on and at that point I want the activity to rebuild its UI. I want to do it this way if possible because exactly what views need to be updated for any given change is going to be tricky to know in advance.
I tried getting the intent, calling finish() on the activity then calling StartActivity with the same intent. Using this method I can disable all the pending transitions, so it's fine except because it creates a new instance of the activity its state can't be recovered (unless I do something really dumb like save it to preferences). And this is not acceptable because the activity contains a ViewPager which using this method returns to page 0 whenever I update something.
Next I tried using Activity.Recreate(). This solves the issue around the state not being saved since it appears to be the same instance of the activity. But in this case I can't work out how to disable all the animations, so there is always a flash on screen.
Is there a way I can make an activity.recreate() call look seamless to the user? Or is there a better way? Since this is all within a viewpager, refreshing the fragment would work just as well, but this not happening from the fragment class itself, but rather many objects which each provide part of the UI.
I faced similar problem, when I invoked recreate on activity it was blinking, I ended up using below code:
// uncomment below line for blink effect :P
// recreate();
// restart activity without blinking :-)
Intent intent = new Intent(MyActivity.this, MyActivity.class);
startActivity(intent); // start same activity
finish(); // destroy older activity
overridePendingTransition(0, 0); // this is important for seamless transition
I know I am too late to answer your question but I hope that it will help other developers who are facing same problem.
I have a synchronicity problem. I have searched and cannot find a question with the same conditions as mine. Pointers are welcome.
Android 4.1.2 on Eclipse 4.2.1
I have two activities; let's call them ListActivity and DetailActivity. On a button press on ListActivity, I start DetailActivity. When the user makes changes to data in the DetailActivity and then clicks the back button, I want to do two things. First, I want to save changes to the database if a dirty flag is true. Second, I want to return an Intent to the onActivityResult() method of the ListActivity.
The problem is one of timing. Since I want to do database updating, I read that it is best practices to do this in the onStop() method of the DetailActivity. Right after I update the database I set up the Intent and call the setReult() method in the DetailActivity.
_resultIntent = new Intent();
_resultIntent.putExtra(ListActivity .DETAIL_RESULT, _currentData);
Log.d("ListActivity.setUpReturn()", "checkpoint");
setResult(Activity.RESULT_OK, _resultIntent);
The onActivityResult() method of the ListActivity is called before I have a chance to set the result. I placed Log calls throughout and what appears to happen is the following:
1) The user is in the DetailActivity and changes some data setting the dirty flag to true.
2) The user clicks the system back button.
3) The DetailActivity disappears from the screen.
4) The ListActivity re-appears.
5) The Log notes the onActivityResult(), onRestart(), onStart(), and onResume() methods of ListActivity execute in that order
6) Some other stuff is logged.
7) The Log FINALLY notes that the onStop() method of the DetailActiviy executes.
This means that by the time I am updating the database and setting up the result Intent, the calling activity has already gone past the point of using it.
I'd rather not constantly update the database. I'd rather put this into the onStop() method like the best practices says, but I don't know how to get around the issue of timing. Any suggestions? Am I doing something obviously wrong?
Check that did you make your activity as a SingleInstance if yes then make it to SingleTop
I would rather rely on event based code logic rather than on probability. You could try the following.
*1) The user is in the DetailActivity and changes some data setting the dirty flag to true.
2) The user clicks the system back button.*
Override the onBackPressed method and perform your database operation right there and once the DB operation is performed you can call the super.onBackPressed() method and let the Android Activity stack take over.
Mind you DB operation could be time consuming and hence it is also recommended to use AsyncTask with callback and only then call finish().
That's because onPause() is called right after the activity loses focus. The onStop() however is called when the activity is going to be destroyd (usually when there is not enough memory). So put your code into the onPause() method and you should be fine...
It turns out the best solution for me was from PravinCG. I will use this as a pattern in the future.
#Override
public void onBackPressed() {
Log.d("DetailActivity.onBackPressed()", "checkpoint");
if (_currentDataIsDirty) {
DoDatabaseWork(_currentData);
}
_resultIntent = new Intent();
_resultIntent.putExtra(ListActivity .DETAIL_RESULT, _currentData);
setResult(Activity.RESULT_OK, _resultIntent);
super.onBackPressed();
}
Dogulas
I am trying to figure out how, when a user lands on my activity screen, it is "reloaded" as if it were being loaded for the first time.
I don't want my user hitting the back arrow and coming back to my activity with old information.
As it is now, when a user "comes back" to my page, the database list isn't being repopulated, and information they typed into EditText fields remains there.
I want the page, everytime the user comes to it, to be like it's their first time there.
Have you ever tried using recreate() in your current activity? Try using it after your new values are populated.
Or you can just put everything that's in the onCreate() on the onResume. A bit ugly but it works.
I have to disagree with Kartik on this, as I understand, android:noHistory='true' will remove activity from application stack. So when user hits back, user will not be able to see the activity at all.
About activity not retaining its value, I would not recommend you this, as user expects that all values would be retained when back is hit, unless there is some specific requirement that you are trying to meet.
So I guess solution to your problem is, as others have suggested do your initialization on views in onResume(). But just doing this may not be sufficient, as views like EditText will by default cache the values anyways. So you might have to manually clear those in your on onResume(). Will keep looking to find any 'perfect' solution if any to this problem.
I had solving similar problem like yours and I solve it whit lunch mode.
I think the best is to take a look of this set the lunch mode in single instance and then
in you onCreate and onResume you can code to refresh you view just the way you want it.
copy requred code into onResume() from onCreate() method