Translate

Saturday, May 18, 2013

Android App Development 201 2nd tutorial; JSON parsing from a url and populating ListView in Android

In this tutorial, we will look at parsing JSON from a url. We will take a Flickr jsonfeed for this project. This feed can be located here. This JSON feed contains a JSON array called "items". Remember JSON array always starts with [ bracket. and the objects are enclosed in { bracket. Each object can have various name value pair. For this example we will be looking at the 'title' and 'link' names and get their values in an ArrayList. We will then populate our listview with the titles. When we click at the titles, a web view will be shown with the url corresponding to that title.
Lets start with the layouts. We need two of them here one for the main activity where the listview is populated and another for the web view activity where the page corresponding to the title will be displayed.

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"
    tools:context=".MainActivity" >

    <ListView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/listView"/>

</RelativeLayout>


web_view.xml


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
 android:orientation="vertical"
 >

    <WebView
        android:id="@+id/webview"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
      />

</LinearLayout>

We will have two activities corresponding these two layouts and a jsonparser class.

MainActivity.java


package com.peshal.jsonfeedtest;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.http.client.ClientProtocolException;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.app.Activity;
import android.content.Intent;

public class MainActivity extends Activity {
ListView lv;
JSONArray items;
JSONObject jsonObject;
List<String> titleCollection = new ArrayList<String>();
List<String> urlCollection = new ArrayList<String>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
lv = (ListView) findViewById(R.id.listView);
new NetworkOperation().execute();
lv.setOnItemClickListener(new OnItemClickListener(){

@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
long arg3) {
String photoUrl = urlCollection.get(arg2);
Intent webViewIntent = new Intent(MainActivity.this, WebViewActivity.class);
webViewIntent.putExtra("url", photoUrl);
startActivity(webViewIntent);
}

});
}

public void loadContents() {
ArrayAdapter<String> adapter =new ArrayAdapter<String>(getBaseContext(), android.R.layout.simple_list_item_1,titleCollection);
lv.setAdapter(adapter);
}

public class NetworkOperation extends AsyncTask<Void, Void, Void> {

@Override
protected Void doInBackground(Void... arg0) {
JsonParser parser = new JsonParser();

try {
String result = parser.getHttpConnection();
String removedString = result.trim().substring(15, result.trim().length()-1);
JSONObject jsonObject = new JSONObject(removedString);
items = jsonObject.getJSONArray("items");
for (int i = 0; i<items.length(); i++) {
jsonObject = items.getJSONObject(i);
titleCollection.add(jsonObject.getString("title"));
urlCollection.add(jsonObject.getString("link"));
}


} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}


@Override
protected void onPostExecute(Void result) {
loadContents();

super.onPostExecute(result);
}

}

}

NetworkOperation class is used for Asynchronous data loading as android doesnot allow network operations in main thread starting android 2.3 gingerbread. AsyncTask invokes the onPostExecute() method

 when the background task is complete. This is when we will populateour listviews. As you can see in this method we redirect to loadContents() method where we populate our listview.

JsonParser.java

package com.peshal.jsonfeedtest;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONObject;


public class JsonParser {
BufferedReader in = null;
JSONObject jsonObject=null;
String result="";



public String getHttpConnection() throws ClientProtocolException, IOException {
HttpClient httpClient = new DefaultHttpClient();
HttpGet request = new HttpGet("http://www.flickr.com/services/feeds/photos_public.gne?tags=punctuation,atsign&format=json");
HttpResponse response = httpClient.execute(request);
in = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));

StringBuffer sb = new StringBuffer("");
String line="";
String lineSeparator=System.getProperty("line.separator");
while ((line=in.readLine())!=null) {
sb.append(line + lineSeparator);
}
in.close();
result = sb.toString();
try{
jsonObject = new JSONObject(result);
}
catch(Exception e) {
}
return result;

}



}

This class is mainly responsible for making a HTTP GET request to the url where the json feed is located and loading the contents from the page to a string buffer and returns the string. This string is parsed to ArrayList in the doInBackground method of AsyncTask from the MainActivity class. One more note here, the json feed contains some unwanted information which are removed using the substring method.

WebViewActivity

package com.peshal.jsonfeedtest;


import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnKeyListener;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.app.Activity;

public class WebViewActivity extends Activity {
WebView webView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.web_view);
    webView = (WebView)findViewById(R.id.webview);
webView.setWebViewClient(new WebViewClient());
String url=getIntent().getExtras().getString("url");
webView.canGoBack();
webView.loadUrl(url);
webView.setOnKeyListener(new OnKeyListener() {

@Override
public boolean onKey(View arg0, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && webView.canGoBack()) {    
webView.goBack();
return true;
}
else {
return false;
}
}
});
}
}

This activity is responsible to load the url corresponding to the title into the web view. The url is passed from MainActivity using Intent.putExtra method. The parameters passed is retrieved in this activity using getIntent().getExtras().getString() method.

Dont forget to add Internet permission in the manifest since we are using the HTTP request as well as webview.

 <uses-permission android:name="android.permission.INTERNET" />




Saturday, March 2, 2013

Android App Development 201 1st tutorial; Android and Web Service, Multi Threading using AsyncTask and More

In this tutorial, we will look at multi threading in android using Async Task as well as how to integrate web service with your android application. We will look at new API's such as location manager to get the location information using the GPS sensor. We will then convert the location information to a Json Object and pass that object to a url using Http POST request. Here is the code:


package com.example.locationtest;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Timer;
import java.util.TimerTask;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONException;
import org.json.JSONObject;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;


public class MainActivity extends Activity implements LocationListener{
private TextView textView =null;
LocationManager locationManager=null;
Location location=null;
protected String url;
protected JSONObject jsonData=null;
private EditText urlText=null;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
locationManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
final boolean gpsEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
if(gpsEnabled!=true) {
Toast.makeText(getApplicationContext(), "GPS Disbled! Please Enable to Proceed!", Toast.LENGTH_SHORT).show();
        startActivity(new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS));
}

textView = (TextView)findViewById(R.id.textView);
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 1, this);
urlText = (EditText)findViewById(R.id.urlTextbox);
Button submitButton = (Button)findViewById(R.id.submitUrl);

submitButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
if (urlText.getText()!=null) {
url=urlText.getText().toString();
System.out.println(url);//for testing only, not required
Toast.makeText(getApplicationContext(), "Url Submitted, Sending data to Web Service at url: " + url, Toast.LENGTH_SHORT).show();
}
}
});




}

@Override
public void onLocationChanged(final Location location) {
this.location=location;
final Handler handler = new Handler();
 Timer ourtimer = new Timer();
 TimerTask timerTask = new TimerTask() {
 int cnt=1;  
 public void run() {
                 handler.post(new Runnable() {
                         public void run() {
                       
                        Double latitude = location.getLatitude();
                      Double longitude = location.getLongitude();
                      Double altitude = location.getAltitude();
                      Float accuracy = location.getAccuracy();
                      textView.setText("Latitude: " + latitude + "\n" + "Longitude: " + longitude+ "\n" + "Altitude: " + altitude + "\n" + "Accuracy: " + accuracy + "meters"+"\n" + "Location Counter: " + cnt);
                      try {
                      jsonData = new JSONObject();
jsonData.put("Latitude", latitude);
jsonData.put("Longitude", longitude);
jsonData.put("Altitude", altitude);
jsonData.put("Accuracy", accuracy);

System.out.println(jsonData.toString());//not required, for testing only
if(url!=null) {
new HttpPostHandler().execute();
}
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
                     
                      cnt++;
                         }
               
                });
         }};
     ourtimer.schedule(timerTask, 0, 120000);

}

@Override
public void onProviderDisabled(String provider) {


}

@Override
public void onProviderEnabled(String provider) {


}

@Override
public void onStatusChanged(String provider, int status, Bundle extras) {


}





public class HttpPostHandler extends AsyncTask<Void,Void,Void> {

@Override
protected Void doInBackground(Void... arg0) {

HttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(url);
StringEntity dataEntity = null;
try {
dataEntity = new StringEntity(jsonData.toString());
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
httpPost.setEntity(dataEntity);
httpPost.setHeader("Content-Type", "application/json");
try {
httpClient.execute(httpPost);
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();

}
return null;


}

@Override
protected void onPostExecute(Void result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
try {
this.finalize();
} catch (Throwable e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

}

}

Here is the layout code:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
 
    <EditText
        android:id="@+id/urlTextbox"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Web Service Url"
    android:layout_gravity="top"
        />
    <Button android:id="@+id/submitUrl"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Submit"
        android:layout_gravity="right"
/>
 
    <TextView
        android:id="@+id/textView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text=""
        android:layout_gravity="center"/>
 
</LinearLayout>



As you can see in the code, at first it makes sure the GPS is turned or it will launch the activity to the location settings menu. Once it makes sure the GPS is enabled, it starts getting location and displaying them in the textview. Once we enter the url to send the post information in the edit text, it starts sending location information to the url using Http POST. Remember to add following permissions to your android manifest file.

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />

Complete source code is available here


Wednesday, January 9, 2013

Android App Development 101 5th tutorial; Android and Web, Turn your Web Site into an Android App!

In this tutorial, I will be using Android WebView to display my blog in our android app. Web View is very straight forward and offer several features. We will be looking at few of them. At first we need to make a layout in xml with our WebView object, then we will load our url into the layout.

activity_main.xml


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:layout_width="match_parent"
    android:layout_height="match_parent"
 android:orientation="vertical"
 >

    <WebView
        android:id="@+id/webview"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
      />

</LinearLayout>


MainActivity.java


package com.example.webview;

import android.os.Bundle;
import android.app.Activity;
import android.view.KeyEvent;
import android.webkit.WebView;
import android.webkit.WebViewClient;

public class MainActivity extends Activity {
WebView ourwebView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
loadWeb();
}

public void loadWeb() {
WebView webView = (WebView)findViewById(R.id.webview);
ourwebView=webView;
this.setTitle("Android Happenings");
ourwebView.setWebViewClient(new WebViewClient());
String url="http://androidhappenings.blogspot.com/";
ourwebView.canGoBack();
ourwebView.loadUrl(url);

}


public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode==KeyEvent.KEYCODE_BACK && ourwebView.canGoBack()) {
ourwebView.goBack();
return true;

}
return super.onKeyDown(keyCode, event);
}


}

As we can see in the above java code, the onKeyDown method checks for back presses and move our web view one page back in each back press whenever possible. Also make sure that you add internet permission in your manifest or it will display web page not found error.
<uses-permission android:name="android.permission.INTERNET" />