SharedPreferences with multiple files - android

I'm trying to write my first program, and am now learning and writing the part where I save general information and user information via SharedPreferences.
Used the documentation and wrote the first part for saving general information and everything worked great. I could write and read values perfectly.
I expanded to store user information in a second file, and it seems to write, but i always get the default value. If I switch to using the general information file instead of user file, it works.
I think I'm doing something wrong in how I am using GetSharedPreferences() where it is limiting me to using just 1 file like it says for GetPreferences().
The general settings I am storing in a file named "Data", and user settings I am saving in file User1, User2, etc for each user
Below is my code.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
// If first time running app, create Guest user
int intNumOfUsers=Integer.valueOf(funcReadData("Data","INT","NumOfUsers"));
if (intNumOfUsers==0)
{
String strTest=funcReadData("User1","STR","User");
subWriteData("Data","INT","NumOfUsers","1");
subWriteData("User1","STR","Name","Guest");
subWriteData("User1","STR","Pass","Guest");
}
// Determine if user needs to login before continuing
if (Boolean.valueOf(funcReadData("Data", "BLN", "StayLoggedIn")))
{
subLoadMain();
finish();
}
}
In above onStart, when the app is run the first time, it reads from "Data" file to get value of intNumOfUsers and if 0, it creates a default one by changing intNUmOfUsers to 1, and then creating a guest User/Pass in "User1" file.
The value to "Data" file saves and can be read perfectly, but the value to "User1" doesn't seem to save since I only get default value when I read it.
I use below common procedure to read and write data so no mistake with differences in code for each case exists.
public void subWriteData(String strFile, String strType, String strKey, String strValue)
{
SharedPreferences prefs = getSharedPreferences(strFile, MODE_PRIVATE);
SharedPreferences.Editor editor=prefs.edit();
Log.d("WD","WRITE-"+strFile+"-"+strType+"-"+strKey+"-"+strValue);
switch (strType)
{
case "STR":
editor.putString(strKey, strValue);
break;
case "INT":
editor.putInt(strKey,Integer.valueOf(strValue));
break;
case "BLN":
editor.putBoolean(strKey,Boolean.valueOf(strValue));
break;
case "LNG":
editor.putLong(strKey,Long.valueOf(strValue));
break;
case "FLT":
editor.putFloat(strKey, Float.valueOf(strValue));
break;
}
editor.commit();
}
public String funcReadData(String strFile, String strType, String strKey) {
String strValue = "";
SharedPreferences prefs = getSharedPreferences("Data", MODE_PRIVATE);
switch (strType)
{
case "STR":
strValue = prefs.getString(strKey, "");
break;
case "INT":
strValue = String.valueOf(prefs.getInt(strKey, 0));
break;
case "BLN":
strValue = String.valueOf(prefs.getBoolean(strKey, false));
break;
case "LNG":
strValue = String.valueOf(prefs.getLong(strKey, 0));
break;
case "FLT":
strValue = String.valueOf(prefs.getFloat(strKey, 0));
break;
}
Log.d("WD","READ"+"-"+strFile+"-"+strType+"-"+strKey+"-"+strValue);
return strValue;
}
And below is just more code where I see if i can find user details and match against given information or create new user etc
public void subCreateLogin(View view)
{
Boolean boolUserFound=false;
Boolean boolUserLoggedIn=false;
int intNumOfUsers;
CheckBox chkStayLoggedIn = (CheckBox) findViewById(R.id.chkStayLoggedIn);
EditText txtUser = (EditText)findViewById(R.id.txtUser);
if (txtUser.getText().length()==0 )
{
Toast.makeText(Login.this, "Please enter a valid username", Toast.LENGTH_SHORT).show();
}
else
{
EditText txtPass = (EditText)findViewById(R.id.txtPass);
if (txtPass.getText().length()==0 )
{
Toast.makeText(Login.this, "Password field cannot be empty", Toast.LENGTH_SHORT).show();
}
else
{
intNumOfUsers=Integer.valueOf(funcReadData("Data","INT","NumOfUsers"));
if (intNumOfUsers>1)
{
int Lvar;
String txtData;
for (Lvar = 1; Lvar <= intNumOfUsers; Lvar++)
{
txtData = funcReadData(("User"+Lvar).toString(), "STR","Name");
if (txtData.toUpperCase().equals(txtUser.getText().toString().toUpperCase()))
{
boolUserFound=true;
txtData = funcReadData(("User"+Lvar).toString(), "STR", "Pass");
if (txtData.equals(txtPass.getText().toString()))
{
boolUserLoggedIn=true;
subWriteData("Data","STR","LastUser", txtUser.getText().toString());
if (chkStayLoggedIn.isChecked())
{
subWriteData("Data","BLN","StayLoggedIn","true");
}
}
else
{
Toast.makeText(Login.this, "Incorrect password. Please try again.", Toast.LENGTH_SHORT).show();
}
}
}
}
if (!boolUserFound)
{
// First new user, create his details
intNumOfUsers++;
subWriteData("Data","INT","NumOfUsers",String.valueOf(intNumOfUsers));
subWriteData(("User"+intNumOfUsers).toString(), "STR", "Name", txtUser.getText().toString());
subWriteData(("User"+intNumOfUsers).toString(),"STR","Pass",txtPass.getText().toString());
subWriteData("Data","STR","LastUser", txtUser.getText().toString());
//boolUserFound=true;
boolUserLoggedIn=true;
if (chkStayLoggedIn.isChecked())
{
subWriteData("Data","BLN","StayLoggedIn","true");
}
}
}
}
if (boolUserLoggedIn)
{
subLoadMain();
finish();
}
}
So anything that reads/write to "Data" is fine, but to "User1", "User2" etc never seems to work. How do I enable the ability to save multiple preferences files?
Thanks!

