Sunday, February 10, 2013

on Leave a Comment

Parse For Android: A Simple Login Starter Project (with Otto Service Bus!)

Recently I did a brief overview of Parse and all the amazing things it offers mobile developers. Parse comes with some great API documentation but if you check the sample projects you will find that it is sorely lacking in the Android department space (and well pretty much anything besides iOS). Being that I was already well on my way with Parse in an Android project I thought it may be helpful to share some of my findings and techniques in a sample project which closely follows the existing iOS  Login Screen sample application. 

This project also uses another third party API, the Otto Service Bus. The more apps I write the more I appreciate the service bus pattern. It is very common in iOS (NSNotificationCenter) and it is a nice clean way to separate the UI from the model of your project without adding much overhead. Granted there may be other faster ways of accomplishing a similar task but I am liking Otto at the moment.

Just as in the Parse iOS sample project I will attempt to make the classes as reusable as possible I fully intend this project to be the base for my future projects. Below you will find an outline of the major classes and their uses. I made a point to keep the UI as barebones as possible so that it could be modified easily to suit the needs of the implementer. The meat of the project is in the classes using the Parse API.

Source Repository : https://github.com/rdrobinson3/LoginAndSignupTutorial



**You will need to include your own Parse API key in LoginActivity to make use of the project. Check out the Quick Start Guide pages for more info.

App ID and Client ID Go Here:
    
public class LoginActivity extends BaseActivity {

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

        Parse.initialize(this, "Your App Id", "Your Client ID");
        

User Interface

A  basic login screen is fairly simple from a UI perspective. In this example our three major classes are the LoginActivity, LoginFragment, and CreateAccountFragment. 

1. LoginActivity

I started the project with the basic Android LoginActivity template. With the template you get the LoginActivity for free. For the most part I left the UI in tact. The LoginActivity in this example has four major responsibilities:
  1. Load our LoginFragment. 
  2. Handle the forgot password dialog. 
  3. Show/Hide the progress dialog.
  4. Load the new activity when sign-in is successful. 
You will notice the use of @Subscribe annotations. The designate to the Otto Service Bus that this class is interested in instances of the AuthenticateUserSuccessEvent. The name of the method does not matter for Otto as the bus looks to the class type of the subscribing method single argument. 

    @Subscribe
 public void onSignInSuccess(AuthenticateUserSuccessEvent event){
     showProgress(false, getString(R.string.login_progress_signing_in));
  Intent loginSuccess = new Intent(this, MainActivity.class);
  startActivity(loginSuccess);
  finish();
 }


2. LoginFragment

LoginFragment is pretty straight forward. The view is only 2 EditText fields (username and password) and 2 Buttons (Sign in and Create Account). Log in attempts go through some brief front end validation before being sent to our UserManager. The reuqests looks like this:


  // perform the user login attempt.
  UserManager.getInstance().authenticate(username.toLowerCase(Locale.getDefault()), password);


3. CreateAccountFragment

Like the LoginFragment, the CreateAccountFragment is fairly unremarkable. One thing to highlight is how the application is handling errors from sign in requests. Both CreateAccount and Login actions are treated as sign in requests. The reason for this is because the Parse api will return a successful authentication when an account is created. For this reason, both LoginFragment and CreateAccountFragment register for AuthenticateUserErrorEvents. 

 @Subscribe
 public void onSignInError(AuthenticateUserErrorEvent event){
  clearErrors();
  switch (event.getErrorCode()) {
   case ParseException.INVALID_EMAIL_ADDRESS:
    mEmailEditText.setError(getString(R.string.error_invalid_email));
    mEmailEditText.requestFocus();
    break;
   case ParseException.EMAIL_TAKEN:
    mEmailEditText.setError(getString(R.string.error_duplicate_email));
    mEmailEditText.requestFocus();
    break;
   case ParseException.USERNAME_TAKEN:
    mUserNameEditText.setError(getString(R.string.error_duplicate_username));
    mUserNameEditText.requestFocus();
    break;
   default:
    UnknownErrorDialogFactory.createUnknownErrorDialog(this.getActivity()).show();
    break;
  }
 }

Model

It is in the model that you really get to see the elegance of using the Parse API. In this example we only have one manager class that is responsible for interacting with our Parse instance. As your project grows so would the number of manager classes.

1. User

The User class is really just a convenience child class for the ParseUser in this instance. The Parse API users the ParseUser class (which itself is a subclass of the ParseObject) to hold the email. username, and password fields. This class becomes more useful as you need to extend the ParseUser to hold additional properties.  This class also includes a convenience constructor for creating a ParseUser instance.

2. UserManager

As you have already seen, the UI uses ths UserManager class to execute login and create account requests. The question is, how are those passed along to the cloud? Fortunately this task is very simple. The ParseUser class contains static methods for authenticate and signup. 
public void signUp(String username, String email, String password) {
  User newUser = new User(username, email, password);
  postEvent(produceUserSignInStartEvent());
  newUser.signUpInBackground(new UserSignUpCallback(newUser));
 }

One other bonus of using Parse is that it also manages the Forgotten Password scenario. In the event of a forgotten password the user enters their email and Parse will dispatch a password reset email to that account if it exists.

If a user tries to authenticate but provides incorrect credentials (or some other error occurs) then you will need to check the exception in the callback. In the example above we provide the UserSignUpCallback to the signUpInBackground function in the same way you would normally use callbacks with an AsyncTask. For this example I simply forward the error events on along the service bus so the UI can display the appropriate error message on the screen ( as seen in the CreateAccountFragment above).


 private class UserSignUpCallback extends SignUpCallback {

  User user;

  public UserSignUpCallback(User user) {
   this.user = user;
  }

  @Override
  public void done(ParseException e) {
   if (e == null) {
    postEvent(produceUserSignInSuccessEvent(user));
   } else {
    postEvent(produceUserSignInErrorEvent(e));
   }

  }
 }

Conclusion

With this example my goal was to have a simple reusable authentication and account creation screen that would be easily adaptable to any application. Creating an authentication screen is something I consider the boring busy work of the creative process. Often I found myself really excited to start on a new app idea only to find that I am writing a login screen AGAIN!

I hope that someone can find this useful. I find the service bus pattern and new platform services like Parse to really take a lot of guesswork out of the architectural process.

Source Repository : https://github.com/rdrobinson3/LoginAndSignupTutorial
Powered by Blogger.