Skip to content

Code Theory

Web and Mobile Development articles

  • Home
  • About
  • Contact

Building a Single Integrated Registration and Login System on Android with Parse.com

Update: Parse is shutting down. So you should start migrating.

In this article we’ll build a login screen which will be somewhat similar to whatsapp’s login screen. So the login and registration screens will actually be the same and the unique identifier for each user will be their phone numbers. So to quickly summarize, here are the fields we’ll have:

  • First Name – This will accept and store the user’s first name.
  • Last Name – This will accept and store the user’s last name.
  • Country – This will be a simple dropdown holding the user’s country.
  • Country Phone Code – Store the country’s phone number code.
  • Phone Number – This will accept and store the user’s phone number which will be the unique identifier for each user.

As the backend, we won’t build our custom solution from scratch but leverage Parse.com to store all the user details. Parse’s SDK will help us with logging in and signing up the user as well as with other features like logout by maintaining the session on disk.

Installing and Setting Up Parse

Let’s quickly install and setup parse for our application with the following steps:

  • Signup for a new account on Parse.com.
  • Create a new app with your app’s name. All your application keys will be accessible here (Application Keys tab under Settings).
  • Next go to the Quickstart wizard from where after making your selections through the subsequent steps you’ll end up at the SDK Installation guide. Download the latest SDK from the link given there – https://parse.com/downloads/android/Parse/latest
  • Extract the zip file downloaded and move the Parse-*.jar file to the `libs` directory of your project.
  • Before using the Parse library, we must call Parse.initialize(context, PARSE_APPLICATION_ID, PARSE_CLIENT_KEY) once to set our application ID and client key. We can do this in the onCreate method of our Application class. Here’s a really good article that
    explains what an Application class is and how to set it up.
  • Installation complete!

Note: We’ll need the INTERNET and ACCESS_NETWORK_STATE permissions, hence add this in the AndroidManifest.xml file before the <application> tag:

[java]
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
[/java]

You can test the library with a simple piece of code:

[java]
ParseObject testObject = new ParseObject("TestObject");
testObject.put("foo", "bar");
testObject.saveInBackground();
[/java]

This code creates a new object of class TestObject (think of it as a Database Table or Collection) and saves a new row with the value of “bar” under the “foo” column. You can either click the “Test” button on the Parse SDK installation page or examine the data in the Parse Data Browser.

Coding into the Project

Parse is up and running so we should start coding the user interface and functionality into our app. We’ll start off with a very basic UI for our login cum registration/signup screen.

[xml]
<RelativeLayout 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"
tools:context="com.pycitup.pyc.LoginActivity">

<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/firstName"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:hint="First Name"
android:inputType="textCapWords" />

<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/lastName"
android:layout_below="@+id/firstName"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:hint="Last Name"
android:inputType="textCapWords" />

<Spinner
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/country"
android:layout_below="@+id/lastName"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="+"
android:id="@+id/plusSign"
android:layout_alignTop="@+id/countryCode"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignBottom="@+id/countryCode"
android:layout_marginTop="10dp"
/>

<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/countryCode"
android:width="50dp"
android:hint="1"
android:layout_below="@+id/country"
android:layout_toRightOf="@+id/plusSign"
android:inputType="number"
/>

<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/phoneNumber"
android:hint="phone number"
android:layout_below="@+id/country"
android:layout_alignRight="@+id/country"
android:layout_alignEnd="@+id/country"
android:layout_toRightOf="@+id/countryCode"
android:inputType="phone" />

<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Login"
android:id="@+id/loginButton"
android:layout_centerVertical="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />

</RelativeLayout>
[/xml]

Nothing complicated, all very simple XML objects for our different views. One interesting thing to notice is the android:inputType XML attribute. This attribute defines the content type of the text held by the Editable object. It can hold multiple values separated by the bitwise OR (|) operator. For a comprehensive list of content types, check here.

Here are the different input types we’ve used:

  • textCapWords: This leads to the soliciting of capitalization of the first character of each view. In effect, when you focus on the field and the keyboard slides up, the first character you type appears in uppercase and then the typing mode changes to lowercase.
  • number: A numeric only field, hence the keyboard type will only contain numbers.
  • phone: Phone number field, hence the keyboard type will appear like a dialer and contain characters pertinent to phone numbers.