in your read data function while getting the shared prefs you have specified the file name as Data instead of passing in the file name while in writing you use the passed in filename.

Related

Once inserted, data in Firebase is automatically disappearing for some unknown reason

I made another post to explain better, ok? :)
This video shows exactly what I mean:
The video is: https://www.youtube.com/watch?v=DCg00fe-_xs
Firebase normally stores data. After the 6th second of the video, trying to enter new data, the data stays about a second in Firebase, but automatically then it disappears.
I try to input the data into Firebase two more times in this video, but the data always automatically disappears afterwards.
You can see that the other datas that are stored in Firebase does NOT disappear. But the data of this code is automatically disappearing for some reason as shown in the video. Please what can I do to fix it?
Code:
button = findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
final String raça = spinner_raca.getSelectedItem().toString();
final String regiaoDoEstado = spinner_regiaoDoEstado.getSelectedItem().toString();
final String estado = spinner_estado.getSelectedItem().toString();
Intent receiverIntent = getIntent();
Bundle bundleRecebedor = receiverIntent.getExtras();
String nomecompleto = bundleRecebedor.getString("nomecompleto");
String email = bundleRecebedor.getString("email");
String doencasPreExistentes = bundleRecebedor.getString("doencasPreExistentes");
String dataDeNascimento = bundleRecebedor.getString("dataDeNascimento");
String genero = bundleRecebedor.getString("genero");
String identificadorEmHash = bundleRecebedor.getString("identificadorEmHash");
String telefone = receiverIntent.getStringExtra("telefone");
reference = FirebaseDatabase.getInstance().getReference().child("Usuarios").child(identificadorEmHash);
Toast.makeText(getApplicationContext(), identificadorEmHash, Toast.LENGTH_LONG).show();
if(identificadorEmHash.equals(null)) {
Toast.makeText(getApplicationContext(), "The identifier does not exist", Toast.LENGTH_LONG).show();
} else {
reference.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
reference = FirebaseDatabase.getInstance().getReference().child("Usuarios").child(identificadorEmHash);
if (!dataSnapshot.exists()) {
Toast.makeText(getApplicationContext(), "The identifier does not exist", Toast.LENGTH_LONG).show();
} else {
HashMap<String, String> sendDataToDataBase = new HashMap<>();
sendDataToDataBase.put("Nome Completo", nomecompleto);
sendDataToDataBase.put("E-mail", email);
sendDataToDataBase.put("Identificador em Hash", identificadorEmHash);
sendDataToDataBase.put("Telefone", telefone);
sendDataToDataBase.put("Doenças Pré Existentes", doencasPreExistentes);
sendDataToDataBase.put("Data de Nascimento", dataDeNascimento);
sendDataToDataBase.put("Gênero", genero);
// When I am going to send the following data to Firebase, the problem of the video happens.
sendDataToDataBase.put("Região do Estado em que mora", regiaoDoEstado);
sendDataToDataBase.put("Raça", raça);
sendDataToDataBase.put("Estado do Brasil em que mora", estado);
try {
raiz.child(identificadorEmHash).setValue(sendDataToDataBase);
} catch (Exception e) {
e.getMessage();
}
}
}
});
}
}
});
Please, can someone help me to fix this bug?
Firebase doesn't automatically delete data, so if you see the data show up in the console it was written there by a client/API call, and allowed by your security rules. If the data subsequently gets updates or removed again, there is another client/API call that does so.
I recommend checking for realtime listeners in your code, that may be responding to your first write by updating (and accidentally reverting) that operation. It is also quite common to have a server-side script that is doing this.
Update: one thing you can try is to use updateChildren instead of setValue in all places such as this one:
raiz.child(identificadorEmHash).updateChildren(sendDataToDataBase)

