Understand SharedPreferences Android - java

In android I want to make a basic login and registration application. I am following this tutorial. The application works properly and runs. I am just trying to understand the code now and after many google searches I can not understand some of the code and was wondering if somebody could help me understand it.
Below I have posted the method I do not understand and in comments highlighted what I do not understand - any clarification is much appreciated, I have also commented the code to what I believe the code does, if any of it is incorrect please tell me, you can also view all of the code on the tutorial website.
I am mainly confused about how the sharedpreferences works I have followed his tutorial on sharedpreferences too I understand that but do not understand this. Thank you and sorry if the problem is very basic
private void checkLogin(final String email, final String password) {
// Tag used to cancel the request
String tag_string_req = "req_login";
// Dialog stating trying to login
pDialog.setMessage("Logging in ...");
showDialog();
// Send the request over to the database to check details
StringRequest strReq = new StringRequest(Method.POST,
AppConfig.URL_LOGIN, new Response.Listener<String>() {
// Do this once you get a response
#Override
public void onResponse(String response) {
Log.d(loginName, "Login Response: " + response.toString());
hideDialog();
// Break the response up into individual things and store in variables
try {
JSONObject jObj = new JSONObject(response);
boolean error = jObj.getBoolean("error");
// Check for error node in json
if (!error) {
// I DO NOT UNDERSTAND THIS!!! how does this bit work?
// it sets the shared preferences login to true correct?
// but how does it set it true to only this particular user?
// Because it doesnt store the email and password along with it
// and sets its tag "isLoggedIn" and then saves it to the shared
// preferences
session.setLogin(true);
// Now store the user in SQLite
String uid = jObj.getString("uid");
JSONObject user = jObj.getJSONObject("user");
String name = user.getString("name");
String email = user.getString("email");
String created_at = user
.getString("created_at");
//I DO NOT UNDERSTAND THIS!!! Why do you need to do this & does this
//affect the MySQL DB at all?
db.addUser(name, email, uid, created_at);
// I DO NOT UNDERSTAND THIS!!! Why do you need to write LoginActivity.this
// do you not just write MainActivity?
Intent intent = new Intent(LoginActivity.this,
MainActivity.class);
startActivity(intent);
finish();
} else {
// Error in login. Get the error message
String errorMsg = jObj.getString("error_msg");
Toast.makeText(getApplicationContext(),
errorMsg, Toast.LENGTH_LONG).show();
}
} catch (JSONException e) {
// JSON error
e.printStackTrace();
Toast.makeText(getApplicationContext(), "Json error: " + e.getMessage(), Toast.LENGTH_LONG).show();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.e(loginName, "Login Error: " + error.getMessage());
Toast.makeText(getApplicationContext(),
error.getMessage(), Toast.LENGTH_LONG).show();
hideDialog();
}
}) {
/***************************************************************/
//I DO NOT UNDERSTAND THIS WHOLE METHOD WHY DO YOU DO THIS?!!!
/***************************************************************/
#Override
protected Map<String, String> getParams() {
// Posting parameters to login url
Map<String, String> params = new HashMap<String, String>();
params.put("email", email);
params.put("password", password);
return params;
}
};
// FINALLY I ALSO DO NOT UNDERSTAND WHY YOU DO THIS! AND WHAT DOES IT DO
AppController.getInstance().addToRequestQueue(strReq, tag_string_req);
}

This adds a user to an SQL database:
db.addUser(name, email, uid, created_at);
There should be a class somewhere that defines the actual function, which then creates the query that actually interacts with the database.
The intent changes the activity (what is rendered on the screen and what logic is handled):
LoginActivity.this: the context in the current class - this can be simplified to just this, but it's a bit of syntactic sugar in Java that attempts to clarify which this is being referred to.
MainActivity.class: the target activity
Intent intent = new Intent(LoginActivity.this,
MainActivity.class);
The difference between two activities can be explained with the content of a game. The menu is "LoginActivity.this" and "MainActivity.class" is the actual game content
As for shared preferences, the usage is pretty straight-forward:
To obtain shared preferences, use the following method In your
activity:
SharedPreferences prefs = this.getSharedPreferences(
"com.example.app", Context.MODE_PRIVATE);
To read preferences:
String dateTimeKey = "com.example.app.datetime";
// use a default value using new Date()
long l = prefs.getLong(dateTimeKey, new Date().getTime());
To edit and save preferences
Date dt = getSomeDate();
prefs.edit().putLong(dateTimeKey, dt.getTime()).apply();
(Source, posted by naikus)
The internal mechanics aren't something you need to worry about - the thing you really need to know is that it's able to save your data in a way you can use that doesn't involve directly accessing files (which has become a maze since Android 10).
EDIT:
Based on what I saw at the tutorial, the entire thing is to check if the login information entered exists in the database. The getParams() method defines what goes into the form data

Related

Checking for last user that logged in

I am trying to finish up the implementation of a login screen for my app. I have a REST API backend that verifies the username + token and returns the userId of the person logging into the app.
I want to store the last userId from the user who has logged into the app. I plan to use Shared preferences for this.
Based on the last stored userId, i plan to execute either going to the main activity (if this user has logged in previously, but logged out after a while and is re-logging in), or executing an AsynkTask to syncronise some data from the backend (if it is a new user). Here is my logic, which seems to not be working properly.
It is switching directly to the MainSyncTask, even if i'm logging in with the last username (userId is the same, received from the API), and savedUserId.equals(currentUserId) should return true and execute the Intent. last userId is properly store in the sharedpreferences db, check with Stecho .
String userId = getUserIdFromAPIResponse();
sharedpreferences = PreferenceManager.getDefaultSharedPreferences(this);
private void checkIdAndGoToActivity() {
final String PREF_VERSION_CODE_KEY = "user_id";
// Get current version code
String currentUserId = userId;
// Get saved version code
String savedUserId = sharedpreferences.getString(PREF_VERSION_CODE_KEY, "");
if (savedUserId.equals(currentUserId)) {
Log.e(TAG, "Current User Logged in");
Intent intent = new Intent(LoginActivity.this, MainActivity.class);
startActivity(intent);
/* destroys activity , prevents user from going back to previous MainActivity after login out */
finish();
} else if (!savedUserId.equals(currentUserId)) {
Log.e(TAG, "New user logged in");
MainSyncTask mainSyncTask = new MainSyncTask(LoginActivity.this, LoginActivity.this, userEmail, userPassword);
mainSyncTask.execute();
SyncEventReceiver.setupAlarm(getApplicationContext());
}
// Update the shared preferences with the current version code
sharedpreferences.edit().putString(PREF_VERSION_CODE_KEY, currentUserId).apply();
}

Backendless - Trying to retrieve specific data from Users table

I'm making an app for my final project in school..
I've made an Login page and inside the login page I need to retrieve a data from a specific column named Permissions and then check the permission to declare to which next Activity the app will take the user..
In simple words I need something like this:
public void login(View view){ //button
if(Permission == admin){ // get the permission from the user that is logging in.. lets say from username = "Bob123"
//do something..
}
}
A possible solution is to:
create an instance of BackendlessUser in your application class:
public static BackendlessUser user;
If you have added the permission column to the Users table and you have made the email an identity column in the schema you can use the following code to retrieve a BackendlessUser object and direct the user to the correct Activity based on his permission in the Users table:
public void login(String emailToLogin){
DataQueryBuilder dataQueryBuilder = DataQueryBuilder.create();
dataQueryBuilder.setWhereClause("email = " + "'" + emailToLogin + "'");
Backendless.Data.of(BackendlessUser.class).find(dataQueryBuilder,
new AsyncCallback<List<BackendlessUser>>() {
#Override
public void handleResponse(List<BackendlessUser> response) {
if (response.get(0).getProperty("permission").equals("permissionOne")) {
Intent intent = new Intent(LoginActivity.this, permissionOneActivity.class);
startActivity(intent);
}//end if
else if (response.get(0).getProperty("permission").equals("permissionTwo")) {
Intent intent = new Intent(LoginActivity.this, permissionTwoActivity.class);
startActivity(intent);
}//end else if
}//end handleResponse
#Override
public void handleFault(BackendlessFault fault) {
//add error handling here...
}//end handleFault
});}
In the code mentioned below, the response.get(0) will always return the correct user since we are getting the BackendlessUser object based on his email that we set to be a Unique Identifier.
"permissionOne" and "permissionTwo" is whatever you have called your permissions, eg. "permissionOne" takes you to the admin Activity and "permissionTwo" takes you to the clients Activity.
response.get(0).getProperty("permission").equals("permissionOne")
This code myUserObject.getProperty("myColumnName"); retrieves any property you want from the Users table in Backendless
Hope this helps somebody.

Facebook SDK blocking upload of String to Firebase

I'm developing an Android app which uses Facebook Login. Login's working fine and I'm able to get back info via Facebook Graph API calls.
I'm trying upload a string to my Firebase database and the string (titled parentFirstNameFromFacebook) is the first name of the user who signed into Facebook. I'm trying to eventually upload a parent object with parentFirstNameFromFacebook in its setName() method.
doneCreatingNameAndPasswordFAB.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
gettingTextFromNameAndPasswordEditTexts();
//region creating new Parent object and setting required variables
Parent coOpCreatingParent = new Parent();
coOpCreatingParent.setCoopCreator(true);
coOpCreatingParent.setNumOfHoursOwned(0);
Bundle params = new Bundle();
params.putString("fields", "id,first_name");
new GraphRequest(AccessToken.getCurrentAccessToken(), "me", params, HttpMethod.GET,
new GraphRequest.Callback() {
#Override
public void onCompleted(GraphResponse response) {
if (response != null) {
try {
JSONObject data = response.getJSONObject();
parentFirstNameFromFacebook = data.getString("first_name");
SharedPreferences fBookSharedPref;
SharedPreferences.Editor editor;
fBookSharedPref = getSharedPreferences(Constants.FBOOK_NAME_SHARED_PREF, Context.MODE_PRIVATE);
editor = fBookSharedPref.edit();
editor.putString(Constants.FBOOK_NAME_SHARED_PREF, parentFirstNameFromFacebook);
editor.apply();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}).executeAsync();
SharedPreferences fBookSharedPref = getSharedPreferences(Constants.FBOOK_NAME_SHARED_PREF, Context.MODE_PRIVATE);
fbookFirstNameForUpload = fBookSharedPref.getString(Constants.FBOOK_NAME_SHARED_PREF, null);
coOpCreatingParent.setName(fbookFirstNameForUpload);
getProfileImageUrlFromFBookGraph();
coOpCreatingParent.setImageUrl(parentImageIDFromFBookGraph);
ArrayList<Child> newChildArrayList = new ArrayList<>();
coOpCreatingParent.setChildren(newChildArrayList);
//endregion
//region creating new ArrayList<Parent> adding Parent object from above
ArrayList<Parent> coOpParentArrayList = new ArrayList<>();
coOpParentArrayList.add(coOpCreatingParent);
//endregion
getReferenceOfCoOpBeingCreated();
//region uploading entire new Co-Op object to Firebase
CoOp coOpObjectBeingUploaded = new CoOp(coOpKey, enteredNewCoOpPassword, enteredNewCoOpName, coOpParentArrayList);
referenceOfCoOp.setValue(coOpObjectBeingUploaded);
//endregion
//region going to AddChildren Activity with Co-Op key in intent
Intent intentForNewActivity = new Intent(getBaseContext(), AddChildrenActivity.class);
intentForNewActivity.putExtra(Constants.CO_OP_REFERENCE_TO_CHILD_ACTIVITY_KEY, coOpKey);
startActivity(intentForNewActivity);
//endregion
}
});
In the Firebase screenshot below, parentsInCoOp is an ArrayList and the 0 below it is the Parent object. I'm trying to set a name and Facebook URL string as other variables for that Parent object.
Firebase screenshot
Whatever I do, the name doesn't show up on Firebase! I'm not sure what I'm doing wrong!
I also tried using Shared Preferences in case there's an issue with setting parentFirstNameFromFacebook within the Facebook call's onCompleted() method. I put parentFirstNameFromFacebook in SharedPref and then got it out to pass it through parent.setName().
Once I successfully upload the first name, then I'll do the same process for the fbook image URl string.
Anyone have any advice? Thanks!
You are performing the Facebook API GraphRequest using the executeAsync() method. The request is processed on a separate thread and the onComplete() response is received asynchronously. I don't use the Facebook API, but am guessing the request requires communication with the Facebook servers and will require many milliseconds to deliver a response.
The result is that these statements
fbookFirstNameForUpload =
fBookSharedPref.getString(Constants.FBOOK_NAME_SHARED_PREF, null);
coOpCreatingParent.setName(fbookFirstNameForUpload);
execute before the statements in the callback have executed and stored the name in preferences.

Converting Android Volley Request to iOS NSURL asynchronous request

I have the following method in my Android app which I use for user login/registration.
public void registerUser(final String username, final String email, final String password) {
pDialog.setMessage("Signing Up...");
pDialog.show();
request = new StringRequest(Method.POST, SL_URL, new Response.Listener<String>() {
#Override
public void onResponse(String s) {
pDialog.dismiss();
String[] split = s.split("Config.php");
String after = split[1];
try {
JSONObject jsonObject = new JSONObject(after);
boolean error = jsonObject.getBoolean("error");
if (error) {
String errorMsg = jsonObject.getString("error_msg");
Toast.makeText(getApplicationContext(),
errorMsg, Toast.LENGTH_LONG).show();
} else {
session.setLogin(true, username, email);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}) {
#Override
protected Map<String, String> getParams() throws AuthFailureError {
HashMap<String, String> hashMap = new HashMap<>();
hashMap.put("tag", "login");
hashMap.put("username", name);
hashMap.put("password", password);
return hashMap;
}
};
queue.add(request);
}
Now I am writing my app for iOS and trying to replicate this in Swift. So far I have the following code:
let username = usernameTxt.text
let password = passwordTxt.text
let urlPath: String = "***"
let url: NSURL = NSURL(string: urlPath)!
let request1: NSMutableURLRequest = NSMutableURLRequest(URL: url)
request1.HTTPMethod = "POST"
let stringPost="tag=login&username=" + username! + "&password=" + password! // Key and Value
NSLog(stringPost)
let data = stringPost.dataUsingEncoding(NSUTF8StringEncoding)
request1.timeoutInterval = 60
request1.HTTPBody=data
request1.HTTPShouldHandleCookies=false
let queue:NSOperationQueue = NSOperationQueue()
NSURLConnection.sendAsynchronousRequest(request1, queue: queue, completionHandler:{ (response: NSURLResponse?, data: NSData?, error: NSError?) -> Void in
do {
var jsonResult: NSDictionary = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as! NSDictionary
} catch _ {}
})
Now as someone new to iOS development and Swift in general, I have the following questions:
What is the best way to replicate the progressDialog I use in Java in Swift, it must be visible until the request is complete and then it should be dismissed. I'm guessing this should be placed in the completionHandler, however I'm not sure which UI element to use for the progress Dialog.
How do I obtain my response as a String and replicate the behaviour of the split function, and then convert the result of this into a jsonObject like I do in my Java code.
What is the best way to replicate the Toast used to show the error message. I don't think using a dialog which must be closed with a button would be optimal here.
Thank you.
I am also developing Applications for Android and IOS. Here i Answered your three Problems which is faced by me also as a beginner. I hope this would help you.
1) Use MBProgressHUD Link to replicate the progressDialog in Swift .There are two method to show and dismiss the progressDialog:
Use showLoadingHUD() before making HTTP request
private func showLoadingHUD() {
let hud = MBProgressHUD.showHUDAddedTo(self.view, animated: true)
hud.labelText = "Loading..."
}
And hideLoadingHUD() after receiving the response from server
private func hideLoadingHUD() {
MBProgressHUD.hideAllHUDsForView(self.view, animated: true)
}
2) you can use Alamofire Link which can handle Network stuff And you can easily obtain response in String.
Example:
self.showLoadingHUD()
Alamofire.request(.GET, data, parameters: nil)
.response { (request, response, data, error) in
print(data) // if you want to check data in debug window.
let Result = NSString(data: data!, encoding: NSUTF8StringEncoding)
Result!.stringByReplacingOccurrencesOfString("\"", withString: "")
if(newResult == "1"){
self.navigationController!.popViewControllerAnimated(true)
JLToast.makeText("Success").show()
}
else if (newResult == "0"){
JLToast.makeText("Failed").show()
}
self.hideLoadingHUD()
3) mankee Toas are used for a purpose of displaying information for short period of time and disappear themselves. Here we can use Android like Toast which is JLToast. Available on github .
JLToast.makeText("Success").show()

Comparing values from textviews and JSONArray

Sorry for the (seemingly) lazy question, but i've been looking for a solution with no luck (in other words, I haven't found a solution that i understand).
I want to have users log in to an app by way of entering a username and password, this username and password has to match a username and password from the jsonarray which i've retrieved from a phpmyadmin database. The username and password have to be in the same row.
Here's the function I use to retrieve my jsonarray:
private void getData(){
JSONArray json;
try{
user = editText1.getText().toString();
password = editText2.getText().toString();
json = readJsonFromUrl("http://localhost/indextest.php?function=getdata");
Thread.sleep(1000);
} catch (Exception e) {
Log.e("BACKGROUND_PROC", e.getMessage());
}
}
I just need to know how to search the jsonarray for the values that i retrieve from my textviews.
If possible I would like to retrieve a value that I can easily assign to an if statement like such:
public void onClick(View v) {
switch (v.getId()) {
case R.id.button1:
if ( editText1 != null && editText1.length() != 0 && editText2 != null && editText2.length() != 0){
getData();
m_ProgressDialog = ProgressDialog.show(HomeScreen.this,
"Please wait...", "Checking Details...", true);
m_ProgressDialog.setCancelable(true);
if ( /*username and password match*/){
Intent i = new Intent(this, Afterlog.class);
startActivity(i);
}
else{
Toast.makeText(HomeScreen.this, "The username and password did not match any in our database...", Toast.LENGTH_SHORT).show();
}
}
else {
Toast.makeText(HomeScreen.this, "Please enter a user name AND a password...", Toast.LENGTH_SHORT).show();
}
break;
}
}
Two things:
Take a look at GSON. It is a Google Library for encoding objects into json and then decoding json into objects. In essence, you can define a class that has the same structure as the data you are receiving in JSON and then use GSON to read the JSON and create an object of your class with the appropriate fields filled in. Your code would look something like this:
First, define your class structure for the data you are sending as JSON:
public class LoginData {
public String Username; //These identifiers must match the JSON structure
public String HashedPassword;
public LoginData(String username, String hashedPass) {
Username = username;
HashedPassword = hashedPass;
}
}
Then, once you receive the JSON, you can parse the information like this:
LoginData login = mGson.fromJson(json, LoginData.class);
It sounds like you are storing usernames and passwords in raw text and retrieving them from your database in raw text. This is a VERY BAD IDEA! Passwords should always be stored in an encrypted form (i.e. hashed). When the user provides their password to log in, you encrypt the provided password and compare the encrypted versions (i.e. compare the hash of the provided password to the stored hash from your database). This prevents people who might be listening to your network traffic from being able to capture your passwords. Instead, if they were watching your network traffic they would see the hashed password, and without knowing exactly the algorithm used to hash the passwords, they would not be able to calculate the original password.
Your code needs to run in an asyncTask because it is performing a network request:
Here is an example:
class LoginTask extends AsyncTask<String, String, JSONObject>
{
protected JSONObject doInBackground(String... urls)
{
return readJsonFromUrl(urls[0]);
}
protected void onPostExecute(JSONObject result)
{
try {
//this assumes that the response looks like this:
//{"username" : "john" , "password" : "Bsd6578" }
String responseUsername = result.getString("username");
String responsePassword = result.getString("password");
if (user.equals(responseUsername) && password.equals(responsePassword)){
Intent i = new Intent(this, Afterlog.class);
startActivity(i);
}else{
Log.d("mylog", "username and password dont match");
}
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Your button is should be responsible for running that task:
public void onClick(View v) {
switch (v.getId()) {
case R.id.button1:
user = editText1.getText().toString();
password = editText2.getText().toString();
new LoginTask().execute()
break;
}
}
Found a very simple and to the point tutorial here:
http://www.coderzheaven.com/2012/04/22/create-simple-login-form-php-android-connect-php-android/
Thanks for all the help #meda :)

Categories

Resources