Since we’re done with defining our views, we’ll move onto writing the code in our Activity file that’ll deal with the functionality (including communication with Parse). So here’s the code that should go into a new Activity file called LoginActivity.

[java]
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Spinner;

import com.parse.FindCallback;
import com.parse.LogInCallback;
import com.parse.ParseException;
import com.parse.ParseQuery;
import com.parse.ParseUser;
import com.parse.SignUpCallback;

import java.util.ArrayList;
import java.util.List;

public class LoginActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);

// All the views from our login form
final EditText firstNameView = (EditText) findViewById(R.id.firstName);
final EditText lastNameView = (EditText) findViewById(R.id.lastName);
final Spinner countryView = (Spinner) findViewById(R.id.country);
final EditText countryCodeView = (EditText) findViewById(R.id.countryCode);
final EditText phoneNumberView = (EditText) findViewById(R.id.phoneNumber);
Button loginButtonView = (Button) findViewById(R.id.loginButton);

// Set items for the Spinner dropdown
ArrayList<String> countries = new ArrayList<String>();
countries.add("Australia");
countries.add("Brazil");
countries.add("China");
countries.add("Canada");
countries.add("India");
countries.add("Russia");
countries.add("Singapore");
countries.add("United States");

// Create the adapter for the spinner
ArrayAdapter adapter = new ArrayAdapter(this, android.R.layout.simple_spinner_item, countries);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);

// Attach the adapter to the spinner
countryView.setAdapter(adapter);

// On login button click
loginButtonView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {

// Get the values of all the form fields

final String phoneNumber = phoneNumberView.getText().toString().trim();
String firstName = firstNameView.getText().toString().trim();
String lastName = lastNameView.getText().toString().trim();
String countryCode = countryCodeView.getText().toString().trim();
String country = countryView.getSelectedItem().toString().trim();

// Simple validation: if any field is empty then don’t let the form submit
// and show an alert dialog with error message
if (phoneNumber.isEmpty() || firstName.isEmpty() || lastName.isEmpty() || countryCode.isEmpty() || country.isEmpty()) {
AlertDialog.Builder builder = new AlertDialog.Builder(LoginActivity.this);
builder.setMessage("Please make sure you entered all the fields correctly.")
.setTitle("Oops!")
.setPositiveButton(android.R.string.ok, null);
AlertDialog dialog = builder.create();
dialog.show();

return;
}

// Create a ParseUser object to create a new user
final ParseUser user = new ParseUser();

user.setUsername(phoneNumber);
user.setPassword("Fake Password");
user.put("firstName", firstName);
user.put("lastName", lastName);
user.put("country", country);
user.put("countryCode", countryCode);

// First query to check whether a ParseUser with
// the given phone number already exists or not
ParseQuery<ParseUser> query = ParseUser.getQuery();
query.whereEqualTo("username", phoneNumber);

query.findInBackground(new FindCallback<ParseUser>() {
@Override
public void done(List<ParseUser> parseUsers, ParseException e) {

if (e == null) {
// Successful Query

// User already exists ? then login
if (parseUsers.size() > 0) {
loginUser(phoneNumber, "Fake Password");
}
else {
// No user found, so signup
signupUser(user);
}
}
else {
// Shit happened!
AlertDialog.Builder builder = new AlertDialog.Builder(LoginActivity.this);
builder.setMessage(e.getMessage())
.setTitle("Oops!")
.setPositiveButton(android.R.string.ok, null);
AlertDialog dialog = builder.create();
dialog.show();
}
}
});
}
});
}

private void loginUser(String username, String password) {
ParseUser.logInInBackground(username, password, new LogInCallback() {
public void done(ParseUser user, ParseException e) {
if (user != null) {
// Hooray! The user is logged in.

navigateToHome();
} else {
// Login failed!
AlertDialog.Builder builder = new AlertDialog.Builder(LoginActivity.this);
builder.setMessage(e.getMessage())
.setTitle("Oops!")
.setPositiveButton(android.R.string.ok, null);
AlertDialog dialog = builder.create();
dialog.show();
}
}
});
}

private void signupUser(ParseUser user) {
user.signUpInBackground(new SignUpCallback() {
@Override
public void done(ParseException e) {
if (e == null) {
// Signup successful!

navigateToHome();
} else {
// Fail!
AlertDialog.Builder builder = new AlertDialog.Builder(LoginActivity.this);
builder.setMessage(e.getMessage())
.setTitle("Oops!")
.setPositiveButton(android.R.string.ok, null);
AlertDialog dialog = builder.create();
dialog.show();
}
}
});
}

