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.
Related
I am working on a note taking app and i am storing various images and texts using room persistence. I was wondering if it is better to keep updating the database every time user performs an action (like update the existing note) or is it better to do it at the end when the activity terminates or moves on to another activity.
What are the pros and cons of both the options.
Is there any better way than that ?
In my opinion you should update it on every action. Looks like this way google keep works to provide syncronization with server. And you should consider that your app can be closed without calling even onPause (e.g. due to some system crash), so this approach is more safe. So I don't really see any cons in updating database on every action.
IMHO one important thing is to never assume the users just stay within same app for more than 5 minute. They will switch to another app or do lock screen then leave your app for 30 minute and demand same exact screen when they come back to your app. If the activity already cleared by OS then... you know the rest.
So I'll definitely go with the first approach(update db for every action).
The best practice is to update your database on every change. If you worry about performance it doesn't have a sensible impact on your app performance. In applications with hundreds of database transactions per second like multipart download managers maybe it impacts the CPU and disk usage but your task is to slow for performance issues. Although you could use onStop() method to save data on the database before the user exit based on Android document but this work has no efficiency in your case and Android doesn't guarantee to call onStop in every situation.
When I launch my app, I should select start activity, depending on Room data. Like this:
If there is no user (by login string, stored in preferences) - show entrance Activity.
If there is a user but his propertyA wasn't set (null by default) - show Activity where he will select it's value (non-null afterwards).
Otherwise show general Activity.
The first option can be easily checked, because we can load value from preferences immediately. But to check propertyA I need to get user by login and Room forces doing it only in background, so we need async logic here.
The options to solve this I see:
Show Activity from step 2 (or some temporary Activity), update to necessary when user is ready (loaded). Bad because user will see wrong contents. Moreover, to avoid unnecessary updates we should store last property value - so we change to general Activity only when changing from null to something else (this way we get code mess for simple task).
Room database's allowMainThreadQueries(). Bad because breaks Room's general idea.
Semaphore (on main thread, but with expectation user loading is a fast task). Bad because looks ugly in code and has same problem as step 2.
I suppose my approach is totally wrong (in architecture way). Can you suggest how it can be solved in more elegant way?
Honestly, with your issue, I wouldn't go for any of the three options you listed.
Since your app relies on fetching data before knowing what content to show to the user, why not use a Launch Screen?
Launch Screens were added to Material Design and it's a good option if you wish to do some initial start-up processing while not sacrificing aesthetics or risk displaying inaccurate data.
Here's a link to Launch Screens: https://material.io/design/communication/launch-screen.html
Even if you don't use either a Placeholder UI or a Branded Launch Screen, it's still more pleasant to just show a short animation to the User as your app queries if propertyA is set.
I'm trying to implement the MVP architecture in my app.
However, after reading some blogs and viewing some sample project samples, I'm not sure I completely understood where is the right place to detach the view, and what should be done once the view attached for the second time after an async operation.
Most of the examples I saw, just sum it all up with a view's null validation check after an async call.
I'll try to make my point clear with an example - Login/Registration by phone number (The main idea is the important thing, and not the example itself)
There is an activity which display a fragment - LoginFragment.
The user enters his phone number and tries to login.
If the user exits - he should get navigated to another activity (after entering the code received by sms..)
If the user doesn't exits, he should get navigated to registration process - RegistrationFragment.
If there was an error, a dialog with error message should appear, ErrorDialogFragment.
Now, in a happy flow where the user presses the login button and waits until the process complete, all good.
But, in a less happier flows (not so frequent ones, but definitely can't get ignored), the user presses the login button and after that presses the home button or alternatively gets a phone call.
In scenario 1, where we attach/detach the view in onCreate/onDestroy, once the async login operation finish and we should replace to RegistrationFragment or show ErrorDialogFragment, there is a chance we will meet the famous IllegalStateException:
getting exception "IllegalStateException: Can not perform this action after onSaveInstanceState"
In scenario 2, where we attach/detach the view in onResume/onPause, once the async login operation finish we won't be able to replace fragment or show a dialog because the view is already detached.
In this case, I'm not sure what is the right thing to do.
Should we go with scenario 1 and commit the transaction with commitallowingstateloss?
I'm afraid it is a bad idea.
Or Should we go with scenario 2. In this scenario, we should act accordingly when view attached again, which means saving states (RegistrationRequied, ErrorHasOccured, LoginProcessStillRunning, etc..) in the Presenter/Interactor.
Can someone can shed some light regarding this?
Thanks in advance!
Oh the joys of the Android lifecycle. I feel your pain.
In my personal experience, resorting to commitAllowingStateLoss is usually a symptom of trying to update your Ui (View) while in the background (and as you note, the ui may be destroyed).
What I would suggest is that you don't try to update your ui without checking if the activity has been backgrounded (onStop or onPause depending on the situation). If your ui has been backgrounded, remember the changes you need to make and do them when your Ui is reconnected (onStart or onResume depending on the situation).
In essence I'm saying you should follow Scenario 2. And yes. You will have to save quite a bit of state somehow.
Unfortunately this isn't easy and there are many approaches to doing this ranging from using event buses, all the way through to using RxJava.
Every approach has it's advantages and flaws and they are all really too complex to discuss in detail in a single post.
However, I have a blog post I wrote some time ago on a way of doing this in a way that doesn't require additional libraries.
It's a little out of date now, but it may give you some ideas: A Simple MVP aproach for Android
All the best.
Kind regards,
Chris.
I'm wondering why I still see a lot of apps (including fb & instagram) that use pull to refresh feature for updating content? I mean, they have notification system that can tell itself to refresh when there's new data. I see that FB for instance it has little bubble in the news feed section that tells me i have new feeds up there and it can take me to it if i press it, but the pull to refresh functionality is still there. Why?
This is a great question. I'm interpreting it from the perspective of user experience.
Fast Company did an interview with Kevin Systrom a few years ago when Instagram added pull-to-refresh. He wasn't into the idea.
Systrom feels the gesture, which enables mobile users to refresh their photo feeds with a simple tug of the thumb, is a superfluous addition to his app, a relic of another smartphone era. "I don’t believe there should be refresh buttons," he says.
You're right that applications don't need to provide manual refresh capabilities. I'd say that pull-to-refresh and other user initiated actions fall under a category of interfaces that return agency to users, rather than relying on automatic processes to accomplish a task — in this case, refreshing content.
There are a few questions a user might ask if pull-to-refresh was removed from the examples you've given.
How do I get new content?
How often does this content refresh?
Does the user know that the content is automatically kept up-to-date? Do they trust that it's being refreshed quickly and consistently?
Nielsen Norman Group wrote a post late last year about visibility of system status, particularly that progress indicators contribute to a positive user experience by reducing uncertainty. I'd extend this research to pull-to-refresh and related interfaces. Maintaining a user's ability to manually perform an action that fetches new content covers two of Nielsen's ten usability heuristics — visibility of system status and user control and freedom.
In this light, a user who engages pull-to-refresh has a particular mindset: I want the latest data, and I want it now. Necessary or not, allowing them to manually refresh may be contributing to an improved user experience.
FYI: Pull to refresh was first used by Loren Brichter in the app Tweetie 2 which was acquired by Twitter later.
I think his answer to how he had implemented Pull down to refresh
gesture would be an apt answer for you question
Tweetie 2 simply took this idea from Tweetie 1, that reloading was
simply “loading newer”, and “loading newer” put new messages at the
top of the list… and activated the action based on a finger motion
that you were already doing. Why make the user stop scrolling, lift
their finger, then tap a button? Why not have them continue the
gesture that they are already in the process of making? When I want to
see newer stuff, I scroll up. So I made scrolling itself the gesture.
The gesture is only half the battle though, you need appropriate
feedback. Once the reload is activated, the scrollable area of the
list actually changes to leave the feedback UI in-place (rather than
bouncing offscreen). Without this part, the UI is unintuitive. And
once the loading is complete, the UI makes itself disappear.
Reference
It's usually better for a user to choose when to update the the news feed "like on the Social Apps".
Since its not usually good to update the content automatically when the user is still reading it.This can bring about confusion to the user.
And the pull to refresh is a qualified feature for doing the work
Also this is to save mobile data usage especially in countries where internet is expensive
Simple point by considering google's Do and Don't
Swipe-to-Refresh can be used to One-phased loading.We can use other type
progress bars ie , circular etc for loading content for the first
time and load and display all content at once or loading items when
scrolls .
You can understand the purposes clearly by going through this
In my opinion this UI component is an equivalent of refresh button which does not occupy any space and it is user friendly because join scrollable + force refreshing + loading animation + finish event
It is up to app's team to determine should they use it or not based on their possibilities
your question is Awsome.. i have some R&D on it.
see nowadays reach apps never use pull to refresh in android. because android have service that can run in background with wack-lock.
but ios have no background service.
service always consume battery best way when app is open you can one time use service and after than stop service and use swipe to sync or refresh.
hope u get some idea about it.
i have one Link for more about it.see comments that can open you for this point.
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