I have the ResultFragment. The onViewCreated() method has some logic regarding saving the result. If a user has earned an achievement, a button appears and he can go to the AchievementFragment. However, when the user presses the back button from there, he goes back to ResultFragment and triggers the saving again and that leads to a result duplicate.
How can I handle this behavior? I can check if the result is a duplicate, but this is going to hide a symptom and not solve the problem.
If you want to prevent the application from triggering the saving of the result, which leads to duplications when going back, make use of Boolean.
Below there is a simplified pseudo code of what you could use and adapt to your project:
ResultFragment:
Boolean resultObtained = false // place it somewhere that is not reset when going back
if (resultObtained == true) {
// do not save result
}
else {
// save result
}
The Boolean can be reset to false when you go back to the homepage. While is true, the ResultFragment should not duplicate the result if you nest the function inside the if statement using the Boolean.
For the Boolean, you could add it somewhere else and make it static, so it is easily accessible from all the fragments. Additionally, you can keep in the same fragment, but you would need to write more code to ensure that it is not reset to false again when going back. Alternatively, you may place it directly in the AchievementFragment and make it static so it stays true when you go back. However, it is up to you how you want to adapt it in your code.
Related
I am using xamarin forms prism.
Quick info : I have a page that contains information, this page the user can delete along with its information, this page is an instance of a page called saved conversation, think of each instance as a saved email, you may have many of the one type and are made dynamically.
The user deletes one saved conversation and this also removes an instance for that page, after they have deleted it, it will send them back to one of two pages every time. But they are still able to access this deleted saved conversation page using the hardware back button (Android), either by clicking it straight after they were force navigated back or navigating the app a bit and then pressing the back button multiple times. I would use something such as...
protected override bool OnBackButtonPressed()
{
return true;
}
But I want the back button to work for other pages and only not work if the previous page is an instance of the Saved conversation page, regardless if it has been deleted or not (As I think I may be able to figure out if it was deleted or not myself, just need to detect the page the hardware back button is going to send the user to, I think).
This might fall under a user experience decision over a technical workaround; but it sounds to me like this page you have might be a good candidate to be a Modal Page.
Navigating away from the modal page (popping it from the stack) should accomplish the same goal you are aiming for: not being able to navigate "back" to that page.
What I have done was add this code to all the pages in which I did not want the user to be able to go back. But it would only limit them from going back if the previous page is one of the two shown below. If it isn't then the back button works.
What I did note was you have to make sure modalNavigation is set to false when navigating to the pages (in my case conversation and saved conversation) otherwise they won't appear on the navigation stack to check against.
/// <summary>
/// Will override the harware back button.
/// </summary>
/// <returns> True if it can't go back false if it can.</returns>
protected override bool OnBackButtonPressed()
{
int count = this.Navigation.NavigationStack.Count;
bool shouldntGoBack = false;
if (count > 1)
{
string previousPage = this.Navigation.NavigationStack[count - 2].ToString();
if (previousPage == "NGT.Views.ConversationPage" || previousPage == "NGT.Views.SavedConversationPage")
{
shouldntGoBack = true;
}
}
return shouldntGoBack;
}
How to check if a fragment is visible to the user in an Android app?
I have an app where the Home activity has several fragments. One of the fragments listens to events from another activity started from Home and hence executing a method every time I come back to Home from that activity. While what I want is to only trigger those events and have the method executed if the fragment is visible to the user in the foreground.
I have tried the following but nothing seemed to work:
isAdded() and isVisible() check - always return true as soon as the fragment the created, irrespective of fragment actually visible to the user or not.
getUserVisibleHint() - this again would return true even if I was still in the other activity. Additionally, it is deprecated as well, so even if it worked I would want to look for another solution.
I have come to a dead-end to find an actual working way to check if the fragment is actually visible to the user and not just added to memory.
Any help on this is appreciated!
I finally came across the solution while trying myself:
Simple check for isResumed() and it'd only return true if the fragment is in the foreground and resumed state.
Just to be safe, check for isVisible which also checks for isAdded internally and would reduce the condition, so a simple if-condition:
if (isVisible() && isResumed()) {
// perform your action here
}
This worked for me!
I am calling a Master/Detail activity in android by clicking on a button placed in another activity (UserActivity). The strange thing is, that if i click the back button in the Master/Detail activity, I loose the Data in the state of the UserActivity. It wants to execute the onCreate Method again.
If I click on the login-button in the LoginActivity where i am redirected to the UserActivitiy and i go back with the Back-Button of the "Smartphone", the username and password i typed are still there. So there i do not loose the data.
Is there a difference between the back-button of the Smartphone and the back-button at the top of the program? I am a bit confused now and i know how to persist the state of the Activity. But my question is, why i am having this behavior on the one side and on the other not.
Just in case you will leave the question like this and don't add code:
What will probably help is checking for the amount of items that are already there. When I ran into this issue, the onStart() got called so quickly that it seemed to me that the Activity has lost the data. Actually it DID have the data, but calling onCreate/onStart (I'm in a Fragment) NULLed it.
What I did to avoid this is to check if there is a need to load items in the list. If there is, it calls a method that contains what the old onCreate/onStart did. If there is no need to load data, it will just skip the step and live with the "old" data happily for the rest of its life.
#Override
public void onStart() {
super.onStart();
if(DummyContent.ITEMS.size()<3){
initializeApp();
}
}
void initializeApp(){
videoTitles=new ArrayList<String>();
videoUrls=new ArrayList<String>();
. . .
}
I have a ViewPager with a FragmentStatePagerAdapter and the starting page should be somewhere in the middle. But when the user goes to another Activity and then comes back, the page number should be saved, so that he returns to the same page. There is probably an easy way to get this done, but I can't find the solution.
Usually the current page number will be saved, so this is not the point. The problem is that I don't know where to put the code that sets the starting page at first, because when I put it in onCreate, the starting page will be shown even if I come back from a different Activity.
I also tried saving the number in a variable in the onPause method:
this.currentPageNumber = viewPager.getCurrentItem();
But next time when onStart() is called, the variable currentPageNumber is null, so it seems that variables are not saved after onDestroy().
I could use a static variable, but it feels wrong. Is there a better solution?
EDIT: Sorry, I didn't make clear enough, that I want the saved page only be opened, if I come back to this Activity after I launched it. Every time I start the Activity from the launcher, the starting page should be shown and not the saved page.
EDIT 2: The behaviour I want to have is exactly the same as the Google Calendar app has when you open the day or week perspective. If I open this app, the current day will be shown. If I swipe to another day, then open settings, then press back, this other day is still be shown. But if I restart the app, again today will be shown.
After you have initialised your viewpager, use this method :
viewPager.setCurrentItem(int position)
Or this :
viewPager.setCurrentItem(int position, boolean withAnimation)
You can save the last position by using SharedPreference in the onPageSelect() method where you can get the position of each page. You have to implement the OnPageChangeListner in order to have this method.
Edit
Your question wasn't clear :
Sorry, maybe I didn't express my problem well enough. I want the starting page to appear everytime I start my app. But if I enter the activity by the back-button (for example if I opened my settings activity and then go back) the last viewed page should be shown. The solution provided in the link will lead to the safed page everytime I open the app
I don't know why you want to change this, it's a normal behavior, read this.
But if you insist, you can always use setCurrentItem() method in the onResume of your Activity/Fragment, thus the first page will always be shown after your Activity/Fragment gets resumed.
Edit 2
That can still be done by setCurrentItem. In your adapter, try to detect the index of the page of the current day. Create a method that returns that field from outside the adapter. And then after you have initialised your ViewPager,
viewpager = (ViewPager) findViewById(R.id.viewpager);
viewpager.setAdapter(adapter);
setCurrentItem(adapter.getCurrentDayPosition()) // or something like that ...
The method in the adapter :
public int getCurrentDayPosition() {
return this.currentDayPosition // this a field of the adapter.
}
I have the same requirement to show the default page whenever the onCreate of the ViewPager hosting Activity is called and show the current page for all the other cases including the motivating case: when user navigate back from the Activity started from the current page (onCreate won't be called in this case). My solution is based on the time spend between onCreate and onResume.
If the time between onCreate and onResume is shorter then a threshold (I use 1s assuming onCreate could be finished within 1s which we really wanted for the good programming practice), then we believe this is the first time the onStart/onResume is called right after the onCreate, otherwise we believe it is about all the other cases including our motivating case.
Then we only need to set the current timestamp in onCreate and do the time comparison in onResume to make the decision to set the current item of ViewPager to default or current. Note that we need to save the current page number in onPause in SharedPreference.
I am not claiming this idea is perfect but it works fine for me so far. Let me know if you are interested in the implementation and I will post my code upon your request.
i think this solve your problem , because first time you launch your activity there is no instance saved (savedInstanceState) ...
read comments in the post ...Android :Save View Pager State ...
I am developing an app where a single activity is instantiated multiple times by itself. I guess you could think of it like a book where each activity is a page. At the end of the page (activity) the user presses a button to go to a new page. I fire off an Intent for the same Activity, but I push different data into the Bundle so that a different page is loaded.
This works fine, and I like the fact that the user can back up to a previous point, but my question is whether this will eventually be a problem? What happens if this activity is instantiated 10 times, or 50, or 100? Will the device run out of memory, will GC come along and clean up old activities, or what?
If GC does clean them up, what happens when the user presses Back and the previous Activity is no longer on the stack?
Is it better to keep track of the user's path, finish() the activity, and override the Back button so that whether the user is moving forward or backwards, I only load a single Activity? Another approach I could take is to refresh all the data on the page so that it's still the same activity, but with new data. The Back button would not work as expected in this case.
Thoughts?
have you considered perhaps using the same Activity and just changing the content that it renders.
So in the book example. You would have a book Activity which would have a Page ViewGroup somewhere in its view hierarchy that renders the contents of the page. Then when a user goes to the next page or the previous page, the Page ViewGroup simply renders the contents of the desired Page. You could then use a data-structure to manage your stack of pages and the users current position.
Not sure what your app is trying to do, so I understand this might not work for your particular use. However, I would expect this to have a better run-time performance than instantiating entire Activities.
Old Activities that are no longer visible will get destroyed if their memory is needed. However, Android has a state persistence mechanism in place so that when an Activity is restarted (navigating back to page that was destroyed in your case) it can be reconstructed properly. This can be done through the shared preferences mechanism or the bundle object passed into Activity.onCreate. However, you will have to explicitly save off the state in Activity.onStop(...) and Activity.onSaveInstanceState(...), and then restore the state in Activity.onCreate(...) and Activity.onRestoreInstanceState
More on the lifecycle of Activies can be read here (Not sure what your level of understanding is)
http://developer.android.com/reference/android/app/Activity.html#ActivityLifecycle:
Now I'm not sure what happens at the extremes of this, whether you can create so many Activities that Android will no longer be able to bring back ones it killed. I would expect that there's some sort of protection mechanism in place to prevent that but I don't know what it is.
Found this article which might provide some more info, not sure if this is the info you were looking for though:
http://zerocredibility.wordpress.com/2009/08/24/why-android-swap-doesnt-make-sense/
Cheers & Happy Hunting!
I would rather override the back button behaviour and using for instance a ViewFlipper to do the animation job. That's pretty simple to do:
// You could do simpler by overriding onBackPressed() if you
// don't need 1.6 compatibility
//--
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) {
if (currentPage>0) {
return super.onKeyDown(keyCode, event);
} else {
currentPage--;
showPage(currentPage);
return true;
}
}
return super.onKeyDown(keyCode, event);
}