

Developing Android Application for Client side
This is the continuation of Android Login Registration System with Node.js and MongoDB. In our previous tutorials we have used Eclipse IDE for client side programming with JAVA and XML. Now we switch over to Android Studio IDE which is more interactive and faster IDE.
Prerequisites
-> Turn On Offline mode in Android Studio for Gradle build. So that you can work offline. Do this by File ->Settings ->Compiler-> Gradle then check the box Offline mode.
-> Setup Android Virtual Device for testing our application.
Download Complete Project
Creating Project
Create an New project in Android Studio by File->New Project. In the following Dialog box enter the Application name followed by package name as com.amal.nodeandroid. Change the names according to your needs. In the proceeding dialog box enter the Main Activity name as LoginActivity and layout as activity_login.
Creating Layouts
Our main layout activity_login consists of two EditText widgets to get email and password as input. It consists of three buttons for Login, to open the Registration screen and to open the forgot password dialog.
activity_login.xml
<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:orientation="vertical" android:background="#e9e8dd" tools:context=".LoginActivity" > <ImageView android:id="@+id/imageView1" android:layout_width="fill_parent" android:layout_height="100px" android:background="#5ba4e5" android:layout_gravity="center" android:src="@drawable/logo" /> <EditText android:layout_width="440px" android:layout_height="80px" android:layout_gravity="center" android:layout_marginTop="30px" android:id="@+id/email" android:hint="example@mail.com"/> <EditText android:id="@+id/password" android:layout_width="440px" android:layout_gravity="center" android:layout_height="80px" android:inputType="textPassword" android:hint="******"/> <Button android:layout_width="440px" android:layout_height="80px" android:layout_gravity="center" android:id="@+id/loginbtn" android:background="@drawable/btn_back" android:textColor="#ffffff" android:textAlignment="center" android:text="Login"/> <LinearLayout android:layout_width="440px" android:layout_height="wrap_content" android:layout_marginTop="10px" android:layout_gravity="center" android:orientation="horizontal" > <Button android:layout_width="215px" android:layout_height="80px" android:layout_gravity="center" android:id="@+id/register" android:background="@drawable/btn_blue_back" android:textColor="#ffffff" android:textAlignment="center" android:text="Register"/> <Button android:layout_width="215px" android:layout_height="80px" android:id="@+id/forgotpass" android:layout_marginLeft="10px" android:background="@drawable/btn_red_back" android:textColor="#ffffff" android:textAlignment="center" android:text="Forgot Password"/> </LinearLayout> </LinearLayout>
Our Next layout is for registration screen which has two EditText to get email and password as input. It also has buttons to switch back to Login Screen.
activity_register.xml
<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:orientation="vertical" tools:context=".LoginActivity" > <ImageView android:id="@+id/imageView1" android:layout_width="fill_parent" android:layout_height="100px" android:layout_gravity="center" android:background="#5ba4e5" android:src="@drawable/logo" /> <EditText android:layout_width="440px" android:layout_height="80px" android:layout_gravity="center" android:id="@+id/email" android:layout_marginTop="30px" android:hint="example@mail.com"/> <EditText android:id="@+id/password" android:layout_gravity="center" android:layout_width="440px" android:layout_height="80px" android:inputType="textPassword" android:hint="******"/> <Button android:layout_width="440px" android:layout_height="80px" android:id="@+id/registerbtn" android:layout_gravity="center" android:background="@drawable/btn_back" android:textColor="#ffffff" android:textAlignment="center" android:text="Register"/> <Button android:layout_width="440px" android:layout_height="80px" android:layout_marginTop="10px" android:id="@+id/login" android:layout_gravity="center" android:background="@drawable/btn_blue_back" android:textColor="#ffffff" android:textAlignment="center" android:text="Login Now"/> </LinearLayout>
The dialog for Profile is the activity_profile which has a webview to display image from gravatar. It has two buutons one to trigger change password dialog and logout.
activity_profile.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <WebView android:layout_width="200px" android:layout_marginTop="30px" android:layout_height="200px" android:layout_gravity="center" android:id="@+id/webView" /> <Button android:layout_width="440px" android:layout_gravity="center" android:layout_marginTop="30px" android:layout_height="80px" android:id="@+id/chgbtn" android:background="@drawable/btn_back" android:textColor="#ffffff" android:textAlignment="center" android:text="Change Password"/> <Button android:layout_width="440px" android:layout_gravity="center" android:layout_marginTop="10px" android:layout_height="80px" android:id="@+id/logout" android:background="@drawable/btn_blue_back" android:textColor="#ffffff" android:textAlignment="center" android:text="Logout"/> </LinearLayout>
Change password dialog is defined as chgpassword_frag. It has two EditText for Old Password and new Password and buttons to change password and to cancel the dialog.
chgpassword_frag.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="400px" android:layout_gravity="center" android:layout_height="match_parent"> <EditText android:layout_width="match_parent" android:layout_height="80px" android:inputType="textPassword" android:textAlignment="center" android:hint="Old Password" android:id="@+id/oldpass" android:layout_gravity="center" /> <EditText android:layout_width="match_parent" android:layout_height="80px" android:inputType="textPassword" android:hint="New Password" android:textAlignment="center" android:id="@+id/newpass" android:layout_gravity="center" /> <Button android:layout_width="fill_parent" android:layout_height="80px" android:id="@+id/chgbtn" android:background="@drawable/btn_back" android:textColor="#ffffff" android:textAlignment="center" android:text="Change Password"/> <Button android:layout_width="fill_parent" android:layout_height="80px" android:layout_marginTop="10px" android:layout_marginBottom="40px" android:id="@+id/cancelbtn" android:background="@drawable/btn_blue_back" android:textColor="#ffffff" android:textAlignment="center" android:text="Cancel"/> </LinearLayout>
Next layout is for Reset password which is reset_pass_init which has one input text field. If email is sent successfully the layout is changed to reset_pass_code. The reset_pass_code has input text field for code and new password.
![]() | ![]() |
reset_pass_init.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="400px" android:layout_gravity="center" android:layout_height="match_parent"> <EditText android:layout_width="match_parent" android:layout_height="80px" android:textAlignment="center" android:hint="Email" android:id="@+id/email" android:layout_gravity="center" /> <Button android:layout_width="fill_parent" android:layout_height="80px" android:id="@+id/resbtn" android:background="@drawable/btn_back" android:textColor="#ffffff" android:textAlignment="center" android:text="Continue"/> <Button android:layout_width="fill_parent" android:layout_height="80px" android:layout_marginTop="10px" android:layout_marginBottom="40px" android:id="@+id/cancelbtn" android:background="@drawable/btn_blue_back" android:textColor="#ffffff" android:textAlignment="center" android:text="Cancel"/> </LinearLayout>
reset_pass_code.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="400px" android:layout_gravity="center" android:layout_height="match_parent"> <EditText android:layout_width="match_parent" android:layout_height="80px" android:inputType="textPassword" android:textAlignment="center" android:hint="Code" android:id="@+id/code" android:layout_gravity="center" /> <EditText android:layout_width="match_parent" android:layout_height="80px" android:inputType="textPassword" android:textAlignment="center" android:hint="New password" android:id="@+id/npass" android:layout_gravity="center" /> <Button android:layout_width="fill_parent" android:layout_height="80px" android:id="@+id/conbtn" android:background="@drawable/btn_back" android:textColor="#ffffff" android:textAlignment="center" android:text="Continue"/> <Button android:layout_width="fill_parent" android:layout_height="80px" android:layout_marginTop="10px" android:layout_marginBottom="40px" android:id="@+id/cancel" android:background="@drawable/btn_blue_back" android:textColor="#ffffff" android:textAlignment="center" android:text="Cancel"/> </LinearLayout>
Creating Styles
Here I have used custom button backgrounds with rounded corners. The styles for green, blue and red are defined as btn_back, btn_blue_back, btn_red_back. These styles should be placed in drawable directory.
btn_back.xml
<?xml version="1.0" encoding="UTF-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android"> <solid android:color="#9fbb58"/> <stroke android:width="3dip" android:color="#9fbb58" /> <corners android:radius="15dip"/> <padding android:left="0dip" android:top="0dip" android:right="0dip" android:bottom="0dip" /> </shape>
btn_back_blue.xml
<?xml version="1.0" encoding="UTF-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android"> <solid android:color="#5ba4e5"/> <stroke android:width="3dip" android:color="#5ba4e5" /> <corners android:radius="15dip"/> <padding android:left="0dip" android:top="0dip" android:right="0dip" android:bottom="0dip" /> </shape>
btn_back_red.xml
<?xml version="1.0" encoding="UTF-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android"> <solid android:color="#E84C3D"/> <stroke android:width="3dip" android:color="#E84C3D" /> <corners android:radius="15dip"/> <padding android:left="0dip" android:top="0dip" android:right="0dip" android:bottom="0dip" /> </shape>
Creating Java Classes
Initially we need to create ServerRequest class which has function getJSONFromUrl to get JSON from by HTTP POST method. It also has a Request class which extends to AsyncTask. The Request class performs the background Operations. The function getJSON process and get data using the AsyncTask class and returns as JSONObject.
ServerRequest.java
package com.amal.nodelogin; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; import java.util.List; import java.util.concurrent.ExecutionException; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.NameValuePair; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpPost; import org.apache.http.impl.client.DefaultHttpClient; import org.json.JSONException; import org.json.JSONObject; import android.os.AsyncTask; import android.util.Log; public class ServerRequest { static InputStream is = null; static JSONObject jObj = null; static String json = ""; public ServerRequest() { } public JSONObject getJSONFromUrl(Stringurl,List<NameValuePair>params) { try { DefaultHttpClient httpClient = new DefaultHttpClient(); HttpPost httpPost = new HttpPost(url); httpPost.setEntity(new UrlEncodedFormEntity(params)); HttpResponse httpResponse = httpClient.execute(httpPost); HttpEntity httpEntity = httpResponse.getEntity(); is = httpEntity.getContent(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } catch (ClientProtocolException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } try { BufferedReader reader = new BufferedReader(new InputStreamReader( is, "iso-8859-1"), 8); StringBuilder sb = new StringBuilder(); String line = null; while ((line = reader.readLine()) != null) { sb.append(line + "n"); } is.close(); json = sb.toString(); Log.e("JSON", json); } catch (Exception e) { Log.e("Buffer Error", "Error converting result " + e.toString()); } try { jObj = new JSONObject(json); } catch (JSONException e) { Log.e("JSON Parser", "Error parsing data " + e.toString()); } return jObj; } JSONObject jobj; public JSONObject getJSON(String url, List<NameValuePair> params) { Params param = new Params(url,params); Request myTask = new Request(); try{ jobj= myTask.execute(param).get(); }catch (InterruptedException e) { e.printStackTrace(); }catch (ExecutionException e){ e.printStackTrace(); } return jobj; } private static class Params { String url; List<NameValuePair> params; Params(String url, List<NameValuePair> params) { this.url = url; this.params = params; } } private class Request extends AsyncTask<Params, String, JSONObject> { @Override protected JSONObject doInBackground(Params... args) { ServerRequest request = new ServerRequest(); JSONObject json = request.getJSONFromUrl(args[0].url,args[0].params); return json; } @Override protected void onPostExecute(JSONObject json) { super.onPostExecute(json); } } }
The main Activity of our project is LoginActivity which performs login operation. It performs POST operation using ServerRequest class and gets json response from the server. Login has two parameters email and password. The response is displayed in a Toast. On sucessful login a access token and gravatar url is recieved which is stored in SharedPreferences and user is redirected to Profile Activity.
It too performs forgot password Operation. Reset Password is performed in Dialog instead of new Activity. When email is entered POST is performed with parameter email. If email is valid user is redirected to next layout where he/she must enter code and new password. It has parameters code, new password, email and it is sent to Server using POST by ServerRequest class. All server JSON responses are displayed in Toast.
LoginActivity.java
package com.amal.nodelogin; import android.app.Activity; import android.app.Dialog; import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.Toast; import org.apache.http.NameValuePair; import org.apache.http.message.BasicNameValuePair; import org.json.JSONException; import org.json.JSONObject; import java.util.ArrayList; import java.util.List; public class LoginActivity extends Activity { EditText email,password,res_email,code,newpass; Button login,cont,cont_code,cancel,cancel1,register,forpass; String emailtxt,passwordtxt,email_res_txt,code_txt,npass_txt; List<NameValuePair> params; SharedPreferences pref; Dialog reset; ServerRequest sr; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); sr = new ServerRequest(); email = (EditText)findViewById(R.id.email); password = (EditText)findViewById(R.id.password); login = (Button)findViewById(R.id.loginbtn); register = (Button)findViewById(R.id.register); forpass = (Button)findViewById(R.id.forgotpass); pref = getSharedPreferences("AppPref", MODE_PRIVATE); register.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Intent regactivity = new Intent(LoginActivity.this,RegisterActivity.class); startActivity(regactivity); finish(); } }); login.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { emailtxt = email.getText().toString(); passwordtxt = password.getText().toString(); params = new ArrayList<NameValuePair>(); params.add(new BasicNameValuePair("email", emailtxt)); params.add(new BasicNameValuePair("password", passwordtxt)); ServerRequest sr = new ServerRequest(); JSONObject json = sr.getJSON("http://10.0.2.2:8080/login",params); if(json != null){ try{ String jsonstr = json.getString("response"); if(json.getBoolean("res")){ String token = json.getString("token"); String grav = json.getString("grav"); SharedPreferences.Editor edit = pref.edit(); //Storing Data using SharedPreferences edit.putString("token", token); edit.putString("grav", grav); edit.commit(); Intent profactivity = new Intent(LoginActivity.this,ProfileActivity.class); startActivity(profactivity); finish(); } Toast.makeText(getApplication(),jsonstr,Toast.LENGTH_LONG).show(); }catch (JSONException e) { e.printStackTrace(); } } } }); forpass.setOnClickListener(new View.OnClickListener(){ @Override public void onClick(View view) { reset = new Dialog(LoginActivity.this); reset.setTitle("Reset Password"); reset.setContentView(R.layout.reset_pass_init); cont = (Button)reset.findViewById(R.id.resbtn); cancel = (Button)reset.findViewById(R.id.cancelbtn); cancel.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { reset.dismiss(); } }); res_email = (EditText)reset.findViewById(R.id.email); cont.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { email_res_txt = res_email.getText().toString(); params = new ArrayList<NameValuePair>(); params.add(new BasicNameValuePair("email", email_res_txt)); // JSONObject json = sr.getJSON("http://192.168.56.1:8080/api/resetpass", params); JSONObject json = sr.getJSON("http://10.0.2.2:8080/api/resetpass", params); if (json != null) { try { String jsonstr = json.getString("response"); if(json.getBoolean("res")){ Log.e("JSON", jsonstr); Toast.makeText(getApplication(), jsonstr, Toast.LENGTH_LONG).show(); reset.setContentView(R.layout.reset_pass_code); cont_code = (Button)reset.findViewById(R.id.conbtn); code = (EditText)reset.findViewById(R.id.code); newpass = (EditText)reset.findViewById(R.id.npass); cancel1 = (Button)reset.findViewById(R.id.cancel); cancel1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { reset.dismiss(); } }); cont_code.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { code_txt = code.getText().toString(); npass_txt = newpass.getText().toString(); Log.e("Code",code_txt); Log.e("New pass",npass_txt); params = new ArrayList<NameValuePair>(); params.add(new BasicNameValuePair("email", email_res_txt)); params.add(new BasicNameValuePair("code", code_txt)); params.add(new BasicNameValuePair("newpass", npass_txt)); JSONObject json = sr.getJSON("http://10.0.2.2:8080/api/resetpass/chg", params); // JSONObject json = sr.getJSON("http://192.168.56.1:8080/api/resetpass/chg", params); if (json != null) { try { String jsonstr = json.getString("response"); if(json.getBoolean("res")){ reset.dismiss(); Toast.makeText(getApplication(),jsonstr,Toast.LENGTH_LONG).show(); }else{ Toast.makeText(getApplication(),jsonstr,Toast.LENGTH_LONG).show(); } } catch (JSONException e) { e.printStackTrace(); } } } }); }else{ Toast.makeText(getApplication(),jsonstr,Toast.LENGTH_LONG).show(); } } catch (JSONException e) { e.printStackTrace(); } } } }); reset.show(); } }); } }
Next is the RegisterActivity. It is similar to LoginAcivity. It takes two parameters email and password and it is sent using POST through ServerRequest class. All the server JSON responses are displayed in Toast as alert.
RegisterActivity.java
package com.amal.nodelogin; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.Toast; import org.apache.http.NameValuePair; import org.apache.http.message.BasicNameValuePair; import org.json.JSONException; import org.json.JSONObject; import java.util.ArrayList; import java.util.List; public class RegisterActivity extends Activity { EditText email,password; Button login,register; String emailtxt,passwordtxt; List<NameValuePair> params; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_register); email = (EditText)findViewById(R.id.email); password = (EditText)findViewById(R.id.password); register = (Button)findViewById(R.id.registerbtn); login = (Button)findViewById(R.id.login); login.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Intent regactivity = new Intent(RegisterActivity.this,LoginActivity.class); startActivity(regactivity); finish(); } }); register.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { emailtxt = email.getText().toString(); passwordtxt = password.getText().toString(); params = new ArrayList<NameValuePair>(); params.add(new BasicNameValuePair("email", emailtxt)); params.add(new BasicNameValuePair("password", passwordtxt)); ServerRequest sr = new ServerRequest(); JSONObject json = sr.getJSON("http://10.0.2.2:8080/register",params); //JSONObject json = sr.getJSON("http://192.168.56.1:8080/register",params); if(json != null){ try{ String jsonstr = json.getString("response"); Toast.makeText(getApplication(),jsonstr,Toast.LENGTH_LONG).show(); Log.d("Hello", jsonstr); }catch (JSONException e) { e.printStackTrace(); } } } }); } }
ProfileActivity is the last activity. On successful login user is redirected to Profile page. The gravatar url and access token are fetched from SharedPreferences. The profile gravatar image is displayed in WebView.
It also has change password feature where the user need to enter the old password and new password. While changing password the old password, new password and token are sent as parameters to the Server through ServerRequest class. The change password operation is performed in a dialog.
ProfileActivity.java
package com.amal.nodelogin; import android.app.Activity; import android.app.Dialog; import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; import android.view.View; import android.webkit.WebView; import android.widget.Button; import android.widget.EditText; import android.widget.Toast; import org.apache.http.NameValuePair; import org.apache.http.message.BasicNameValuePair; import org.json.JSONException; import org.json.JSONObject; import java.util.ArrayList; import java.util.List; public class ProfileActivity extends Activity { SharedPreferences pref; String token,grav,oldpasstxt,newpasstxt; WebView web; Button chgpass,chgpassfr,cancel,logout; Dialog dlg; EditText oldpass,newpass; List<NameValuePair> params; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_profile); web = (WebView)findViewById(R.id.webView); chgpass = (Button)findViewById(R.id.chgbtn); logout = (Button)findViewById(R.id.logout); logout.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { SharedPreferences.Editor edit = pref.edit(); //Storing Data using SharedPreferences edit.putString("token", ""); edit.commit(); Intent loginactivity = new Intent(ProfileActivity.this,LoginActivity.class); startActivity(loginactivity); finish(); } }); pref = getSharedPreferences("AppPref", MODE_PRIVATE); token = pref.getString("token", ""); grav = pref.getString("grav", ""); web.getSettings().setUseWideViewPort(true); web.getSettings().setLoadWithOverviewMode(true); web.loadUrl(grav); chgpass.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { dlg = new Dialog(ProfileActivity.this); dlg.setContentView(R.layout.chgpassword_frag); dlg.setTitle("Change Password"); chgpassfr = (Button)dlg.findViewById(R.id.chgbtn); chgpassfr.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { oldpass = (EditText)dlg.findViewById(R.id.oldpass); newpass = (EditText)dlg.findViewById(R.id.newpass); oldpasstxt = oldpass.getText().toString(); newpasstxt = newpass.getText().toString(); params = new ArrayList<NameValuePair>(); params.add(new BasicNameValuePair("oldpass", oldpasstxt)); params.add(new BasicNameValuePair("newpass", newpasstxt)); params.add(new BasicNameValuePair("id", token)); ServerRequest sr = new ServerRequest(); // JSONObject json = sr.getJSON("http://192.168.56.1:8080/api/chgpass",params); JSONObject json = sr.getJSON("http://10.0.2.2:8080/api/chgpass",params); if(json != null){ try{ String jsonstr = json.getString("response"); if(json.getBoolean("res")){ dlg.dismiss(); Toast.makeText(getApplication(),jsonstr,Toast.LENGTH_SHORT).show(); }else { Toast.makeText(getApplication(),jsonstr,Toast.LENGTH_SHORT).show(); } }catch (JSONException e) { e.printStackTrace(); } } } }); cancel = (Button)dlg.findViewById(R.id.cancelbtn); cancel.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { dlg.dismiss(); } }); dlg.show(); } }); } }
Creating Manifest
We need the following permission for our Application.
android.permission.INTERNET
Screenshots
![]() | ![]() |
![]() | ![]() |
Any questions comment here 🙂