Q:

Validation of EditText's does not work

I have a signup screen. It contains a place for the user's full name, email address and password (the user has to confirm their password). 
However, it does not work as expected. For the signup button to be enabled the fields have to filled in, in order: top to bottom (this wasn't intended). 
Moreover, the red colour on the confirm password field does not go away and the signup button does not enable unless the characters are shown. The checking to see if there are characters in all the fields seem to be malfunctioning and I am not sure why. The checking works sometimes and doesn't work other times.
Please can someone help me optimize this. There are comments in the code to show what each method does.
This is the Layout:
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:orientation="vertical"> 

    <EditText
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:inputType="textPersonName"
        android:hint="@string/hintNameField"
        android:ems="10"
        android:id="@+id/txtSName"
        android:layout_marginTop="30dp"
        android:layout_marginLeft="5dp"
        android:layout_marginRight="5dp" />

    <EditText
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:inputType="textEmailAddress"
        android:hint="@string/hintEmailField"
        android:ems="10"
        android:id="@+id/txtSEmailAddress"
        android:layout_marginTop="15dp"
        android:layout_marginLeft="5dp"
        android:layout_marginRight="5dp" />

    <EditText
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:inputType="textPassword"
        android:ems="10"
        android:id="@+id/txtSPassword"
        android:hint="@string/hintPasswordField"
        android:layout_marginTop="15dp"
        android:layout_marginLeft="5dp"
        android:layout_marginRight="5dp"/>

    <EditText
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:inputType="textPassword"
        android:ems="10"
        android:id="@+id/txtSPasswordConfirm"
        android:hint="@string/hintPasswordConfirmField"
        android:layout_marginTop="15dp"
        android:layout_marginLeft="5dp"
        android:layout_marginRight="5dp"
        />

    <CheckBox
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/showPasswordCheckBox"
        android:id="@+id/showPasswordCheckBox"
        android:layout_marginTop="10dp"
        android:layout_marginLeft="5dp"/>

    <Button
        android:layout_width="200dp"
        android:layout_height="wrap_content"
        android:text="@string/btnSignUp"
        android:id="@+id/btnSignUp"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="10dp"
        android:enabled="false"
        />

</LinearLayout>

This is the Java class for the layout:
//this is the full name field
snameTxt = (EditText) findViewById(R.id.txtSName);
snameTxt.addTextChangedListener(new TextWatcher() {
    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
    }

    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {

    }

    @Override
    public void afterTextChanged(Editable s) {

    }
});

snameTxt.setOnLongClickListener(new View.OnLongClickListener() {
    @Override
    public boolean onLongClick(View v) {
        Toast.makeText(getApplicationContext(), "Please enter your full name", Toast.LENGTH_SHORT).show();
        return false;
    }
});

//this is the email address field
semailTxt = (EditText) findViewById(R.id.txtSEmailAddress);
semailTxt.addTextChangedListener(new TextWatcher() {
    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {

    }

    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {

    }

    @Override
    public void afterTextChanged(Editable s) {

    }
});

semailTxt.setOnLongClickListener(new View.OnLongClickListener() {
    @Override
    public boolean onLongClick(View v) {
        Toast.makeText(getApplicationContext(), "Please enter the email address to be associated with your account", Toast.LENGTH_SHORT).show();
        return false;
    }
});

//this is the password field
spasswordTxt = (EditText) findViewById(R.id.txtSPassword);
    spasswordTxt.addTextChangedListener(new TextWatcher() {
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
    }

    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {
        //the code to enable the button. This needs the most optimization
        if (String.valueOf(spasswordTxt.getText()).trim().length() > 3 && 
            String.valueOf(snameTxt.getText()).trim().length() > 0 && 
            String.valueOf(semailTxt.getText()).trim().length() > 0) {
            signupBtn.setEnabled(true);
        } else {
            signupBtn.setEnabled(false);
        }
        if (String.valueOf(spasswordTxt.getText()).trim().length() < 3) {
            signupBtn.setEnabled(false);
        }
        if (String.valueOf(snameTxt.getText()).trim().length() < 1) {
            signupBtn.setEnabled(false);
        }
        if (String.valueOf(semailTxt.getText()).trim().length() < 1) {
            signupBtn.setEnabled(false);
        }
    }

    @Override
    public void afterTextChanged(Editable s) {

    }
});

