Make the main thread wait for backgroundtasks to finish? - android

In my app, I want users to be able to register themselves. If another user before them has already used that particular emailadress or username the app should say so and not let them upload data to the server.
Right now my problem is, that the main thread does not wait for the two background tasks that check if username or email already exist, but keeps going so every user object is sent to the server, even though they already exist.
Here is my code to check username and email:
public void checkEmailadress(String s){
ParseQuery<ParseObject> query = ParseQuery.getQuery("userLogin");
query.whereEqualTo("emailadress",s);
query.findInBackground(new FindCallback<ParseObject>() {
#Override
public void done(List<ParseObject> arg0, ParseException e) {
// TODO Auto-generated method stub
Iterator itr = arg0.iterator();
if(itr.hasNext()){
emailadressInUse = true;
}else{
emailadressInUse = false;
}
System.out.println(emailadressInUse);
finishSubmittingUser();
}
});
}
same goes for checking the username. This works fine. The problem is, boolean emailadressInUse does not change fast enough for the main thread to change action.
here is the method that initiates those two methods
public void submitNewUser(View view){
EditText edittext1 = (EditText) findViewById(R.id.chose_username);
EditText edittext2 = (EditText) findViewById(R.id.chose_realname);
EditText edittext3 = (EditText) findViewById(R.id.chose_emailadress);
EditText edittext4 = (EditText) findViewById(R.id.chose_password);
username = edittext1.getText().toString();
realname = edittext2.getText().toString();
emailadress = edittext3.getText().toString();
password = edittext4.getText().toString();
checkUsername(username);
checkEmailadress(emailadress);
}
this is called from inside checkEmail. The two booleans should have changed state by now. And according to System.out.println in checkEmail they did. So why is my method finishSubmittingUser not picking up on that change?
public void finishSubmittingUser(){
if((usernameInUse==false) && (emailadressInUse==false)){
saveDataChange("realname", realname);
ParseObject userLogin = new ParseObject("userLogin");
userLogin.put("username", username);
userLogin.put("emailadress", emailadress);
userLogin.put("password", password);
userLogin.saveInBackground();
Intent intent = new Intent(this, LogInUserActivity.class);
intent.putExtra(USERNAME, username);
startActivity(intent);
}
else{
if(usernameInUse==true){
Toast.makeText(getApplicationContext(),getString(R.string.username_in_use),Toast.LENGTH_SHORT).show();
}
if(emailadressInUse==true){
Toast.makeText(getApplicationContext(),getString(R.string.emailadress_in_use),Toast.LENGTH_SHORT).show();
}
}
}
There must be an easy way to do this that i´m not seeing right now.
Thanks for your help.

Make the main thread wait for backgroundtasks to finish?
As Emmanuel said, do not block the main application thread.
Right now my problem is, that the main thread does not wait for the two background tasks that check if username or email already exist, but keeps going so every user object is sent to the server, even though they already exist.
If "every user object is sent to the server" is something the user does, after registration, simply disable the UI for that (e.g., disable the action bar item) until your registration is confirmed.
If "every user object is sent to the server" is something that happens automatically after a successful registration, then you should not be executing that code until after a successful registration.

Related

Password comparing in Android

So I have stored password as hash in shared preferences, when user puts password I need to make a hash of it and compare with stored one.
Should it be done in AsyncTask or Thread because calculation and comparison could freeze UI? And then do you know a clean way to recieve result (true, false) from asynctask or thread?
public void startGenerateCode(View view) {
String pinCompare = pin; //pin is class variable obtained from editText
pinCompare = tools.bin2hex(tools.getHash(pinCompare));
if(pinCompare.compareTo(session.getDetails("Pin"))==0){
generateCode();
}
else
Toast.makeText(this, "Wrong PIN", Toast.LENGTH_SHORT).show();
}
public void generateCode(){
Intent i = new Intent(this, GeneratedCode.class);
startActivity(i);
overridePendingTransition(R.anim.right_slide_in, R.anim.right_slide_out);
finish();
}
This is done in activity after button is pressed.
Zolo,
I guess this process is triggered when someone presses a Button, such as login. I don't think you need any extra Thread to process the Hash calculus.
If you then have to connect to a server and send/receive data, then you should use it due to the asynchronous flow.
Response to comments on main post:
Yes, you can start an Activity in onPostExecute.
Code example:
public void startGenerateCode(View view) {
// Disable button
Button button = (Butto) view;
button.setEnabled(false);
String pinCompare = pin; //pin is class variable obtained from editText
pinCompare = tools.bin2hex(tools.getHash(pinCompare));
if(pinCompare.compareTo(session.getDetails("Pin"))==0){
generateCode();
} else {
// If the login fails, re-enable the button to try again
button.setEnabled(true);
Toast.makeText(this, "Wrong PIN", Toast.LENGTH_SHORT).show();
}
}
I did it by heart, so there may be mistakes.