Android Studio Login/Register System ideas

I want to make a diet helper app for android devices, using android studio and
I need ideas on what to use to implement the login/register system, I followed a tutorial on youtube but it was outdated and I ended up wasting my time, then I've read on google, that android studio has a library called volley that I can use with PHP and MySql to make the login system.
Do you have other ideas, or is that the best one to go with?
I'm open to suggestions so shoot!
Update:
I've created a post about how to do this using a PHP backend for your Android application. https://keithweaver.ca/posts/4/android-php-custom-login
Additionally to the link above, this is how you can setup a server.
https://github.com/kweaver00/tutorials/blob/master/setup-server.md
https://keithweaver.ca/posts/9/setup-ubuntu-server-quickly
Original Post:
This is one solution and isn't guaranteed to be the best.
You can really use anything to communicate with a server. Async Tasks or Retrofit are both popular.
Assuming you have set up a server with a LAMP stack. Make sure you have an SSL so you don't pass user information that isn't encrypted.
Create a user table in mysql
Ex.
id int default->NULL AI primary-key
user varchar 250 default->null
pass varchar 250 default->null
signupdate date default-> null
Create a log in sessions table of some sort
Ex.
id int default->NULL AI primary-key
user varchar 250 default->null
token varchar 250 default->null
addedDate date default->null
Create a log in php script (I know this probably isnt the best way to right php code)
$connection = mysqli_connect("localhost", "phpmysqluser", "password", "dbname") or die("Error 404: unable to connect");
$username = $_POST['user'];
$pass = $_POST['pass'];
//add code to remove slashes and etc.
$result = mysqli_query($connection, "SELECT * FROM userTable WHERE user='$username' AND pass='$pass'") or die("Error: this line has error");
class response{
public $loggedin =0;
public $message = "";
}
$response = new response();
if(mysqli_num_rows($result) == 1){
$logInToken = generateLogInToken();
//have a function that creates a unique token and stores it for X days or minutes
$response->loggedin = 1;
$response->message = $logInToken;
}else{
$response->message = "wrong info";
}
echo json_decode($response);
This should output a json file like this depending on your user and pass variables.
{
"loggedin" : 1,
"message" : "asdnlansdkansd"
}
Right another script that passes in the log in token and user name to check if it's valid.
$connection .... //same as above
//well it really should be a include_once cause if you change credentials
$token = $_POST['token'];
$user = $_POST['user'];
$registeredDate = "";
$today = date('Y-m-d');
$result = mysqli_query($connection, "SELECT * FROM tokenTable WHERE user='$user' AND token='$token'") or die("Error...");
class response{
public $status = 0;
}
$response = new response();
if(mysqli_num_rows($result) == 1){
//check token has been register today and if not sign them out
while($row = mysqli_fetch_array($result)){
$registeredDate = $row['addedDate'];
}
if($registeredDate == $today){
//token is valid
$response->status = 3;
}else{
//expired
$response->status = 2;
}
}else{
//user and token are not valid
$response->status = 1;
}
echo json_decode($response);
Giving a json object like:
{
"status" : 3
}
In your Android app on open, run the code to check if the account is valid if there is anything stored locally. Or just go to log in screen.
On splash screen in the onCreate (you dont need a splash screen, its actually not recommended but its the easiest way to explain the process):
if(userNameAndTokenStoredInSharedPref()){
String token = getTokenFromSharedPref();
String userName = getUserNameFromSharedPref();
checkAgainstServer(token, userName);
}else{
Intent openLogInWindow = new Intent(this, LogInActivity.class);
startActivity(openLogInWindow);
}
still in the slash activity but out of the oncreate:
protected void checkAgainstServer(String token, String user){
//using retrofit
ThisAppRestClient.get().postCheckTokenAndUser(token, user, new Callback<UserStatusCallBack>() {
#Override
public void success(UserStatusCallBack userStatusCallback, retrofit.client.Response response) {
if(userStatusCallback.getStatus() == 1){
//Invalid token
}else if(userStatusCallback.getStatus() == 2){
//Expired token
}else if(userStatusCallback.getStatus() == 3){
//Success
Intent openMainWindow = new Intent(this, MainActivity.class);
startActivity(openMainWindow);
}
}
#Override
public void failure(RetrofitError error) {
//Retrofit errors like timeouts, etc.
}
}
}
The log in activity would be something like:
logBtn.setOnClickListener(new View.onClick...
String userName = userNameEditText.getText().toString().toLowerCase().trim();
String password = passwordEditText.getText().toString().trim();
if(!TextUtils.isEmpty(userName) && !TextUtils.isEmpty(password)){
callServerLogInScript(userName, password);
}
userNameEditText.setText("");
logBtn.setVisibility(View.GONE);
}
lower down the file:
protected void callServerLogInScript(String user, String pass){
//using retrofit
ThisAppRestClient.get().postCheckTokenAndUser(user, pass, new Callback<LogInCallBack>() {
#Override
public void success(LogInCallBack logInCallback, retrofit.client.Response response) {
if(logInCallback.getLoggedIn() == 1){
//succssful
storeUserNameInSharedPref(user);
storeTokenInSharedPref(logInCallback.getMessage());
Intent openMainActivity = new Intent(this, MainActivity.class);
startActivity(openMainActivity);
}else{
//incorrect log in
logBtn.setVisibility(View.VISIBLE);
}
}
#Override
public void failure(RetrofitError error) {
//Retrofit errors like timeouts, etc.
}
}
}
The reason for not storing the user name and password directly is if the device is rooted they can manipulate the data locally but not on your server.
It depends which you want to use. If you have your own server to host, then use php,mysql. If not, you can also use other third party which provides you to add if you know php,mysql to create.
Another option is if you don't want to use php mysql to store datas, then you can proceed with parse.com
So if you want to use parse.com, just register it. It's free to use.
Hope it will match your requirement, say for eg: if you want to create registration(everything saving in datas will be handled),you need to give exact object name that matches what you given in parse.com
Even you can also create in code itself without object name. I will show you a piece of example how to create and insert for registration..
ParseUser user = new ParseUser();
user.setEmail((txtEmail));//create an edittext and get the values in strings and store..
user.setPassword(txtPassword);//same for password
user.setUsername(txtUsername);//username
user.signUpInBackground(new SignUpCallback() {
public void done(ParseException e) {
if (e == null) {
//completed..it has been registered
Toast.makeText(getApplicationContext(),
"Successfully Signed up, please log in.",
Toast.LENGTH_LONG).show();
finish();
} else {
Toast.makeText(getApplicationContext(),
"Sign up Error", Toast.LENGTH_LONG)
.show();
}
}
});
Simple one if you don't want to use php,mysql. Well documentation and easy to integrate and use it. Happy coding.
FYI: Android studio is IDE for development. And volley is HTTP library that makes networking for Android.

Parse Android: understanding cloud code and deploy

My app is simple as it requires four steps
Step 1:
UserA can create a questionnaire and send it to userB.
Step 2:
UserB receives the questionnaire with three options represented in radio button
Step 3:
UserB chooses the preferable answer that presented in radio button and click submit button
Step 4:
Upon clicking submit button userA receives an email with given answer from userB
However, I used parse for this app and I just started recently learning about cloud code and how to use it since I am trying to fetch sender's (UserA) email from User table but still I am not getting the desired results as I feel I am missing something
My main.js
Parse.Cloud.define("getEmail", function(request, response) {
Parse.Cloud.useMasterKey();
var userQuery = new Parse.Query(Parse.User);
var senderName = userEmail.get("senderId");
userQuery.equalTo("email", request.params.email);
userQuery.get("email", {
success: function(userEmail) {
// the object was retrieved
if ( email == senderName) {
status.message(email + "found");
return getEmail.save;
}
else {
status.message("Invalid email address");
}
},
error: function(object, error) {
status.error("something went wrong")
}
});
});
My android, cloud code function
private void callCodeCloud() {
HashMap<String, String> params = new HashMap<String, String>();
params.put("objectId", objectId);
params.put("email", email);
ParseCloud.callFunctionInBackground("getEmail", params, new FunctionCallback<String>() {
public void done(String email, ParseException e) {
if (e == null) {
Toast.makeText(getApplication(), "Vote Sent", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(getApplication(), "Error", Toast.LENGTH_SHORT).show();
}
}
});
}
private String returnVoteAnswer() {
int nIdRadio = radioVoteGroup.getCheckedRadioButtonId();
if (nIdRadio == R.id.optionone) {
optionONE.setText(mO);
callCodeCloud();
}
else if (nIdRadio == R.id.optiontwo) {
optionTWO.setText(mT);
callCodeCloud();
}
else if (nIdRadio == R.id.optionthree) {
optionTHREE.setText(mH);
callCodeCloud();
}
else{
}
return null;
}
I have been really struggling with this for a while now and I need guidance please. It will be really great achievement for me and fresher by finishing this app as this problem has become an obstacle for me in finishing this app.
Thanks in advance

Get the regToken from a GSResponse

The situation is as following:
I send a login request using the method showLoginUI and then, after selecting a provider (Twitter, g+, etc.) the app goes to the onError callback of my GSLoginUIListener with the error "Account pending registration". Until that point, everything is fine. The problem is when I try to create another GSRequest with the method "accounts.setAccountInfo" like in the following code:
GSRequest setAccountInfoRequest = new GSRequest(getString(R.string.gigya_api_key),"accounts.setAccountInfo");
As parameter, I believe I have to add the regToken but where can I get it? In the iOS SDK, there is an Error object (that you get from the GSResponse that allows you to get it like this:
token = error.userInfo["regToken"]
But there is nothing like that on the Android SDK, from the GSResponse I just can get the error code, error message and error details. So, in short, how can I get the regToken that I need for my request? In the documentation does not go into the details of the actual implementation and I have not seen any examples.
Unlike the iOS and .NET SDKs, the Android SDK does not have a publicly expose or documented GSRequest class, so invoking a request the way you are doing it is not advisable.
Instead, you should use GSAPI.sendRequest with a GSResponseListener. The GSResponseListener will have a response object with the method getData which can be invoked to get a dictionary object of all the parameters returned from the request.
An example of how this can be done is provided in our Gigya CS Android demo hosted on GitHub and can be examined in the file SessionInfoFragment.java#121-191.
public void refreshView() {
GSAPI gigya = GSAPI.getInstance();
final TextView statusText = (TextView) rootView.findViewById(R.id.status_value);
final TextView nameText = (TextView) rootView.findViewById(R.id.name_value);
final TextView emailText = (TextView) rootView.findViewById(R.id.email_value);
final ImageView avatarView = (ImageView) rootView.findViewById(R.id.avatar);
if (gigya.getSession() != null){
if (gigya.getSession().isValid()) {
MainActivity parent = (MainActivity) getActivity();
GSObject user = parent.getUser();
// Retrieve the user if it's not set. (Reloaded app with active session)
if (user == null) {
GSResponseListener resListener = new GSResponseListener() {
#Override
public void onGSResponse(String method, GSResponse response, Object context) {
try {
if (response.getErrorCode()==0) { // SUCCESS! response status = OK
MainActivity parent = (MainActivity) getActivity();
Log.w("Gigya-Android-Demos", "Successfully set user");
parent.setUser(response.getData());
setLoggedIn(statusText, nameText, emailText, avatarView, response.getData());
} else { // Error
Log.w("Gigya-Android-Demos", "GSResponse: 'getAccountInfo' returned an error");
Log.w("Gigya-Android-Demos", response.getErrorMessage());
}
} catch (Exception ex) { ex.printStackTrace(); }
}
};
GSAPI.getInstance()
.sendRequest("accounts.getAccountInfo", null, resListener, null );
} else {
// Grab the user data
setLoggedIn(statusText, nameText, emailText, avatarView, user);
}
} else {
setLoggedOut(statusText, nameText, emailText, avatarView);
}
} else {
setLoggedOut(statusText, nameText, emailText, avatarView);
}
}
public void setLoggedOut(TextView status, TextView name, TextView email, ImageView avatar) {
status.setText(getString(R.string.logged_out));
name.setText(getString(R.string.null_value));
email.setText(getString(R.string.null_value));
setUnknownAvatar(avatar);
}
public void setLoggedIn(TextView status, TextView name, TextView emailView, ImageView avatar, GSObject user) {
status.setText(getString(R.string.logged_in));
try {
GSObject profile = user.getObject("profile");
String first = profile.getString("firstName");
String last = profile.getString("lastName");
String email = profile.getString("email");
if (profile.containsKey("photoURL")) {
setAvatar(avatar,profile.getString("photoURL"));
} else {
setUnknownAvatar(avatar);
}
name.setText(first + " " + last);
emailView.setText(email);
} catch (Exception ex) {
Log.w("Gigya-Android-Demos", "Something went horribly wrong with the user!");
ex.printStackTrace();
}
}
You should notice the use of getData() and GSObject classes throughout the example provided. Using this method of making a request, you should be able to examine the response data including the regToken.

Change from cloud JSON to local JSON

I'm looking at making a change in an app I'm working on (it's based off of this: http://goo.gl/rDBXVl) from loading a cloud based resource to a local based resource. I'm not particularly sure how I would go about doing this. I want to go from pulling a JSON file off the internet to pulling the JSON from my Assets folder.
I located the area in the app where it pulls the URL and loads the JSON but am unsure of what changes to make at this point.
public void loadData (Bundle savedInstanceState) {
// Check Network State
if (!NetworkUtil.getNetworkState(this)) {
final RetryFragment fragment = RetryFragment.getFragmentWithMessage("No connection");
this.addFragment(fragment, RetryFragment.TAG, true);
return;
}
if (savedInstanceState == null || savedInstanceState.get(KEY_LIST_DATA) == null) {
final String url = super.getResources().getString(R.string.config_wallpaper_manifest_url);
if (url != null && URLUtil.isValidUrl(url)) {
// Add Loading Fragment
final LoadingFragment fragment = new LoadingFragment();
this.addFragment(fragment, LoadingFragment.TAG, true);
// Load Data
final RestClientHandler handler = new RestClientHandler(this);
RestClient.get(this, url, handler);
}
} else {
Log.i(TAG, "Restored Instance");
this.mData = (ArrayList<NodeCategory>) savedInstanceState.get(KEY_LIST_DATA);
this.mPosition = savedInstanceState.getInt(KEY_LIST_POSITION);
if (this.mPosition != -1) {
mIgnoreSelection = true;
}
this.configureActionBar();
}
}
You have another option,
just save json in sharedpreferences. so easily read and write it.
Save sharedpreferences code bellow.
/**
* write SharedPreferences
* #param context
* #param name, name of preferences
* #param value, value of preferences
*/
public static void writePreferences(Context context,String name,String value)
{
SharedPreferences setting= context.getSharedPreferences("Give_your_filename", Context.MODE_PRIVATE);
SharedPreferences.Editor editor=setting.edit();
editor.putString(name, value);
editor.commit();
}

Categories

Resources