private void navigateToHome() {
// Let’s go to the MainActivity
Intent intent = new Intent(LoginActivity.this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.login, menu);
return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
[/java]

In the onCreate method the views objects are fetched, few countries are assigned to the spinner and an “onclick” listener is set on the login button. According to the code inside the onClick method of the View.OnClickListener interface implemented we take the values of each view and check if any of those is empty or not. If it is then an error is shown else the communication with Parse starts happening.

This is the flow of the queries made to Parse logically:

  • A ParseQuery object is first created to check whether any user with the submitted phone number exists or not. Based on this value we’ll decide whether we need to login this user or signup (register).
  • If a user is found then the loginUser method is called where the handy class method logInInBackground on the ParseUser class is passed the username (phone number) and password (a fake one) to sign in the user.
  • If a user is not found then the signupUser method is called where the ParseUser object passed to it is made to signup by calling the signUpInBackground method on it.
  • When the login or signup is successful the navigateToHome method is called that invokes the MainActivity (home screen in our case) using an Intent.

If you notice, I’ve used 2 intent flags in the navigateToHome() method:

[java]
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
[/java]

Those flags help with eliminating the LoginActivity from the tasks back stack, so that when you hit the back button after login, you won’t end up on the login screen again. Another way to achieve this behaviour is to use android:noHistory attribute of the relevant <activity> tag in the AndroidManifest.xml. When set to true, it won’t leave a historical trace in the activity stack for the task.

Let me enumerate a couple of strange decisions taken in the code or some optimization that could be done or standards followed for the better:

  • We use phone number as the unique identifier and have no username or email. But at the same time, the username is required (and maintained as unique) on Parse’s side. So to work in accordance with their rules, I used phone number for the username field. This helps me to conform their required rule as well as maintain phone numbers in a unique field.
  • We have no password, so I used a sample string called “Fake Password” that again complies with the Parse rules of having the password field as required.
  • Instead of using strings directly as titles and messages for the Alert Builders, you’d want to set them in the strings resource file and reference them from the Activity’s code. I used strings directly to keep things short and to the point of the topic’s context.
  • Instead of having so many final variables, we could probably set them as instance/member variables.

To make sure that the user is always logged in before using the app, we can add this piece of code to redirect the user to the login screen (when he launches the app) in the “main” activity’s onCreate method.

[java]
// Get current user
ParseUser currentUser = ParseUser.getCurrentUser();

if (currentUser == null) {
// It’s an anonymous user, hence show the login screen
navigateToLogin();
}
else {
// The user is logged in, yay!!
Log.i(TAG, currentUser.getUsername());
}
[/java]

This is how the navigateToLogin() method will look like:

[java]
private void navigateToLogin() {
// Launch the login activity

Intent intent = new Intent(this, LoginActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
}
[/java]

We can add a logout button to the overflow menu that’ll execute this piece of code in the onOptionsItemSelected method of the Activity class:

[java]
ParseUser.logOut();
navigateToLogin();
[/java]

Easy peasy!

Next Up

We discussed how to make a single screen to server login’s and registration’s purpose. It’s always good, safe and secure to validate the user on signup like sending him an email to activate his account. Since we don’t ask the user for his email but phone number, what we could do is send him an SMS with an activation code that he’ll need to put in the signup flow after submitting the form. I’ll discuss how to do that in the next post.

Author: Rishabh

Rishabh is a full stack web and mobile developer from India. Follow me on Twitter. View all posts by Rishabh

Author RishabhPosted on May 6, 2025Categories Mobile DevelopmentTags android, login, mobile, parse, registration, signup

Post navigation

Previous Previous post: Android Dividing Your ListView Into Sections with Group Headers
Next Next post: Adding Search Functionality to Your Android Application Activity with SearchView and Search Dialog

Recent Posts

  • How to find a pattern with re.search in a Python string
  • How to pass **kwargs inside a Python function
  • How to override a method in a Python class

Subscribe

  • Follow on Twitter
  • RSS Feeds
  • Subscribe by Email
  • Home
  • About
  • Contact
Code Theory Proudly powered by WordPress