I'm asking this question because I want to be sure which is the best way to store the user "logged in" / "logged out" state in my android application.
Here is what I am doing. In my application I connect to the server, send him username and password and if everything is ok it returns me OK. So now I want to be able to save the user logged in state all over my application because I need to change the content depends on that if user is logged in or not.
And the other thing is that I need to be able to save the user's login state, so the next time when he start the application he will be automatically logged in.
Any suggestions or ideas which is the best way to do that?
I made a little research over internet and find a few ways to do that :
MyApplication class which extends android.app.Application
SharedPreference
Or maybe a SQLite
There can be many reasons when your app looses focus, like pressing home button incoming call, etc but no matter what happens your onPause method of current Activity is called so what you have to is-
Override onPause method of every activity
Use SharedPreference to save the state of Application
I use static classes or SharedPreference - it'is easy and it's works.
SQLite it not good way (in my opinion)
your option SharedPreference is the perfect one in this condition as you need to store only boolean and you will access if often in your app to change the content.
The problem with storing the state on the device (using either the SharedPreferences or SQLite) is that the user can manipulate it. So if you simply store "isLoggedIn" in your SQLite-Database, this entry can be manipulated using dpms (for example).
So if you need to store the state, you should use the Application-class (this can be manipulated, too, but it's harder to do so). If the user closes the application, you destroy the state-variable so he needs to do the login when the application is opened the next time.
For usability, you could store username and (if the user wants so) the password.
Also, if you have a web-service that you use to check if the users login-data is correct, why don't you use for example OAuth to authentify the user on the server and deliver the content from it? This would basically make your application a pure "client".
SharedPreference is the best option to access single value in terms of timing which i observe to be true as compared to sql lite.
Related
I was advised to do, in each Activity and Fragment onCreate callback, an if(signed_user_id == null) { showErrorPopIn(); startSplashScreenActivity(); return; } (a check that the user is not logged in, in which case we display an error and redirect the user from the Android app to the splash screen, and we don't execute the rest of the Activity and Fragment code). This code would be used in all activities (except SplashScreen of course) and in all Fragments, in the onCreate method. Cf. another SO question (Check if user is logged in on every activity, or only at the beginning?).
But I find it makes the code a lot heavier, and it seems to be useless. Indeed:
A hacker can change the activity code and the fragment code and therefore remove this condition, right?
And most importantly: checking that the user is logged in is only useful on the server side, not on the Android app side. Indeed, the critical points are the read and write accesses to the databases. But I don't give a damn if the not-connected user can see the graphical part of a Fragment or an Activity if this part doesn't display anything from a database or doesn't allow any modification in a database after a click on a button for example. Right?
So in the end I can remove all those if(signed_user_id == null) conditions I've put in all my Fragments and Activities?
PS 1 : signed_user_id is just FirebaseAuth::getInstance().getUser().getUId() roughly.
PS 2 : if I'm right, it means the first answer of the above linked SO question should be edited to indicate to the original poster that it's useless to do these checks in Android app side.
The problem is in this statement you make:
And most importantly: checking that the user is logged in is only useful on the server side, not on the Android app side.
There are two reasons to check whether a user is authenticated and/or authorized:
To reject unauthorized operations. This check should always happen on the server, as malicious user could bypass the check if (only) implemented on the client.
To show the correct authentication/authorization state to the user, and to allow them to change it (within the rules of your application). These checks happen on the client.
The goal of the second type of check is to show your user a clear UI, and provide them a path forward.
For example, you'll typically want to detect if the user is signed in, and if not show them the sign-in screen of your app. If you don't do this, the first time they know something is wrong is when the database rejects their operation with a "access denied" or similar message. This latter flow may be correct for your app, but it is very common to detect sign-in state on start-up and then first get the user to sign in (either anonymously or identified).
Another example could be if you have a premium user level who are allowed to write more data to your database. Of course the actual check of whether a write is allowed should be done server-side. But you might want to update the UI in some way if a non-premium user has reached their limit, for example disabling the UI elements that would update the database (and thus fail), or maybe show them a "you've reached the limits of your plan, click here to upgrade" banner.
So neither the server-side check nor the client-side check is useless, but they serve different purposes. Server-side checks are required to ensure your data stays uncorrupted, and your business rules are followed. Client-side checks are recommended to give your users a better (UI) experience.
I think this will be much easier if you are using BaseActivity and BaseFragment that all activities and fragment extends from it so you will write this code in BaseActivity/BaseFragment oncreate method only.
On Android, it is possible for users to use the Settings -> Application Manager -> App -> Clear Data feature and clear all the stored data for the app. However, if the user uses the app switcher to switch back to the app it will switch back to the activity last used. In some cases, say with an app that requires login, the activity will be inappropriate for the case where there is no data. How should application handle his case? Should each Activity be derived from a base Activity class that checks if the data has been deleted and then launch the appropriate Activity (say, the login Activity)? Is there a more elegant solution than that?
Instead of checking if data has been deleted, just check if the user is signed in. If he isn't, you can just send him back to the login screen as you suggested.
In any case, if you are using oAuth, or ever intend to implement it for login, checking if the user is logged in should be implemented since the oAuth tokens eventually expire. In this case, no data has been deleted, but the user is no longer signed-in, which would lead to them getting stuck in the inappropriate Activity anyway.
Just create a super-class for your ActivityThatRequiresLogin that will check if the user is logged in, and have all ActivityThatRequiresLogin extend that class. Then, you can call super whenever the onCreate and onResume method is called.
If the user wipes their data, they are automatically signed out, so all you have to do is check if they're signed in or not.
Pressing Clear Data stops your app's process, so your code will not be running.
Unfortunately there is no way to catch intent of such action unless you'r a system app.
The best practice way to handle this situation would use a SharedPreference mechanism and a base activity class.
I have couple of applications that implements some login logic. If lets say one application is logged to some_account#gmail.com I want that all of these applications be logged to some_account#gmail.com. If I logout I want to all application do the same. But I don't want to immediately do the same. Application itself can handle it, but it need to know if some other application is already logged in and if yes just log in for the same email address as this app. So I need to know what is the email address for which other app is logged. I need to store one string.
First I was thinking about SharedPreferences, but this is rather bad idea because there are other options (and stackoverflow is full of bad example of SharedPreferences usage between processes). Despite it I tried this. Set up sharedUserId on all apps, called createPackageContext and eventually try to get preferences. But I cannot read from it. Always I got null, even if I used Context.Mode_WORLD_READABLE - which is deprecated by the way.
Ok, lesson learned do not use SharedPreferences for that (I suppose). But everything what I need now is to store single string somewhere where it could be read by other my apps.
Maybe I should use ContentProvider? But seriously... for one string?
What is the other option? I am sure that for so simple operation I really don't need Service or ContentProvider, but I actually haven't got idea how to do that.
You could use a broadcast receiver. All you would have to do is send a broadcast to application B when the data changes in application A. Then application B can handle the data in the background, and store it however you need to. It might be a bit of over kill, and there could be a better way to do it, but it would work.
I was watching one of Google's app reviews and they were ripping into this guys' app who had a save button and if you didn't save before leaving it would pop up a dialog. They said an android app should just save and not bother the user.
I have a fragment and have several fields and need to determine when to save the data into a SQLite database. I was thinking of saving on exit of each field via the onFocusChange event? Or maybe that's too often? Perhaps the fragment's onPause event? When should I save (specific event please)?
Fragments are much like the activities when it comes to lifecycle. So onPause() is the right place to save persistent state, later after onPause() it may be too late and can lead to data loss. Google recommends to use "edit in place" user model. That is, save edits immediately, in your case saving data when the user switches between input fields is good approach. This prevents data loss if your Fragment/Activity is killed by the system. If you think it can take few seconds to save your state you can use also IntentService in onPause(). In your scenario I would execute AsyncTask updating your database when the user switches between input fields, maybe with detecting if change really occured.
Edit: If you are using ContentProvider than consider using AsyncQueryHandler instead of AsyncTask.
public void onDestroy()
Called when the fragment is no longer in use. This is called after onStop() and before onDetach().
I would probably use that; it would mean the user is done using that fragment. I don't know of any cons in doing it that way or your way.
I am new in Android and is developing an app which runs in background as service to collect user activity. till now my app is able to get information about Time_Start, Time_End and Name of other app used by user.
I want to improve my app to be able to count how many interactions(like user tap, touch,...) user make while using other app. Can any one give some advices about this issue? Just the way to do and I'll do all details by myself.
Thanks!
The best way to do this is to implement Listeners for the types of user interactions you would like to count. Have a global variable in your activity. Every time the user interacts, add one to it.
If you want to keep count across the entire app, you could save a variable in SharedPreferences, and at the end of each activity, add your activity's global variable count to the value you have store in shared preferences. Or, you could just edit the value you have stored in SharedPreferences right off the bat on every user interaction. Just remember to reset the value of the SharedPreferences when you first start the application, as values stored in SharedPreferences are stored even after the app is closed unless you specifically remove them, or clear the SharedPreferences.
Another way you could keep count is by using a global static variable that is accessible from all other activities. This way you would be able to increment it from other activities. This is generally considered bad practices though, so I advise against this.
The documentation for SharedPreferences is here:
http://developer.android.com/reference/android/content/SharedPreferences.html
The documentation for implementing input event Listeners is here:
http://developer.android.com/guide/topics/ui/ui-events.html
Hope this helped!