Create Login/Registration view from a main activity

Im starting to get crazy on my problem here.
I have a main activity that connects to a server on onCreate event, (the program must be connected to the server or else it shall not be working).
client_thread = new ServerCom(this);
Now I want to create a login view with (Username, Password and Login buttom with a user exist validation).
And when there is a login view there has to be some sort of registration view (with Username, Password, confim Password and a Registration button with a user exist validation).
I have create a Login and Registration Activity (for handeling some data with login and registration).
public ClassLogIn(MainActivity owner)
{
this.owner = owner;
}
public ClassLogIn()
{
}
public void onClick(View view) {
if(view == btnLogIn)
{
if(TextUtils.isEmpty(userName.getText()) == false) {
if (TextUtils.isEmpty(userPassword.getText()) == false) {
owner.LogIn(userName.getText(),userPassword.getText());
}
...
To start the activitys from my mainActivity I have done this
else if(id == R.id.action_login){
Intent myIntent = new Intent(MainActivity.this, ClassLogIn.class);
startActivity(myIntent);
}
else if(id == R.id.action_registera){
Intent myIntent = new Intent(MainActivity.this, ClassRegistera.class);
startActivity(myIntent);
}
else if(id == R.id.action_Logout)
{
client_thread.LogOut();
}
Now my problem is how can I get the userName value to my client_thread?
And also how can I call Owner.LogIn from my ClassLogIn activity?
public boolean LogIn(Editable UserName, Editable Password)
{
return client_thread.LogIn(UserName.toString(),Password.toString());
}
Or do I trying to make something that is impossible in Android?
From the top of my head set up some IntentServies to catch intents and make then
set up your variables.
And static variables are not an option ?
(Would add a comment but don't have enough reps)
The specific code to do the following can differ depending on your specifics.
But in general, the procedure we do is the following:
NOTE - We use the WorkingStorage API to save parameters directly into the HHU (Hand Held Unit)
When we initially launch we make an attempt to retrieve from within the HHU the login credentials which includes an Authorization ID.
If they are present, we utilize the Authorization ID for subsequent WebService calls as needed throughout the Activities.
If they are Not present, we launch a User Data Entry 'screen' and get Username & Password input.
Then we send that data to the Server via a WebService call for validation.
The WebService responds to the HHU with a Result.
That Result is either a Valid Authorization ID or an Error Message (such as 'Not Valid', etc.).
If it is a Valid Authorization ID, then all of the login credentials are saved to the HHU with the WorkingStorage API and are then available to be utilized for subsequent WebService calls.

Trying to get an Android jabber app to check for a string in new messages and return a toast message

I have been able to create the if statement that checks for the string and it returns the toast message that i created but it keeps showing the toast message every time i open the chat. even if the most recent message doesn't contain the string I am looking for so i am assume it isn't checking to see if it is the last message received and it doesn't check to see if it is unread. the code is below. the reason i am trying to do this is because my parents share a facebook account and i want an easy way to display if the message is signed mom or dad. the code below only has the check for mom once it works i will be adding the check for dad signature. I am using the open source message client Xabber. Thank you for help.
public void setVisibleChat(String account, String user) {
final boolean remove = !AccountManager.getInstance()
.getArchiveMode(account).saveLocally();
AbstractChat chat = getChat(account, user);
if (chat == null)
chat = createChat(account, user);
else {
// Mark messages as read and them delete from db if necessary.
final ArrayList<MessageItem> messageItems = new ArrayList<MessageItem>();
for (MessageItem messageItem : chat.getMessages()) {
if (!messageItem.isRead()) {
messageItem.markAsRead();
messageItems.add(messageItem);
}
if (chat.getLastText().contains("Mom") && (!messageItem.isRead()));{
Toast.makeText(Application.getInstance(), "Message from Mom!", Toast.LENGTH_SHORT).show();
}
}
Application.getInstance().runInBackground(new Runnable() {
#Override
public void run() {
Collection<Long> ids = getMessageIds(messageItems, remove);
if (remove)
MessageTable.getInstance().removeMessages(ids);
else
MessageTable.getInstance().markAsRead(ids);
}
});
}
visibleChat = chat;
}
You've got an extra semi-colon here
if (chat.getLastText().contains("Mom") && (!messageItem.isRead())); <------
So your next block of code containing the Toast show statement will always be executed.
Remove the semi-colon

Android - some code executes after the phone went to a different Activity

I have a strange scenario here.
I have this code:
// For checking if the person is logged in.
first_time_check();
setContentView(R.layout.main);
// ...next lines of code
and the first_time_check() function checks if the user is logged in for the first time. If their user_id is not in the SharedPreferences, I redirect them to log in:
public void first_time_check()
{
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences( ProblemioActivity.this);
String user_id = prefs.getString( "user_id", null ); // First arg is name and second is if not found.
String first_time_cookie = prefs.getString( "first_time_cookie" , null );
// About setting cookie. Check for first time cookie
if ( first_time_cookie == null )
{
// This user is a first-time visitor, 1) Create a cookie for them
first_time_cookie = "1";
// 2) Set it in the application session.
prefs.edit().putString("first_time_cookie", first_time_cookie ).commit();
// Make a remote call to the database to increment downloads number
// AND send me an email that it was a new user.
}
else
{
// If not first time, get their id.
// If user_id is empty, make them an account.
// If id not empty, call the update login date and be done.
if ( user_id == null )
{
// User id is null so they must have logged out.
Intent myIntent = new Intent(ProblemioActivity.this, LoginActivity.class);
ProblemioActivity.this.startActivity(myIntent);
}
else
{
// Make a remote call to the database to increment downloads number
}
}
return;
}
So after the code executes the
Intent myIntent = new Intent(ProblemioActivity.this, LoginActivity.class);
ProblemioActivity.this.startActivity(myIntent);
it still executes below the original code that calls this functions.
Any idea how that can happen?
Thanks!!
This is excerpted from the Dev Guide
Shutting Down an Activity
You can shut down an activity by calling its finish() method.
You can also shut down a separate activity that you previously
started by calling finishActivity().
Note: In most cases, you should not explicitly finish an activity
using these methods. As discussed in the following section about the
activity lifecycle, the Android system manages the life of an
activity for you, so you do not need to finish your own activities.
Calling these methods could adversely affect the expected user
experience and should only be used when you absolutely do not want
the user to return to this instance of the activity.
Calling finish() on the activity seems appropriate here as you do not want the user to return to this activity.

Register not able to be done due to error checking in the if..else statement

I got problem with register. I use an if-else statement to check whether the user left any blank. If there is any blank, an error message will appear. The problem is, even with no blanks, all filled up, the error message still appears and thus prevents user from registering. I can't find any error.
Please help me spot my error.
package log1.log2;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
public class Login extends Activity {
DBAdapter db = new DBAdapter(this);
/** Called when the activity is first created. */
private EditText etUsername;
private EditText etPassword;
private Button btnLogin;
private Button btnRegister;
private TextView lblResult;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Get the EditText and Button References
etUsername = (EditText)findViewById(R.id.usernametxt);
etPassword = (EditText)findViewById(R.id.passwordtxt);
btnLogin = (Button)findViewById(R.id.btnLogin);
btnRegister = (Button)findViewById(R.id.btnRegister);
lblResult = (TextView)findViewById(R.id.msglbl);
//Cursor c = (Cursor) db.getAllTitles();
//Button btnArrival = (Button) findViewById(R.id.btnRegister);
//btnArrival.setOnClickListener(this);
// Set Click Listener
btnRegister.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Intent intent=new Intent(Login.this,Register.class);
startActivity(intent);
}
});
btnLogin.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v)
{
db.open();
Cursor c = (Cursor) db.getAllUser();
c.moveToFirst();
// Check Login
String username = etUsername.getText().toString();
String password = etPassword.getText().toString();
if(username.equals("") || password.equals(""))
{
Context context = getApplicationContext();
int duration = Toast.LENGTH_LONG;
Toast toast = Toast.makeText(context, "FILL IN ALL FIELDS", duration);
toast.show();
}
else
{
if(username.equals(c.getString(1)))
{
if(password.equals(c.getString(2)))
{
Context context = getApplicationContext();
int duration = Toast.LENGTH_LONG;
Toast toast = Toast.makeText(context, "LOGIN SUCCESS", duration);
toast.show();
long id;
id = db.insertTransaction(
new String(etUsername.getText().toString()));
Intent intent=new Intent(Login.this,Test.class);
startActivity(intent);
}
else
{
Context context = getApplicationContext();
int duration = Toast.LENGTH_LONG;
Toast toast = Toast.makeText(context, "LOGIN FAIL", duration);
toast.show();
}
}
else
{
Context context = getApplicationContext();
int duration = Toast.LENGTH_LONG;
Toast toast = Toast.makeText(context, "LOGIN FAIL", duration);
toast.show();
}
}
db.close();
}
});
}
}
Thank you very much.
Dayne,
I'm gonna try to help you here. Before I do, though, I want you to understand that you have been violating a lot of the conventional rules of stack overflow. I put a lot of time into trying to sort out your issues in this question, so I want to ask you to take a bit of time and try to understand what it is that you are doing wrong that makes others users on stack overflow (including me) very annoyed.
First, please don't use all caps. It is considered rude. Second, please don't post multiple questions on stack overflow that are all about the same issues. This is the 7th question that you have posted regarding this issue. That is also considered rude. Please post one question, and if the suggested answers do not work for you, then comment on them and ask for more help, specifying what part of their answer you used and what problems you are having still. Third, please do not post your entire file. If your entire file is needed the the commentors will ask you to post it, but don't post it up front. Consider that the people who are helping you with your questions are NOT getting paid. They are doing it for free, as a service to people trying to learn how to program. Posting your entire file up front is like you are asking someone to do your work for you, and the users on here are not interested in doing your work, they are interested in helping people learn. We want you to be able to do this stuff yourself. If you just want a solution that works and are not interested in learning why it works, you would be better off choosing a different community of people to ask questions to. Lastly, please try to research more! A lot of your questions betray that you are utterly clueless about how certain things work. Please, rather than simply posting on stackoverflow again and again, go spend a few hours reading up on how to create a login system in Android
That being said, you seem like a nice enough person to me. It looks like you are new to stack overflow and new to programming in general, so I am willing to forgive all those things you did that annoyed me, as long as you do your best to not do them again.
General Issues with your code
Ok, let's get into the general point of your code code. I have tried to fix your code to the point that it compiles and works. However, I want to point out that what you are trying to do is largely useless for any practical program. If I understand you correctly, you are trying to have a user login to some service or be able to register for that service. However, it looks like you are trying to use a database on the phone to log users in or register new users. If you have a database of usernames and passwords stored on a phone, then there is no way to have another user login. Let me give you an example. User A has a phone, and user B has a phone. If the database of usernames and passwords is stored on user A's phone, then how will user B login? Additionally, how would user B register for the service? There is reliable way to communicate between the two phones. On top of that, what if user A drops their phone and it breaks? Does that mean that your entire service is unavailable?
What you need to do, if you are providing login/registration for some service, is to have a server set up somewhere that phones can contact to perform login operations or registration operations. Setting up a server and a login/registration system is a big project, and you will need to read up on how to do that before anyone can really help you - right now I dont think you would understand most of the advice they would give you.
That being said, it is possible that you just want to get this local database login system to work for some reason (perhaps you just want something to work, all programmers have had a point where nothing they do seems to work and you are desperate to make anything work ;) ). So, let's see if we can make it work . . .
Separation of responsibility
You are trying to solve 2 main problems (I am ignoring registration for now. If you understand login then you can figure out registration). First, you want to provide some feedback to the user if they do not give you a username or a password. Second, you want to check if that person has provided a correct username / password combination. Right now you are trying to solve both of these problems within the Login Activity. I recommend separating these responsibilities - let the Login class handle providing feedback, and slightly modify your DBAdapter class so that it can handle checking the username/password.
Modify your DBAdapter class and add the following method:
public boolean isValidUser(String username, String password) {
Cursor c = <your SQLiteDatabase>.rawQuery("SELECT username FROM Users WHERE username='?' AND password='?'", new String[] {username, password});
boolean result = c.moveToFirst();
return result;
}
Please note that this method has a lot of problems, and should not be used in production code. I am assuming you just want this to work, and you don't care if it is perfect. If you can get this all working, perhaps ask a new question focused on verifying that a username / password combination is correct.
Note that you need to change the part that says <your SQLiteDatabase> to contain your database name.
Once you have added this method, your DBAdapter class can, given a username and password, inform you if that username and password combination is valid.
Making the Login Activity
Change the btnLogin onClickListener to this:
btnLogin.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
String username = etUsername.getText().toString();
String password = etPassword.getText().toString();
if (username.trim().equals("") || password.trim().equals("")) {
Context context = getApplicationContext();
int duration = Toast.LENGTH_LONG;
Toast toast = Toast.makeText(context, "FILL IN ALL FIELDS",
duration);
toast.show();
// Rather than having a huge else {} block, why not just add a
// return statement here? Then the rest of your code is a bit
// cleaner!
return;
}
db.open();
if (db.isValidUser(username, password))
{
Context context = getApplicationContext();
int duration = Toast.LENGTH_LONG;
Toast toast = Toast.makeText(context,
"LOGIN SUCCESS", duration);
toast.show();
Intent intent = new Intent(Login.this, Test.class);
startActivity(intent);
} else {
Context context = getApplicationContext();
int duration = Toast.LENGTH_LONG;
Toast toast = Toast.makeText(context, "LOGIN FAIL",
duration);
toast.show();
}
db.close();
}
});
That should be all you need to get this to work! Note, however, that you didn't post your DBAdapter class here. I didn't want to look through the 7 posts to find it. Given the state of this post's code and the one other I looked at, it's likely that there are some errors in your DBAdapter. Read this section on the Android docs and try to debug that part yourself :) If you get stuck, you can ask a question about how to build a database on Android, and NOT a question about how to build a database/login on Android, since your login code should be mostly workable if you use the code I pasted here!
Final Points
Please consider the following comments I made when originally looking at your code
// NO!!!! Do not do this. You will end up with a problem
// very similar to http://stackoverflow.com/questions/3352957/
// why-does-not-this-work-android-oncreate/3352978#3352978
// Instead, say db = new DBAdapter(this) inside of the onCreate() method!
DBAdapter db = null; // new DBAdapter(this);
Also,
// This is an absolutely huge inner-class. It would be a lot better
// to extract this into a private member variable, by saying
// OnClickListener foo = new OnClickListener() { <put all code here> };
// btnLogin.setOnClickListener(foo);
btnLogin.setOnClickListener(new OnClickListener() {
Also,
// No!! If you are calling getAllUser(), you are likely returning a Cursor that points
// to a ton of users. The way your code is now, you are returning a list of all users
// in the application, and then checking to see if this data entered matches the first
// user. This would never work! If you have more than one user, then you need to check
// if the data entered matches ANY of your users. I am removing this code
// db.open();
// Cursor c = (Cursor) db.getAllUser();
// c.moveToFirst();
Cheers,
Hamilton
I think you need to do username.getText().equals(""), not just .equals because in that case you try to compare the empty string to the EditText object...

Categories

Resources