I have activity A with recipes that opens activity B for more options for a recipe.
In activity B I'm doing an action (like adding to favorites) that finishes activity B.
When doing that action, I'm triggering a Talkback announcement so that the user knows the action has been completed successfully.
However, the announcement gets interrupted halfway through because activity B is finishing and Talkback starts announcing activity A instead.
How can I make sure that Talkback announcements are not interrupted? Is there any way to change the priority in the API (similar to live regions?)
I also tried adding a Toast, but the toast announcement gets interrupted as well...
Any suggestions?
Thanks!
I have run into issues like these as well. I did not find a way to stop interruptions, but generally use the following approaches to get around the issues:
Keeping announcements short whenever possible. "Item With A Long Name has been saved to your favorites list" is too long, at that point user has a lot of context and has an expectation of what is going to happen, so short announcement is usually fine. Something like "Favorited"/"Saved" is to the point and takes way less time to be announced! This is important with translations as well, some languages are so much longer than others.
Used carefully and only very infrequently: Adding a delay. Send announcement, set a timer for 500ms or whatever it needs to be, accounting for translations lengths too, finish activity after that. This is something that ideally will not need to be used a lot: only for very important announcements which shouldn't be missed! Having delays could badly affect user experience, so for me this is the last strategy.
Related
I have a rather peculiar case on my hands, and Im surprised that noone seems to have written about it/something similar for Android (or my Google skills suck)
Situation #1:
User can input text into field1 and field2.
User can also re-arrange items in a list (displayed in a RecyclerView)
Whenever the user does any of the edits, the UI is already showing the updated data (e.g. editing field1 will show the text as the user types it, and the list of items will show them in the new order as the user re-arranges them).
Saving the data right away here will trigger the UI to refresh (to display the same thing) and give the user a bad experience (field1 focus will shift to the first letter, and the app might crash if the user quickly re-arranges list items).
So it makes sense to store the edits and execute them at a later point.
Situation #2:
User can tap plus/minus buttons to increase/decrease a value
User can input text into field3.
As in situation #1 above, editing the field will already have the UI in the updated state. But, in this case - tapping the plus/minus button will also update the data, but the UI will not be updated (unless the data is saved, and the query ran again...).
Problem:
If data is saved immediately as the user performs an edit, besides doing a lot of saves, it makes for a bad user experience as the UI will refresh in some cases whereas its already up to date.
If the edits are tucked away and performed at a later point, the UI wont refresh.
Im using MVVM, so all performed actions are sent to the viewmodel and it decides what to do. I find myself looking for a solution that works differently across different screens of the app, but I know that would just be shooting myself in the foot and then jumping off a bridge. Surely, there must be someone out there that has come across this challenge and had some insights around it?
Ideal solution: One solution that just works for all the different screens. Do you have it? Please let me know.
/ Desperate Android Dev
First of all, let me start by stating that I don't think there is a correct answer here, but you should consider what your own app does and then determine what you need to do.
Let me explain. Consider two application, one that saves TODO items and the other is a banking application.
I will now explain what I think could work for your application, since you have not mentioned explicitly any requirements that contradicts that.
In situations like that, I believe being optimistic is a good idea. Assuming that things will not fail, and when they do, try to back out. What does that mean?
That means, for example, in the scenario you mentioned, user enters something in a field. You should let the UI update automatically (Nothing we do here, that's just Android), when that happens you save those changes either locally, or to a server, doesn't matter.
Of course, you can optimize, instead of saving each letter, throttle the input somehow, but you get the idea.
This can either be a succeed or a failure, because we are optimistic, we let the UI update and the user get the feel that our application is lighting fast. You don't need to reload anything, or refresh anything. The UI should match your Model state now already.
What if the things go south, and your HTTP request or DB update fails for some reason, then you need to take action. But try to keep your reaction appropriate.
You can handle that failure in so many ways, again, depending on how critical what you are doing in your app really is.
You can just show a Toast, or even do nothing if the user action was so trivial.
You can show the user something a bit more concrete if the action is of some significance, maybe a Snakbar with retry and explanation of what happened.
You kill your process and finish all activities -kidding don't ever do that- but showing a very intrusive pop-up and possibly reverting the UI value to the correct one, if what the user was doing is quite critical.
Now this approach doesn't just give the feel that the app is really fast, but it also keeps things simple.
Another advise is don't try to solve problems that don't exist yet, that means don't start implementing background services and job queues for some local persistence jobs that never outlive a view, and could never will.
Instead, use measurements, log those errors and failures with some tool, and use those stats to know what needs to be fixed -if any-
Back to our two applications, this approach might be perfect for a TODO app, however this might not be too good for a banking app.
Assume the user transfers money, we say immediately, ALL GOOD MATE! and then the request fails and your user's landlord kicks him out for never paying rent.
So it all comes to how sensitive the operations your're doing.
For reasons outside of my control (so, please no "you're doing it wrong" replies), my Android app needs to play extremely nicely, i.e. when a user hits the home button, my app needs to go away and release all of its resources (which are heayy, more than 1GB RAM consumption etc). It seemed calling finish() in onPause() would do the trick, but here's the problem: onPause() and onStop() also get called when I start an activity of my own, e.g. a preference activity, for which I just want to normally return.
So, my problem is: How can I determine the reason for losing the focus? I can think of two options, neither of which are pretty:
Keep state, i.e. the new activity sets some global flag that I can check in the "covered" activity so it doesn't stop when onStop() gets called. Annoying because every new activity of mine would have to do that.
Use the ActivityManager to check the top activity, and if it's one of mine, don't commit suicide. Maybe better, but the documentation heavily discourages use of the ActivityManager for this type of stuff.
Any ideas?
You are welcome to use onUserLeaveHint(). It may cover some scenarios (e.g., HOME), but not all (e.g., incoming phone call).
please no "you're doing it wrong" replies
IMHO, "more than 1GB RAM consumption" is already "doing it wrong" for a Play Store app. Specialized apps (e.g., specific enterprise scenarios, dedicated hardware) might be able to get away with that.
One approach for option 1 that will make it less annoying to implement and maintain would be to use Application.registerActivityLifecycleCallbacks. At least this way you don't have to implement this logic multiple times in multiple classes or unnecessarily force your activities into a single otherwise unrelated base class.
Not that I necessarily endorse this option. Also note you'll need API 14+.
Inactivity is a very important EVENT. For many apps if the user does not interact with it for a certain number of seconds its time to reset the app and go back to main activity logout, or conserve power. So I would really like to get some feedback on the best way to detect this. In fact I think everyone will benefit from a good solution to this.
So my question is twofold:
1) Is there a better way to detect user inactivity than using a combination of
activity.onUserInteraction() to reset a CountDownTimer?
Note: One reported downside to this approach is that softkeypad interaction might not be
caught by this approach.
Note: Another reported downside is the CountDownTimer is off main thread and might not update
correctly. I am not sure how big an issue this is?
Note: CountDownTimer appears to have cancellation issues as well:
how to stop/cancel android CountDownTimer
2) Lets say that onUserInteraction()/CountDownTimer is the best/only solution to this problem
there are still some questions:
a) should each activity launch its own countdown timer?
b) Should a single countdown timer be restarted in the onCreate method of each activity?
c) lets say I want to dim the screen or goto main activity when the countdown expires where
should the timeout handler be located? In each activity? In a service?
Thanks
Just stumbled upon this question as I've answered something similar just now.
Personally, I'd opt for option 2 that you have suggested, and put a timer into a singleton so its available across all activities. Theres no need for a separate countdown timer unless you have a specific requirement to react different under different features of your application.
Why would you want to reset the timer in the onCreate? You should do that each time the user interacts with the application, such as in the activity.onUserInteraction() method.
To quote from my previous answer:
You'll need to invest a little thought into exactly what your
requirements are here, but from what I can tell, you want to keep
track of the user interactions and if a time limit expires since the
last interaction, perform some action, in your case logging them out
of your application.
Firstly, you'll need some place that you can track when the last
interaction occured, since you'll want this to be application wide you
could use a singleton to hold this, or override the Application class,
either way should do.
Next, you'll need to start tracking user interactions. From your
activities, you can override the onUserInteraction method, this gets
invoked anytime the user interacts with the application such as key
event. Each time you hit this method, update your singleton and let it
know something has happened, with a timestamp.
Finally, you'll need some kind of looping check to constantly check if
anything has happened recently. Theres various was of doing this, you
could have a continuous loop that compares current timestamp to the
last recorded event, a bit of draft code :
while(true)
{
if (timeLastEventRecorded < (now - 15))
{
//nothing has happened in 15 minutes, so take corrective action
}
}
Presumably you'll already have some code in your application that
takes care of logouts, such as when the user clicks "logout", you
should just be able to invoke that in the sample above.
I am wondering how to handle user input forms in my app. (real budget lite). Right now this is what I am doing, but I am not sure if this is the best practice:
I have two soft buttons on most of my activities that take user input: "save" and "cancel".
"save" captures the user input and then finishes the current activity
"cancel" abandons any user input and finishes the current activity
Hitting the back button on the device does the same thing as "save"
It still bothers me a little that the back button performs the function "save and go back". Users who are new to android phones are probably used to web browsers, where the back button means "forget about this page and go back to the previous page". If you were buying something online and you got to the final "purchase" page, you would not expect the back button to complete the purchase, would you? But it seems like that behavior is the way that the built-in applications work, so I am not inclined to do it differently.
Anyway, I have looked through the official documentation and I cannot find this behavior explicitly spelled out. Can someone point me to the right place, or at least provide some guidance as to best practice?
The choices as I see them are:
Do it the way I am doing it now.
Get rid of the "save" button and count on the users knowing that back equals save.
Get rid of both buttons and provide a cancel feature from the menu key.
The google contacts app provides the buttons "done" and "revert", by the way. I guess "revert" means cancel; is there a difference? Maybe I should have my buttons labeled "done" and "revert" instead of "save" and "cancel"? In gmail, the menu button provides the choices "save draft" and "discard". It seems to me that we would be doing the users a favor if we had some consistency here.
Thanks in advance.
But it seems like that behavior is the way that the built-in applications work, so I am not inclined to do it differently.
The only built-in application that does this, that I can think of, is the contacts app, and I find that UX to be lousy. I was just cursing at it yesterday, as it happens.
Perhaps other built-in apps do it too, but I haven't encountered it yet, at least not that I recall.
Anyway, I have looked through the official documentation and I cannot find this behavior explicitly spelled out.
There are no UX guidelines of this nature in the documentation. Unfortunately.
It seems to me that we would be doing the users a favor if we had some consistency here.
You would get no argument from me.
Personally, I think of the BACK button as behaving as a "cancel", or whatever the negative choice would be. Dialogs typically behave this way on Android, for example.
If you have existing users, and you have established communications with them (newsletter, support Google Group, etc.), I'd poll them and see what they think. In the end, it is what your users want that matters most.
In a pinch, make it configurable. Ideally, for something like this, there is One True Right Answer, and therefore configurability would be pointless. However, if your poll indicates a split vote, and in the absence of Android platform UX guidelines, a setting might be the right solution for you.
UPDATE: I wrote a blog post about this issue, as I think it is reasonably important and worth a bit more prose.
I highly recommend you following the model used by the standard Android and apps, where editing always happens in place. That is, there is no "save" button -- the changes you are making are effectively being saved as they are being done. (The implementation may of course be slightly different, but to the user this should not be visible.) Following that model, your buttons should be something along the lines of "done" and "revert". This helps with the user's mental model of what is going on, that leaving the activity would not be likely to turn into a "revert" operation.
One reason for using this data editing model is that you will run into many fewer bad edge cases. If you try to present a more traditional model where the user explicitly saves, then any path the user may take out of your activity is a potential cause of data loss, which then leads you to want to protect them from that, and thus trying to show dialogs to confirm that they really want to lose their data. This is a losing battle, and you will never be able to catch all of the holes out, and your UX will suffer for it. (Consider for example if they receive an incoming phone call, this is just not the time to put up a dialog to first ask them if they want to save their data, nor would you be able to anyway.)
So start with your basic model being edit in place. This is consistent with the convention the standard platform uses, and this was deliberately chosen in the platform design because overall it results in a much simpler and more consistent and comprehensible UX. Design your UI flow to emphasize this model, by avoiding explicit "save" actions.
For me, I always feel 'unsafe' without a save option. For example, in GTask, when you create a new task, hitting 'back' (hard button) will save the stuff and back to prev screen. There's no soft button BTW. But I always frustrated about this.
For your app, I think you need to consider two things before deciding which way did the back button perform:
How critical is your 'save' operation (like it will place orders!)
Did your user expected to cancel stuff?
Obviously, if the save is long-processed and critical, an explicit control must be taken. (and back would not save); and for the second point, I guess GTask considered jotting notes should be quick and simple, and it should feel like jotting on paper --- it's saved, once you wrote.
Referring to what you said, back in web browser is go back and forget everything. But at the same time, Google (e.g. Google Docs) is also doing auto, background save, that it's not 'forgotten' when you back.
Trying to decide a universal action for when the user presses back makes this question a lot more difficult (if not impossible).
A much simpler approach is thinking about the context, and I see two main situations: the user is interacting with a dialog and the user is interacting with a regular activity.
Interacting with a dialog
If an user presses back in a dialog (for instance date time picker dialog) it's because he doesn't want to see that dialog or change that information.
While in a dialog, the user doesn't expect changes to apply until he says so (by pressing "Ok").
Interacting with an activity
For example, the user is seeing the details of some item that your application provides (contact information). Pressing back after some changes could mean "now take me back to the list of contacts". Anyway, this is not 100% clear. So including options to save and discard changes (call it whatever you like) could be a good option.
My thoughts as an android user
The behavior in a dialog is simple and clear. I think we have no doubts about it.
In activities, I'm used to have the back key to save data and send me to the last activity. Whenever I want to discard my changes, I find myself pressing the menu button and looking for a button to cancel.
If you want to something better, include the default behaviour as a preference and/or display a toast when you cancel or save the information.
Cancel vs revert
In practice, they do the same thing. Cancel should, herr, cancel what you are doing right now (editing something). This should/could take you to what you were doing before (list activity).
Revert will change the state of what you are seeing to the way it was before you started doing changes. This may not take you to the previous activity. It could simply update the UI to the original values.
Experiments with contacts application
Pressing back while editing a contact will save the changes.
Pressing home while editing a contact will discard changes
I'm building an Android application that's based around an enhanced WebView (based on PhoneGap). I've enhanced the WebView so that from JavaScript running inside you can invoke the native contact picker to choose a phone number (which may be supplied by Facebook for example).
The problem I have is that the native contact picker runs in an activity in another process and the Android docs say that while another activity is open my activity may get destroyed due to memory constraints. I haven't actually seen this happen in my application but if it did then I'm guessing my WebView's state would be destroyed and the code that was waiting for the picked contact would be terminated.
It seems a bit crazy that the activity requesting a contact could be destroyed while the contact picker is open. Does anyone know if that does indeed happen? Is there a way to persist the state of the WebView if it does?
Thanks,
-Shaun
Does anyone know if that does indeed
happen?
You're looking at the problem too simply.
You have a WebView. You open the contacts application. While the user is in the contacts application, a phone call comes in. While on the phone call (using a Bluetooth headset), a text message comes in, so the user opens that up from its Notification. While still on the phone call and texting away, a text comes in with a link, so she taps it and brings up the Browser application.
By this time, your activity is surely destroyed, except on maybe some of the most recent phones that have a fair bit of RAM.
Now, is that common? No. However, this also has nothing to do with the contacts application -- if the user presses HOME, at some point in the future, your activity may be destroyed to free up RAM as well.
Is there a way to persist the state of
the WebView if it does?
That depends on what you consider "the state of the WebView" to be. This really is PhoneGap's job, if you are making a PhoneGap-based app. So, you might consider asking them.
There is no way to persist the DOM. There are trivial ways to persist the URL (see onSaveInstanceState()). And there may be stuff in between that you consider part of "the state of the WebView" that may or may not be possible to save.
The long and detailed answer is a bit complicated, but essentially it comes down to a few points:
If the Android OS has to go cleaning up Activities or Services, it knows how to prioritise which ones should go first. It does this based on whether they're currently in the foreground (last to go), in the middle of executing code, waiting for a result, or simply sitting inactive in the background (first to go). You can be reasonably certain that if your WebView Activity launched the contact picker using the startActivityForResult, it won't be killed
There's a whole system for saving data if an activity is killed, such as the onPause method (which are triggered as soon as your activity leaves the foreground), the onSaveInstanceState method which is called when your activity is about to die. Read up on those to get more information, and the configurationChanged method when the screen orientation changes. If you haven't at least skim read the Activity Lifecycle document on the developers page, you must do that.
Lastly, I'm sure this question has been addressed many times, but with slightly varying wording or situations. Have a look around, see what else you can find.