spasswordTxt.setOnLongClickListener(new View.OnLongClickListener() {
    @Override
    public boolean onLongClick(View v) {
        Toast.makeText(getApplicationContext(), 
            "Please enter a password with a minimum of 4 characters", Toast.LENGTH_SHORT).show();
        return false;
    }
});

spasswordconfirmTxt = (EditText) findViewById(R.id.txtSPasswordConfirm);
spasswordconfirmTxt.addTextChangedListener(new TextWatcher() {
    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {

    }

    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {
        //if the password and the password confirm fields do not match 
        //then the password confirm field goes red. This also needs optimization
        if (spasswordconfirmTxt.getText().toString().equals(spasswordTxt.getText().toString())) {
            spasswordconfirmTxt.getBackground().clearColorFilter();
        }
        else {
            spasswordconfirmTxt.getBackground().setColorFilter(Color.RED, PorterDuff.Mode.SRC_ATOP);
            signupBtn.setEnabled(false);
        }
    }

    @Override
    public void afterTextChanged(Editable s) {

    }
});

 //this allows the password field characters to be shown
final CheckBox showPasswordCheckBox = (CheckBox) findViewById(R.id.showPasswordCheckBox);
showPasswordCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
    @Override
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
        if(!isChecked){
            spasswordTxt.setTransformationMethod(PasswordTransformationMethod.getInstance());
            spasswordconfirmTxt.setTransformationMethod(PasswordTransformationMethod.getInstance());
        }
        else {
            spasswordTxt.setTransformationMethod(HideReturnsTransformationMethod.getInstance());
            spasswordconfirmTxt.setTransformationMethod(HideReturnsTransformationMethod.getInstance());
        }
    }
});

A:

I sugget you to use some convenience methods, this would help you to write code which is clearer. For example use this method to check if a field contains a valid strihg:
/ Checks if a String actually carries information
public static boolean isValidString(String string) {
    if (string == null) {
        return false;
    } else {
        String s = string.trim(); // Remove blank spaces at start and at end
        if ((s.length() == 0) || (s.equalsIgnoreCase(""))) return false;
        else return true;
    }
}

Going specifically to your problem, I see that the actual validation of the fields is done in the onTextChanged(...) method of the password field, therefore it's obvious that filling the password field at last would carry out the validation, otherwise if you fill the password for first and then go to the other fields, their onTextChanged(...) simply does nothing, therefore the validation isn't carried out. You should add a method which is called in every single onTextChanged(...) callback!
For the red colored field, I am not sure if that's the correct approach to adopt, just try to use some different ways to give visual clues, See my blog post for example.
However I see that you're not doing the check and therefore not enabling properly the submit button when onTextChanged(...) is fired in the confirmation field, I think you forgot something:
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
    //if the password and the password confirm fields do not match 
    //then the password confirm field goes red. This also needs optimization
    if (spasswordconfirmTxt.getText().toString().equals(spasswordTxt.getText().toString())) {
        spasswordconfirmTxt.getBackground().clearColorFilter();
        signupBtn.setEnabled(true); // Enable the button if everything is ok
    }
    else {
        spasswordconfirmTxt.getBackground().setColorFilter(Color.RED, PorterDuff.Mode.SRC_ATOP);
        signupBtn.setEnabled(false);
    }
}

So bottom line is, create another method from which you check all the fields together, which will also enable the button if all check are ok, and make a call to that method whenever ANY of onTextChanged(...) callbacks is fired!
Cheers!

