i am current working on a client server communication in android. The tutorial that i am working on can be found on : http://www.mybringback.com/tutorial-series/12924/android-tutorial-using-remote-databases-php-and-mysql-part-1/
For convenience sake, i will only be posting main activity page (java and xml) and register page(java and xml) because the problem is the same for other class.
When i build and run the project on eclipse, pressing login OR register button in registerlayout.xml, the whole application will crash. What is causing this error? Please help!!!
Error code can be found below
MainActivity.java
package com.example.mysqltest;
import java.util.ArrayList;
import java.util.List;
import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;
import org.json.JSONException;
import org.json.JSONObject;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.os.AsyncTask;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
public class MainActivity extends Activity
implements OnClickListener{
private EditText user, pass;
private Button mSubmit, mRegister;
// Progress Dialog
private ProgressDialog pDialog;
// JSON parser class
JSONParser jsonParser = new JSONParser();
//php login script location:
//localhost :
//testing on your device
//put your local ip instead, on windows, run CMD > ipconfig
//or in mac's terminal type ifconfig and look for the ip under en0 or en1
// private static final String LOGIN_URL = "http://xxx.xxx.x.x:1234/webservice /login.php";
//testing on Emulator:
private static final String LOGIN_URL = "http://172.18.205.34/webservice/login.php";
//testing from a real server:
//private static final String LOGIN_URL = "http://www.yourdomain.com/webservice/login.php";
//JSON element ids from repsonse of php script:
private static final String TAG_SUCCESS = "success";
private static final String TAG_MESSAGE = "message";
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//setup input fields
user = (EditText)findViewById(R.id.getUsername);
pass = (EditText)findViewById(R.id.getPassword);
//setup buttons
mSubmit = (Button)findViewById(R.id.btnLogin);
mRegister = (Button)findViewById(R.id.btnRegister);
//register listeners
mSubmit.setOnClickListener(this);
mRegister.setOnClickListener(this);
}
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
switch (v.getId()) {
case R.id.btnLogin:
new AttemptLogin().execute();
break;
case R.id.btnRegister:
Intent i = new Intent(this, Register.class);
startActivity(i);
break;
default:
break;
}
}
class AttemptLogin extends AsyncTask<String, String, String> {
/**
* Before starting background thread Show Progress Dialog
* */
boolean failure = false;
@Override
protected void onPreExecute() {
super.onPreExecute();
pDialog = new ProgressDialog(MainActivity.this);
pDialog.setMessage("Attempting login...");
pDialog.setIndeterminate(false);
pDialog.setCancelable(true);
pDialog.show();
}
@Override
protected String doInBackground(String... args) {
// TODO Auto-generated method stub
// Check for success tag
int success;
String username = user.getText().toString();
String password = pass.getText().toString();
try {
// Building Parameters
List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("username", username));
params.add(new BasicNameValuePair("password", password));
Log.d("request!", "starting");
// getting product details by making HTTP request
JSONObject json = jsonParser.makeHttpRequest(
LOGIN_URL, "POST", params);
// check your log for json response
Log.d("Login attempt", json.toString());
// json success tag
success = json.getInt(TAG_SUCCESS);
if (success == 1) {
Log.d("Login Successful!", json.toString());
// save user data
SharedPreferences sp = PreferenceManager
.getDefaultSharedPreferences(MainActivity.this);
Editor edit = sp.edit();
edit.putString("username", username);
edit.commit();
Intent i = new Intent(MainActivity.this, ReadComments.class);
finish();
startActivity(i);
return json.getString(TAG_MESSAGE);
} else {
Log.d("Login Failure!", json.getString(TAG_MESSAGE));
return json.getString(TAG_MESSAGE);
}
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
/**
* After completing background task Dismiss the progress dialog
* **/
protected void onPostExecute(String file_url) {
// dismiss the dialog once product deleted
pDialog.dismiss();
if (file_url != null){
Toast.makeText(MainActivity.this, file_url, Toast.LENGTH_LONG).show();
}
}
}
}
activity_main.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:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<EditText
android:id="@+id/getPassword"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/getUsername"
android:layout_below="@+id/getUsername"
android:layout_marginTop="35dp"
android:ems="10"
android:inputType="textMultiLine" />
<Button
android:id="@+id/btnLogin"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignRight="@+id/textView1"
android:layout_centerVertical="true"
android:text="Login" />
<Button
android:id="@+id/btnRegister"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="@+id/btnLogin"
android:layout_alignBottom="@+id/btnLogin"
android:layout_centerHorizontal="true"
android:text="Register" />
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_marginTop="17dp"
android:layout_toLeftOf="@+id/btnRegister"
android:text="Username:" />
<EditText
android:id="@+id/getUsername"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/textView1"
android:layout_below="@+id/textView1"
android:ems="10"
android:inputType="textMultiLine" >
<requestFocus />
</EditText>
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/getPassword"
android:layout_below="@+id/getUsername"
android:layout_marginTop="17dp"
android:text="Password:" />
</RelativeLayout>
registerlayout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Username" />
<EditText
android:id="@+id/getUsername1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="textMultiLine" >
<requestFocus />
</EditText>
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Password" />
<EditText
android:id="@+id/getPassword1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="textMultiLine" />
<Button
android:id="@+id/btnRegister1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Register" />
</LinearLayout>
Register.java
package com.example.mysqltest;
import java.util.ArrayList;
import java.util.List;
import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;
import org.json.JSONException;
import org.json.JSONObject;
import android.app.Activity;
import android.app.ProgressDialog;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
public class Register extends Activity implements OnClickListener{
private EditText user, pass;
private Button mRegister;
// Progress Dialog
private ProgressDialog pDialog;
// JSON parser class
JSONParser jsonParser = new JSONParser();
//php login script
//localhost :
//testing on your device
//put your local ip instead, on windows, run CMD > ipconfig
//or in mac's terminal type ifconfig and look for the ip under en0 or en1
// private static final String LOGIN_URL = "http://xxx.xxx.x.x:1234/webservice /register.php";
//testing on Emulator:
private static final String LOGIN_URL = "http://192.168.1.38/webservice/register.php";
//testing from a real server:
//private static final String LOGIN_URL = "http://www.yourdomain.com/webservice/register.php";
//ids
private static final String TAG_SUCCESS = "success";
private static final String TAG_MESSAGE = "message";
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.registerlayout);
user = (EditText)findViewById(R.id.getUsername1);
pass = (EditText)findViewById(R.id.getPassword1);
mRegister = (Button)findViewById(R.id.btnRegister1);
mRegister.setOnClickListener(this);
}
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
new CreateUser().execute();
}
class CreateUser extends AsyncTask<String, String, String> {
/**
* Before starting background thread Show Progress Dialog
* */
boolean failure = false;
@Override
protected void onPreExecute() {
super.onPreExecute();
pDialog = new ProgressDialog(Register.this);
pDialog.setMessage("Creating User...");
pDialog.setIndeterminate(false);
pDialog.setCancelable(true);
pDialog.show();
}
@Override
protected String doInBackground(String... args) {
// TODO Auto-generated method stub
// Check for success tag
int success;
String username = user.getText().toString();
String password = pass.getText().toString();
try {
// Building Parameters
List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("username", username));
params.add(new BasicNameValuePair("password", password));
Log.d("request!", "starting");
//Posting user data to script
JSONObject json = jsonParser.makeHttpRequest(
LOGIN_URL, "POST", params);
// full json response
Log.d("Login attempt", json.toString());
// json success element
success = json.getInt(TAG_SUCCESS);
if (success == 1) {
Log.d("User Created!", json.toString());
finish();
return json.getString(TAG_MESSAGE);
}else{
Log.d("Login Failure!", json.getString(TAG_MESSAGE));
return json.getString(TAG_MESSAGE);
}
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
/**
* After completing background task Dismiss the progress dialog
* **/
protected void onPostExecute(String file_url) {
// dismiss the dialog once product deleted
pDialog.dismiss();
if (file_url != null){
Toast.makeText(Register.this, file_url, Toast.LENGTH_LONG).show();
}
}
}
}
config.inc.php
<?php
// These variables define the connection information for your MySQL database
$username = "emily";
$password = "testing";
$host = "localhost";
$dbname = "webservice";
$options = array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8');
try
{
$db = new PDO("mysql:host={$host};dbname={$dbname};charset=utf8", $username, $password, $options);
}
catch(PDOException $ex)
{
die("Failed to connect to the database: " . $ex->getMessage());
}
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
if(function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc())
{
function undo_magic_quotes_gpc(&$array)
{
foreach($array as &$value)
{
if(is_array($value))
{
undo_magic_quotes_gpc($value);
}
else
{
$value = stripslashes($value);
}
}
}
undo_magic_quotes_gpc($_POST);
undo_magic_quotes_gpc($_GET);
undo_magic_quotes_gpc($_COOKIE);
}
header('Content-Type: text/html; charset=utf-8');
session_start();
?>
login.php
<?php
//load and connect to MySQL database stuff
require("config.inc.php");
if (!empty($_POST)) {
//gets user's info based off of a username.
$query = "
SELECT
id,
username,
password
FROM users
WHERE
username = :username
";
$query_params = array(
':username' => $_POST['username']
);
try {
$stmt = $db->prepare($query);
$result = $stmt->execute($query_params);
}
catch (PDOException $ex) {
// For testing, you could use a die and message.
//die("Failed to run query: " . $ex->getMessage());
//or just use this use this one to product JSON data:
$response["success"] = 0;
$response["message"] = "Database Error1. Please Try Again!";
die(json_encode($response));
}
//This will be the variable to determine whether or not the user's information is correct.
//we initialize it as false.
$validated_info = false;
//fetching all the rows from the query
$row = $stmt->fetch();
if ($row) {
//if we encrypted the password, we would unencrypt it here, but in our case we just
//compare the two passwords
if ($_POST['password'] === $row['password']) {
$login_ok = true;
}
}
// If the user logged in successfully, then we send them to the private members-only page
// Otherwise, we display a login failed message and show the login form again
if ($login_ok) {
$response["success"] = 1;
$response["message"] = "Login successful!";
die(json_encode($response));
} else {
$response["success"] = 0;
$response["message"] = "Invalid Credentials!";
die(json_encode($response));
}
} else {
?>
<h1>Login</h1>
<form action="login.php" method="post">
Username:<br />
<input type="text" name="username" placeholder="username" />
<br /><br />
Password:<br />
<input type="password" name="password" placeholder="password" value="" />
<br /><br />
<input type="submit" value="Login" />
</form>
<a href="register.php">Register</a>
<?php
}
?>
register.php
<?php
require("config.inc.php");
//if posted data is not empty
if (!empty($_POST)) {
//If the username or password is empty when the user submits
//the form, the page will die.
//Using die isn't a very good practice, you may want to look into
//displaying an error message within the form instead.
//We could also do front-end form validation from within our Android App,
//but it is good to have a have the back-end code do a double check.
if (empty($_POST['username']) || empty($_POST['password'])) {
// Create some data that will be the JSON response
$response["success"] = 0;
$response["message"] = "Please Enter Both a Username and Password.";
//die will kill the page and not execute any code below, it will also
//display the parameter... in this case the JSON data our Android
//app will parse
die(json_encode($response));
}
//if the page hasn't died, we will check with our database to see if there is
//already a user with the username specificed in the form. ":user" is just
//a blank variable that we will change before we execute the query. We
//do it this way to increase security, and defend against sql injections
$query = " SELECT 1 FROM users WHERE username = :user";
//now lets update what :user should be
$query_params = array(
':user' => $_POST['username']
);
//Now let's make run the query:
try {
// These two statements run the query against your database table.
$stmt = $db->prepare($query);
$result = $stmt->execute($query_params);
}
catch (PDOException $ex) {
// For testing, you could use a die and message.
//die("Failed to run query: " . $ex->getMessage());
//or just use this use this one to product JSON data:
$response["success"] = 0;
$response["message"] = "Database Error1. Please Try Again!";
die(json_encode($response));
}
//fetch is an array of returned data. If any data is returned,
//we know that the username is already in use, so we murder our
//page
$row = $stmt->fetch();
if ($row) {
// For testing, you could use a die and message.
//die("This username is already in use");
//You could comment out the above die and use this one:
$response["success"] = 0;
$response["message"] = "I'm sorry, this username is already in use";
die(json_encode($response));
}
//If we have made it here without dying, then we are in the clear to
//create a new user. Let's setup our new query to create a user.
//Again, to protect against sql injects, user tokens such as :user and :pass
$query = "INSERT INTO users ( username, password ) VALUES ( :user, :pass ) ";
//Again, we need to update our tokens with the actual data:
$query_params = array(
':user' => $_POST['username'],
':pass' => $_POST['password']
);
//time to run our query, and create the user
try {
$stmt = $db->prepare($query);
$result = $stmt->execute($query_params);
}
catch (PDOException $ex) {
// For testing, you could use a die and message.
//die("Failed to run query: " . $ex->getMessage());
//or just use this use this one:
$response["success"] = 0;
$response["message"] = "Database Error2. Please Try Again!";
die(json_encode($response));
}
//If we have made it this far without dying, we have successfully added
//a new user to our database. We could do a few things here, such as
//redirect to the login page. Instead we are going to echo out some
//json data that will be read by the Android application, which will login
//the user (or redirect to a different activity, I'm not sure yet..)
$response["success"] = 1;
$response["message"] = "Username Successfully Added!";
echo json_encode($response);
//for a php webservice you could do a simple redirect and die.
//header("Location: login.php");
//die("Redirecting to login.php");
} else {
?>
<h1>Register</h1>
<form action="register.php" method="post">
Username:<br />
<input type="text" name="username" value="" />
<br /><br />
Password:<br />
<input type="password" name="password" value="" />
<br /><br />
<input type="submit" value="Register New User" />
</form>
<?php
}
?>
error logcat
10-28 08:52:43.894: D/dalvikvm(833): GC_FOR_ALLOC freed 71K, 8% free 2660K/2880K, paused 41ms, total 53ms
10-28 08:52:44.004: D/request!(833): starting
10-28 08:52:46.224: I/Choreographer(833): Skipped 30 frames! The application may be doing too much work on its main thread.
10-28 08:52:46.524: D/dalvikvm(833): GC_CONCURRENT freed 57K, 7% free 3009K/3212K, paused 84ms+37ms, total 297ms
10-28 08:52:47.064: E/JSON Parser(833): Error parsing data org.json.JSONException: Value <!DOCTYPE of type java.lang.String cannot be converted to JSONObject
10-28 08:52:47.064: W/dalvikvm(833): threadid=15: thread exiting with uncaught exception (group=0x40a71930)
10-28 08:52:47.144: E/AndroidRuntime(833): FATAL EXCEPTION: AsyncTask #5
10-28 08:52:47.144: E/AndroidRuntime(833): java.lang.RuntimeException: An error occured while executing doInBackground()
10-28 08:52:47.144: E/AndroidRuntime(833): at android.os.AsyncTask$3.done(AsyncTask.java:299)
10-28 08:52:47.144: E/AndroidRuntime(833): at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:352)
10-28 08:52:47.144: E/AndroidRuntime(833): at java.util.concurrent.FutureTask.setException(FutureTask.java:219)
10-28 08:52:47.144: E/AndroidRuntime(833): at java.util.concurrent.FutureTask.run(FutureTask.java:239)
10-28 08:52:47.144: E/AndroidRuntime(833): at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
10-28 08:52:47.144: E/AndroidRuntime(833): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
10-28 08:52:47.144: E/AndroidRuntime(833): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
10-28 08:52:47.144: E/AndroidRuntime(833): at java.lang.Thread.run(Thread.java:856)
10-28 08:52:47.144: E/AndroidRuntime(833): Caused by: java.lang.NullPointerException
10-28 08:52:47.144: E/AndroidRuntime(833): at com.example.mysqltest.MainActivity$AttemptLogin.doInBackground(MainActivity.java:128)
10-28 08:52:47.144: E/AndroidRuntime(833): at com.example.mysqltest.MainActivity$AttemptLogin.doInBackground(MainActivity.java:1)
10-28 08:52:47.144: E/AndroidRuntime(833): at android.os.AsyncTask$2.call(AsyncTask.java:287)
10-28 08:52:47.144: E/AndroidRuntime(833): at java.util.concurrent.FutureTask.run(FutureTask.java:234)
10-28 08:52:47.144: E/AndroidRuntime(833): ... 4 more
10-28 08:52:47.864: I/Choreographer(833): Skipped 87 frames! The application may be doing too much work on its main thread.
10-28 08:52:50.844: E/WindowManager(833): Activity com.example.mysqltest.MainActivity has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView{40d24b58 V.E..... R.....ID 0,0-563,96} that was originally added here
10-28 08:52:50.844: E/WindowManager(833): android.view.WindowLeaked: Activity com.example.mysqltest.MainActivity has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView{40d24b58 V.E..... R.....ID 0,0-563,96} that was originally added here
10-28 08:52:50.844: E/WindowManager(833): at android.view.ViewRootImpl.<init>(ViewRootImpl.java:354)
10-28 08:52:50.844: E/WindowManager(833): at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:216)
10-28 08:52:50.844: E/WindowManager(833): at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:69)
10-28 08:52:50.844: E/WindowManager(833): at android.app.Dialog.show(Dialog.java:281)
10-28 08:52:50.844: E/WindowManager(833): at com.example.mysqltest.MainActivity$AttemptLogin.onPreExecute(MainActivity.java:106)
10-28 08:52:50.844: E/WindowManager(833): at android.os.AsyncTask.executeOnExecutor(AsyncTask.java:586)
10-28 08:52:50.844: E/WindowManager(833): at android.os.AsyncTask.execute(AsyncTask.java:534)
10-28 08:52:50.844: E/WindowManager(833): at com.example.mysqltest.MainActivity.onClick(MainActivity.java:80)
10-28 08:52:50.844: E/WindowManager(833): at android.view.View.performClick(View.java:4204)
10-28 08:52:50.844: E/WindowManager(833): at android.view.View$PerformClick.run(View.java:17355)
10-28 08:52:50.844: E/WindowManager(833): at android.os.Handler.handleCallback(Handler.java:725)
10-28 08:52:50.844: E/WindowManager(833): at android.os.Handler.dispatchMessage(Handler.java:92)
10-28 08:52:50.844: E/WindowManager(833): at android.os.Looper.loop(Looper.java:137)
10-28 08:52:50.844: E/WindowManager(833): at android.app.ActivityThread.main(ActivityThread.java:5041)
10-28 08:52:50.844: E/WindowManager(833): at java.lang.reflect.Method.invokeNative(Native Method)
10-28 08:52:50.844: E/WindowManager(833): at java.lang.reflect.Method.invoke(Method.java:511)
10-28 08:52:50.844: E/WindowManager(833): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
10-28 08:52:50.844: E/WindowManager(833): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
10-28 08:52:50.844: E/WindowManager(833): at dalvik.system.NativeStart.main(Native Method)
10-28 08:52:50.844: I/Choreographer(833): Skipped 73 frames! The application may be doing too much work on its main thread.