Android: Complete JSON to ListView Tutorial

In this tutorial we will create a simple Android app that applies the following techniques:

  1. Create JSON objects and arrays
  2. Store a “local” file for the app
  3. Read and write to the local file
  4. Define a custom ListView
  5. Convert JSON objects into a ListView

Download the source code for this project here.

Application Overview

Here is a basic overview of this app:

  • Home screen has two buttons, called “Create Entry” and “View Log”.
  • When “Create Entry” is clicked a JSON object containing the current date, time, and description is created and stored in a JSON file which is stored locally on the device.
  • When “View Log” is clicked a new activity starts that shows a custom ListView that has a row for each entry in the JSON file.
  • As a bonus – a menu option will be created to clear all entries in the log file.

As you can see we’ve got a lot to do so let’s get started.

Layouts

The Home Screen Layout – activity_main.xml

android_json_listview_activity_main

<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" >

    <Button
        android:id="@+id/button_log"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_marginTop="20dp"
        android:padding="20dp"
        android:onClick="clickListener"
        android:text="@string/log_button" />

    <Button
        android:id="@+id/button_view_log"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/button_log"
        android:layout_below="@+id/button_log"
        android:layout_marginTop="30dp"
        android:padding="20dp"
        android:onClick="clickListener"
        android:text="@string/view_log" />

</RelativeLayout>

Note the onClick function called “clickListener”. I prefer to use the technique for handling button clicks. I’ll show the “clickListener” function in MainActivity.java

Next we’ll need an activity to view the JSON log as a listview. Create a new Android Activity for the log viewer. I called mine “activity_log.xml” It only needs an empty ListView.

The Layout for the ListView – activity_log.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/LinearLayout1"
    android:layout_width="fill_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".LogActivity" >

    <ListView
        android:id="@+id/logListView"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" >

    </ListView>

</LinearLayout>

Lastly we need to design and create the custom ListView template we want to use. The technique for creating a custom ListView is fairly simple but can be intimidating. The process is:

  1. Design a single row item with an layout XML file
  2. Create an “adapter” that defines how incoming data maps to your design from step 1
  3. Feed data into the adapter

Create a new xml file. I called mine adapter_log.xml since its an adapter and its for the log file. Here’s the design I chose:
listview_adapter

Custom ListView Adapter Layout – adapter_log.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="#E2E2E2"
    android:paddingLeft="10dp"
    android:paddingRight="2dp" >

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#FFFFFF"
        android:padding="7dp" >

        <ImageView
            android:id="@+id/imageView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:layout_alignParentTop="true"
            android:layout_marginRight="25dp"
            android:src="@drawable/ic_launcher" />

        <TextView
            android:id="@+id/titleTextView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignTop="@+id/imageView"
            android:layout_toRightOf="@+id/imageView"
            android:text="Medium Text"
            android:textAppearance="?android:attr/textAppearanceMedium" />

        <TextView
            android:id="@+id/descriptionTextView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignBottom="@+id/imageView"
            android:layout_alignLeft="@+id/titleTextView"
            android:text="Small Text"
            android:textAppearance="?android:attr/textAppearanceSmall" />
    </RelativeLayout>

</RelativeLayout>

Note that in order to create the appearance of a thick right border I created a Relative layout with a grey background, then created a new Relative layout inside with a white background and gave the grey layout padding. Another important part is that the highest parent height is set to “wrap_content” that way it’s only as tall as the stuff inside it.

All done with layouts. Time to do some code.

Code

The Home Screen – MainActivity.java

package com.kanzelmeyer.json;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.text.DateFormat;
import java.util.Date;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.os.Bundle;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.view.Menu;
import android.view.View;
import android.widget.Toast;

public class MainActivity extends Activity {

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

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

	// Click Listener for the buttons on the main screen

	public void clickListener(View v) {

		switch (v.getId()) {

		case R.id.button_log:
			logDateTime();
			break;

		case R.id.button_view_log:
			Intent viewLog = new Intent(this, LogActivity.class);
			startActivity(viewLog);
			break;

		default:
			break;
		}
	}


	private void logDateTime() {

		// Variables
                String FILENAME = "log.json";
		String date = DateFormat.getDateInstance().format(new Date());
		String time = DateFormat.getTimeInstance().format(new Date());
		String desc = "Entry Created";
		JSONArray completeArray = new JSONArray();

		// Get the current JSON object from the file. The goal is to get the
		// entire contents of the JSON file (which is a JSON array), convert it
		// to a JSON array, add a new entry object, convert the new JSON object
		// to a string, then overwrite the JSON file with the new JSON array

		try {
			// Open the JSON file and initialize a string builder
			FileInputStream in = openFileInput(FILENAME);
			InputStreamReader inputStreamReader = new InputStreamReader(in);
			BufferedReader bufferedReader = new BufferedReader(
					inputStreamReader);
			StringBuilder sb = new StringBuilder();
			String line;
			// Read the existing content in the JSON file and add it to the
			// string builder
			while ((line = bufferedReader.readLine()) != null) {
				sb.append(line);
			}

			 // If the string builder is not empty (ie, the file was not empty),
			 // we convert the contents to a JSON array and store it in a local
			 // variable

			if (sb.toString() != "") {
				JSONArray temp_arr = new JSONArray(sb.toString());
				completeArray = temp_arr;
			}

		} catch (IOException e) {
			e.printStackTrace();
		}

		catch (JSONException e) {
			e.printStackTrace();
		}

		// Initialize the JSON object for the new entry
		JSONObject entry = new JSONObject();
		// Initialize the JSON object that will contain the entry object
		JSONObject finalEntry = new JSONObject();

		try {
			// Add the time and date to the entry object
			entry.put("date", date);
			entry.put("time", time);
			entry.put("description", desc);
			// Add the entry object to a new object called "entry"
			finalEntry.put("entry", entry);
			
			 // Finally add the completed "entry" object into the array that was
			 // parsed from the JSON file. If the file was empty this entry will
			 // be the first object in the array. If the file was not empty this
			 // entry will be added to the end of the array
			 
			completeArray.put(finalEntry);

			// Convert the complete array in to a string
			String jsonEntry = completeArray.toString();

			// Write complete array to the file
			FileOutputStream fos = openFileOutput(FILENAME,
					Context.MODE_PRIVATE);
			fos.write(jsonEntry.getBytes());
			fos.close();
			// Notify that an entry has been created
			Toast toast = Toast.makeText(getApplicationContext(),
					"Entry Created", Toast.LENGTH_LONG);
			toast.show();
		}

		catch (JSONException e) {
			e.printStackTrace();
		}

		catch (IOException e) {
			e.printStackTrace();
		}
	}
}

MainActivity can be divided into three basic sections:

1. onCreate

Not very interesting – it just sets the view to the correct layout file.

2. Button Click Handler – clickListener()

In my opinion the cleanest and most intuitive technique for handling button clicks is to use a common click handler function. This click listener uses a Switch statement to handle the different buttons. Each button ID gets a case. Here is the function. It is placed inside the MainActivity class.

	// Click Listener for the buttons on the main screen
	public void clickListener(View v) {

		switch (v.getId()) {

		case R.id.button_log:
			logDateTime();
			break;

		case R.id.button_view_log:
			Intent viewLog = new Intent(this, LogActivity.class);
			startActivity(viewLog);
			break;

		default:
			break;
		}
	}

3. JSON Management – logDateTime()

Create a local file
If you look up the reference code for storing a local file from the Android Developer site you’ll find an example for creating and appending a locally stored file. That’s okay for a simple example but in our case we actually don’t want to append a local file. We want to overwrite it each time a new JSON object is added. The complete process is:

  1. Create a local file if it doesn’t exist
  2. Read the local file and convert it to a JSON Array
  3. Add a new entry to the JSON Array
  4. Overwrite the local file with the updated JSON Array

First define variables:

	String FILENAME = "log.json";
	String date = DateFormat.getDateInstance().format(new Date()); // <-- Gets the current date
	String time = DateFormat.getTimeInstance().format(new Date()); // <-- Gets the current time
	String desc = "Entry Created"; // Arbitrary description
	JSONArray completeArray = new JSONArray();

Next we want to open the JSON file and read the contents. If the file is empty we can move on to creating the JSON Array. If the file is not empty we need to read the contents, convert it to a string, then convert the string into a JSON Array:

		try {
			// Open the JSON file and initialize a string builder
			FileInputStream in = openFileInput(FILENAME);
			InputStreamReader inputStreamReader = new InputStreamReader(in);
			BufferedReader bufferedReader = new BufferedReader(
					inputStreamReader);
			StringBuilder sb = new StringBuilder();
			String line;
			// Read the existing content in the JSON file and add it to the
			// string builder
			while ((line = bufferedReader.readLine()) != null) {
				sb.append(line);
			}
			
			 // If the string builder is not empty (ie, the file was not empty),
			 // we convert the contents to a JSON array and store it in a local
			 // variable
			 
			if (sb.toString() != "") {
				JSONArray temp_arr = new JSONArray(sb.toString());
				completeArray = temp_arr;
			}

		} catch (IOException e) {
			e.printStackTrace();
		}

		catch (JSONException e) {
			e.printStackTrace();
		}

Again the whole purpose of the above code is to use the existing JSON array if one exists. If the file is empty then the array initialized with the variables will still be empty.

Finally we want to create a new JSON object to store the date, time, and description. Then we give the JSON object a name and add it the JSON Array. Lastly we convert the updated JSON Array into a string, overwrite the local file with the updated Array, and notify the user that an entry has been created:

		// Initialize the JSON object for the new entry
		JSONObject entry = new JSONObject();
		// Initialize the JSON object that will contain the entry object
		JSONObject finalEntry = new JSONObject();

		try {
			// Add the time and date to the entry object
			entry.put("date", date);
			entry.put("time", time);
			entry.put("description", desc);
			// Add the entry object to a new object called "entry"
			finalEntry.put("entry", entry);
			
			 // Finally add the completed "entry" object into the array that was
			 // parsed from the JSON file. If the file was empty this entry will
			 // be the first object in the array. If the file was not empty this
			 // entry will be added to the end of the array
			 
			completeArray.put(finalEntry);

			// Convert the complete array in to a string
			String jsonEntry = completeArray.toString();

			// Write complete array to the file
			FileOutputStream fos = openFileOutput(FILENAME,
					Context.MODE_PRIVATE);
			fos.write(jsonEntry.getBytes());
			fos.close();
			// Notify that an entry has been created
			Toast toast = Toast.makeText(getApplicationContext(),
					"Entry Created", Toast.LENGTH_LONG);
			toast.show();
		}

		catch (JSONException e) {
			e.printStackTrace();
		}

		catch (IOException e) {
			e.printStackTrace();
		}

That’s it for encoding our JSON data. Now each time the button is clicked an entry is added to the current array, then the updated array overwrites the old one. Using this method we maintain a file containing one JSON Array with an object for each entry (representing each button click).

Entry class – Entry.java

Now we want to create a Java class with the same structure as our JSON data. We’ll need this class in order to easily build a list of entries that we can pass into our ListView.

public class Entry {
	public String date;
	public String time;
	public String description;
	
	// -------------- SET METHONDS --------------
	
	public void setDate(String str) {
		this.date = str;
	}
	public void setTime(String str) {
		this.time = str;
	}
	public void setDescription(String str) {
		this.description = str;
	}
	
	// -------------- GET METHONDS --------------
	
	public String getDate() {
		return this.date;
	}
	public String getTime() {
		return this.time;
	}
	public String getDescription() {
		return this.description;
	}
	
}

ListView Adapter – LogAdapter.java

This section is probably the most challenging to understand. I’ve done my best to make it as easy as possible. Here is the complete code.

import java.util.List;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

public class LogAdapter extends BaseAdapter {

	protected Context _context;
	List<Entry> entryList;
	
	public LogAdapter(Context context, List<Entry> eList){
		_context = context;
		entryList = eList;
	}
	
	
	@Override
	public int getCount() {
		return entryList.size();
	}

	@Override
	public Object getItem(int arg0) {
		return entryList.get(arg0);
	}

	@Override
	public long getItemId(int arg0) {
		return arg0;
	}

	@Override
	public View getView(int arg0, View arg1, ViewGroup arg2) {

		if (arg1 == null) {
			LayoutInflater mInflater = (LayoutInflater) _context
					.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
			arg1 = mInflater.inflate(R.layout.adapter_log, null);
		}

		TextView title = (TextView) arg1.findViewById(R.id.titleTextView);
		TextView desc = (TextView) arg1.findViewById(R.id.descriptionTextView);

		Entry entry = entryList.get(arg0);

		title.setText(entry.description);
		desc.setText(entry.date + " at " + entry.time);

		return arg1;
	}

}

When you create a new class and add “extends BaseAdapter” Eclipse will automatically detect that you need some “stuff” in your class and add it for you. Below is what you will see (I called my class LogAdapter.java”

import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;

public class LogAdapter extends BaseAdapter{

	@Override
	public int getCount() {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public Object getItem(int arg0) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public long getItemId(int arg0) {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public View getView(int arg0, View arg1, ViewGroup arg2) {
		// TODO Auto-generated method stub
		return null;
	}

}

To make functions easier to use we should pass our class a Context and a List. I’ll explain the list in detail later. For now just know that we should pass it into the class. Add the following code to your class.

	protected Context _context;
	List<Entry> entryList;
	
	public LogAdapter(Context context, List<Entry> eList){
		_context = context;
		entryList = eList;
	}

The only really interesting part of the list adapter is in the fourth method called getView. Here is where you “map” the input data to the parts of the layout you created earlier:

if (arg1 == null) {
			LayoutInflater mInflater = (LayoutInflater) _context
					.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
			arg1 = mInflater.inflate(R.layout.adapter_log, null); // <-- replace the ID with the ID of your adapter layout you created earlier
		}

                // Initialize variables and point them to the appropriate element of your adapter layout
		TextView title = (TextView) arg1.findViewById(R.id.titleTextView);
		TextView desc = (TextView) arg1.findViewById(R.id.descriptionTextView);

                // Get the element of the list you passed into the function and convert it to an Entry object
		Entry entry = entryList.get(arg0);

                // Map the fields of the object to the correct element of your layout
		title.setText(entry.description);
		desc.setText(entry.date + " at " + entry.time);

                // Done
		return arg1;

Finally – View the JSON log as a ListView – LogActivity.java

Almost done, I promise. The only thing left to do is to populate a ListView with the JSON data. Here is the code:

package com.kanzelmeyer.json;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.os.Bundle;
import android.app.Activity;
import android.app.AlertDialog;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.ListView;
import android.widget.Toast;
import android.support.v4.app.NavUtils;
import android.annotation.TargetApi;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Build;

public class LogActivity extends Activity {


	final String FILENAME = "log.json";
	LogAdapter adapter;

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

		// Show the Up button in the action bar.
		setupActionBar();

		// Create an entry class list from the log file
		List<Entry> entryList = getLogList();

		// Pass the context and Entry object list to the list view adapter
		LogAdapter adapter = new LogAdapter(this, entryList);

		// Populate the list view with the custom adapter
		ListView logView = (ListView) findViewById(R.id.logListView);
		logView.setAdapter(adapter);

	}

	public List<Entry> getLogList() {

		// Initialize a list of Entry objects
		List<Entry> entryList = new ArrayList<Entry>();

		try {
			// Open the file and parse it into a string builder
			FileInputStream in = openFileInput(FILENAME);
			InputStreamReader inputStreamReader = new InputStreamReader(in);
			BufferedReader bufferedReader = new BufferedReader(
					inputStreamReader);
			StringBuilder sb = new StringBuilder();
			String line;

			while ((line = bufferedReader.readLine()) != null) {
				sb.append(line);
			}

			// Convert the string builder into a JSON array
			JSONArray completeArray = new JSONArray(sb.toString());
			
			// Initialize some temporary variables to store the data 
			// we want from the JSON objects
			String logDate, logTime, logDesc;
			
			 // Iterate through the JSON array, store each object in a
			 // temporary object, create an entry object from the temporary 
			 // object, then add the Entry object to the Entry object list 
			 
			for (int i = 0; i < completeArray.length(); i++) {

				JSONObject dummyObj = completeArray.getJSONObject(i);
				// Get the object called 'entry'
				JSONObject tempObj = dummyObj.getJSONObject("entry");

				logDate = tempObj.getString("date");
				logTime = tempObj.getString("time");
				logDesc = tempObj.getString("description");

				// Create an entry objects (entryObj)
				Entry entryObj = new Entry();
				entryObj.date = logDate;
				entryObj.time = logTime;
				entryObj.description = logDesc;
				// Add the entry object to the list
				entryList.add(entryObj);
			}

		} catch (IOException e) {
			e.printStackTrace();
		}

		catch (JSONException e) {
			e.printStackTrace();
		}
		
		// Return the entry list that contains an entry object for each entry in the 
		// JSON array from the JSON log file
		return entryList;

	}

	
	 // Set up the {@link android.app.ActionBar}, if the API is available.
	 
	@TargetApi(Build.VERSION_CODES.HONEYCOMB)
	private void setupActionBar() {
		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
			getActionBar().setDisplayHomeAsUpEnabled(true);
		}
	}

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

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		switch (item.getItemId()) {
		case android.R.id.home:
			// This ID represents the Home or Up button. In the case of this
			// activity, the Up button is shown. Use NavUtils to allow users
			// to navigate up one level in the application structure. For
			// more details, see the Navigation pattern on Android Design:
			//
			// http://developer.android.com/design/patterns/navigation.html#up-vs-back
			//
			NavUtils.navigateUpFromSameTask(this);
			return true;
			
		case R.id.clear_log:
			// Dialog box to confirm the delete log action
			new AlertDialog.Builder(this)
			.setTitle(R.string.clear_log)
			.setMessage("Do you really want to delete all log entries?")
			.setIcon(android.R.drawable.ic_dialog_alert)
			.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {

			    public void onClick(DialogInterface dialog, int whichButton) {
			    	clearLog();
			    	Intent it = new Intent(LogActivity.this, MainActivity.class);
                    it.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);  
                    startActivity(it); 
			    }
				})
			 .setNegativeButton(android.R.string.no, null).show();
			break;

		case R.id.action_settings:
			break;

		}
		return super.onOptionsItemSelected(item);
	}
	
	private void clearLog() {
		// Blank string that we will write to the File
		String clear = "";

		// Open the file in MODE_PRIVATE which will allow us to overwrite the file
		
		try {
			// Write the blank string to the file
			FileOutputStream fos = openFileOutput(FILENAME, MODE_PRIVATE);
			fos.write(clear.getBytes());
			fos.close();

			// Notify the user that the log was cleared
			Toast toast = Toast.makeText(getApplicationContext(),
					"Log Cleared", Toast.LENGTH_LONG);
			toast.show();

		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

It seems like a lot but there are basically just three chunks:

1. onCreate

Here is where we initialize the List that we need to pass to our Adapter, call the Adapter, then populate the ListView with our custom adapter. Initializing the list is where we use the JSON data. Its the lion’s share of the work in this class. As an added bonus there is also a menu with a Clear Log option. When you click “Clear Log” it prompts the user to confirm his request. If confirmed the JSON file is cleared and the user is sent back to the home screen.

	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_log);

		// Show the Up button in the action bar.
		setupActionBar();

		// Create an entry class list from the log file
		List<Entry> entryList = getLogList();

		// Pass the context and Entry object list to the list view adapter
		LogAdapter adapter = new LogAdapter(this, entryList);

		// Populate the list view with the custom adapter
		ListView logView = (ListView) findViewById(R.id.logListView);
		logView.setAdapter(adapter);

	}

Use the JSON data – getLogList()

This function is the real workhorse of this class. It reads the JSON file that we created on the main page and converts it to a list of Entry objects as defined by our Entry class. The process is:

  1. Read the JSON file and convert it to a string
  2. Convert the string to a JSON Array
  3. Iterate through the JSON Array and build an Entry object for each object in the JSON Array
  4. Add each Entry object to a list of Entry objects
  5. Return the complete List of Entry objects
	public List<Entry> getLogList() {

		// Initialize a list of Entry objects
		List<Entry> entryList = new ArrayList<Entry>();

		try {
			// Open the file and parse it into a string builder
			FileInputStream in = openFileInput(FILENAME);
			InputStreamReader inputStreamReader = new InputStreamReader(in);
			BufferedReader bufferedReader = new BufferedReader(
					inputStreamReader);
			StringBuilder sb = new StringBuilder();
			String line;

			while ((line = bufferedReader.readLine()) != null) {
				sb.append(line);
			}

			// Convert the string builder into a JSON array
			JSONArray completeArray = new JSONArray(sb.toString());
			
			// Initialize some temporary variables to store the data 
			// we want from the JSON objects
			String logDate, logTime, logDesc;
			
			// Iterate through the JSON array, store each object in a
			// temporary object, create an entry object from the temporary 
			// object, then add the Entry object to the Entry object list 
			
			for (int i = 0; i < completeArray.length(); i++) {

				JSONObject dummyObj = completeArray.getJSONObject(i);
				// Get the object called 'entry'
				JSONObject tempObj = dummyObj.getJSONObject("entry");

                                // Store the JSON values in temporary variables
				logDate = tempObj.getString("date");
				logTime = tempObj.getString("time");
				logDesc = tempObj.getString("description");

				// Create an entry objects (entryObj) with the JSON values
				Entry entryObj = new Entry();
				entryObj.date = logDate;
				entryObj.time = logTime;
				entryObj.description = logDesc;
				// Add the entry object to the list
				entryList.add(entryObj);
			}

		} catch (IOException e) {
			e.printStackTrace();
		}

		catch (JSONException e) {
			e.printStackTrace();
		}
		
		// Return the entry list that contains an entry object for each entry in the 
		// JSON array from the JSON log file
		return entryList;

	}

3. Menu stuff (optional)

I’ve created a simple menu option that clears log. To set up this menu first create a menu for this page. Menus are xml files stored in res/menu. Below is the menu I’ve created.

log.xml

<menu xmlns:android="http://schemas.android.com/apk/res/android" >
    <item
        android:id="@+id/clear_log"
        android:showAsAction="never"
        android:title="@string/clear_log"/>
    <item
        android:id="@+id/action_settings"
        android:orderInCategory="100"
        android:showAsAction="never"
        android:title="@string/action_settings"/>
</menu>

Now we just need to implement the menu and define what to do with each option. The click handler for the menu is similar to the click handler we created for the buttons. The case for the home button was automatically generated by the Android SDK because when I created the LogActivity class I specified that the parent was MainActivity, therefore it adds the back button functionality for SDK versions that support it. The case for the clear_log option is intended to erase the contents of the JSON file. Since erasing a file is a permanent operation I think its appropriate to confirm the action with user before acting. So the function uses a dialog box to prompt the user to confirm his choice. If the choice is confirmed the clearLog() function is called and the user is “redirected” to the home screen.

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		switch (item.getItemId()) {
		case android.R.id.home:
			// This ID represents the Home or Up button. In the case of this
			// activity, the Up button is shown. Use NavUtils to allow users
			// to navigate up one level in the application structure. For
			// more details, see the Navigation pattern on Android Design:
			//
			// http://developer.android.com/design/patterns/navigation.html#up-vs-back
			//
			NavUtils.navigateUpFromSameTask(this);
			return true;
			
		case R.id.clear_log:
			// Dialog box to confirm the delete log action
			new AlertDialog.Builder(this)
			.setTitle(R.string.clear_log)
			.setMessage("Do you really want to delete all log entries?")
			.setIcon(android.R.drawable.ic_dialog_alert)
			.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {

			    public void onClick(DialogInterface dialog, int whichButton) {
			    	clearLog();
			    	Intent it = new Intent(LogActivity.this, MainActivity.class);
                    it.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);  
                    startActivity(it); 
			    }

				})
			 .setNegativeButton(android.R.string.no, null).show();
			
			
			break;

		case R.id.action_settings:
			break;

		}
		return super.onOptionsItemSelected(item);
	}

The clearLog() function simply overwrites the JSON file with a blank string and notifies the user that the log has been cleared:

	private void clearLog() {
		// Blank string that we will write to the File
		String clear = "";
		// Open the file in MODE_PRIVATE which will allow us to overwrite
		// the file

		try {
			// Write the blank string to the file
			FileOutputStream fos = openFileOutput(FILENAME, MODE_PRIVATE);
			fos.write(clear.getBytes());
			fos.close();

			// Notify the user that the log was cleared
			Toast toast = Toast.makeText(getApplicationContext(),
					"Log Cleared", Toast.LENGTH_LONG);
			toast.show();

		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

That’s it! Give it a test drive!

android_json_listView_entry_created

android_json_listView_custom_adapter

Arduino Motion Sensor Function

I worked on a project recently and needed a good function to read the input from a PIR motion sensor for my Arduino. I found the PIRsense source code on Arduino’s website (http://www.arduino.cc/playground/Code/PIRsense ) and modified it into a function. Feel free to use for your Arduino motion sensor projects.

The function is boolean, meaning it returns either TRUE or FALSE. Good luck with your projects!

Begin Code:

// **************** DEBOUNCE THE MOTION SENSOR **************
boolean motionDetected(){
/////////////////////////////
//VARS
long unsigned int lowIn;
//the amount of milliseconds the sensor has to be low
//before we assume all motion has stopped
long unsigned int pause = 5000;
boolean lockLow = true;
boolean takeLowTime;

if(digitalRead(PIR_PIN) == HIGH){
return true;
if(lockLow){
//makes sure we wait for a transition to LOW before any further output is made:
lockLow = false;
delay(50);
}
takeLowTime = true;
}

if(digitalRead(PIR_PIN) == LOW){
if(takeLowTime){
lowIn = millis(); //save the time of the transition from high to LOW
takeLowTime = false; //make sure this is only done at the start of a LOW phase
}
//if the sensor is low for more than the given pause,
//we assume that no more motion is going to happen
if(!lockLow && millis() – lowIn > pause){
//makes sure this block of code is only executed again after
//a new motion sequence has been detected
lockLow = true;
delay(50);
}
}
return false;
}

//END CODE

 

This code is a function to use a motion sensor, or a PIR, with your arduino. If you are building a project which needs a motion sensor or PIR, use this function.

Weekend Project: Touch Torch – Simple no-button flashlight using a touch transistor switch circuit

My homemade Touch Torch. To use the flashlight, simply touch both terminals on the side of the Altoids box! Build this simple no-button flashlight for only a few dollars in parts! This is an excellent children’s project. You can build this in an afternoon with your son or daughter, and it can help encourage your child to enjoy electronics!

You’ll need:

  1. Two LEDs.
  2. Two resistors (330 Ohm, 10k ohm)
  3. Two NPN transistors (or a Darlington pair) Any common low power transistors should work.
  4. 9v battery
  5. Altoids bin (or any small box)
  6. Two small bolts and nuts
  7. Two rubber insulators
  8. Soldering iron, solder, wire, and glue.

The circuitry in the flashlight is very simple. It uses a Darlington transistor to amplify a small current that travels through your body. The circuit is called a “touch switch”, or a touch circuit, and there are many types of these circuits. The circuit schematic is below:

touch transistor

1. Start by soldering the transistors together. If you are using a Darlington pair, you can skip this step. Solder the base of one transistor to the emitter of the other. Then solder both collectors together. Now you have a single Darlington transistor.

Go ahead and solder a lead to the collectors and a lead to the emitter as well, you’ll need it later.

2. Solder the 10k resistor to the base of your Darlington pair. (Here I’m using 180 ohm because that’s what I had laying around. The value isn’t crucial, but I would recommend  between 1k and 10k.)

3. Solder the LEDs together. Solder both positive leads together and both negative leads together. This puts the two in parallel so that they receive the same voltage. Solder leads to each terminal.

4. Solder! The negative LED lead to the collector of the Darlington pair, and solder the 330 ohm resistor to the positive lead of the LEDs. Solder the other side of the resistor to the positive lead of the battery. Lastly, (whew!) solder one extra lead to the power supply side of the resistor. (In the photo below: top red lead goes to battery, black lead is the extra lead, bottom red lead goes to positive of LEDs.)

5. Solder the negative battery lead to the emitter of the Darlington transistor. Done with soldering now!

Now, prepare the Altoids bin. To drill holes in the metal bin, I recommend drilling a pilot hole (seen below). Drill two holes on the end for the LEDs. Then drill a hole on either side of the bin for the screws. Insert some non-conductive insulators into and around the holes on the sides.

Side holes with insulators.

Pilot holes for the LEDs

I don’t remember where I found those convenient insulators, but you can improvise an insulator by putting a small piece of electrical tape on the outside of the container covering the hole. Use an Exacto knife to cut a plus sign in the tape across the hole, then curl the electrical tape through the hole. Repeat the process starting from the inside of the bin. The object is to prevent the metal screws from contacting the container. If you are using a non-conductive container (like wood or plastic), then you can skip all this.

ALMOST DONE! Insert a small bolt into each hole (head on the outside). Remember the extra lead you soldered to the positive battery terminal (step 4)? Wrap the other end of this lead around one of the bolts on the inside, then use the nut to tighten it down against the insulation, thereby tightening the bolt in place.

For the other bolt, wrap the lose end of the base 10k resistor (step 2) around the bolt and tighten it down with the nut. Make sure the two bolts aren’t touching each other and aren’t touching the Altoids bin. Also, cover all the solder connections and bare wire with electrical tape so it doesn’t short on anything. All that’s left is to connect the power supply! Hope you enjoy this project!

Get awesome royalty free photos at 123RF Stock Photos!

Arduino: Upload HEX Files to ATtiny85 Using Your Arduino and AVRdude

Use your Arduino UNO to upload a HEX file to an Atmel ATtiny85. In this tutorial, I am using Windows 7 64 bit.

Sources:

You’ll need:
HARDWARE:

  • Arduino UNO (or something similar)
  • ATtiny85 (or similar Atmel target microprocessor
  • jumper wires
SOFTWARE:
  • Arduino environment (latest release)
  • AVRdude (latest release)
  • a test HEX file (I used the TV-B-Gone hex file)

Arduino
If you’re like me, you’ve spent countless hours with budget ISP programmers (like the AVR Pocket Programmer) and had little success uploading HEX files to the ATtiny85. Fortunately, if you own an Arduino, then you do not need another ISP. Turn your Arduino into an ISP by completing the following steps:
  1. Connect the board as usual for uploading code.
  2. Go to File  > Examples > ArduinoISP
  3. Upload this sketch to the Arduino
If you need to generate a HEX file in Arduino, you can do so by holding “Shift” and clicking “Verify”. If the sketch compiles correctly, the second to last line in the output will be the path name to the HEX file. For example, using the simple Blink program, the output should be something like:
C:\DOCUME~1\user\LOCALS~1\Temp\build2695350595880978373.tmp\Blink.cpp.hex
Copy this location because you’ll need it later if you don’t already have a HEX file to upload.
Lastly, note the COM port used by the Arduino. My computer uses COM3. You will need this later.

Hardware
Using a breadboard, make the following connections between the Arduino and the ATtiny85. Use the picture for reference. (Source). *Note the 10 microfarad cap between RESET and Gnd on the Arduino
  • ATtiny Pin 7 to Arduino Pin 13 (SCK)
  • ATtiny Pin 6 to Arduino Pin 12 (MISO)
  • ATtiny Pin 5 to Arduino Pin 11 (MOSI)
  • ATtiny Pin 1 to Arduino Pin10 (RESET)
  • ATtiny Pin 8 to Arduino +5v (Vcc)
  • ATtiny Pin 4 to Arduino GND (Ground)

AVRdude
So far so good, now time for AVRdude (assuming it’s already installed, if not, click here for instructions). Open the command prompt (Start >> type “CMD”, hit enter) . Navigate to the directory containing the HEX file by typing “cd” then the directory, like:
cd C:\users\folder_containing_HEX_file
Now that you are in the right directory, all that’s left is to blast the file into the ATtiny85. To do so, use the following command:

avrdude -P comport -b 19200 -c avrisp -p attiny85 -v -e -U flash:w:hexfilename.hex

, replacing comport with the proper comport (like COM3) and hexfilename with the proper name. Hit Enter, and if all the planets align, the code will be uploaded successfully. It may take a few seconds.

Debugging:
If you encounter any error messages, you may try disconnecting the Arduino UNO from your computer and reconnecting it. You can also try uploading the ArduinoISP sketch again.
Be sure to check out…
For a fun weekend build using the techniques in this post, check out the $3.50 TV B Gone clone by darksponge.
Closing Remarks
I came up with this method by combining two methods I read about. I haven’t been able to find a tutorial that explains this very clearly, so I hope this helps. Please read the sources for additional information on programming these devices.

Arduino H Bridge Motor Control

Use your Arduino and some transistors to control the direction of a DC motor!

Parts:

  • Breadboard
  • 2 NPN transistors (2N4401 or almost any general purpose NPN)
  • 2 PNP transistors (2N4403 or almost any general purpose PNP)
  • Low power DC motor (3 to 9V)
  • Arduino
  • Hookup wire

Almost any NPN and PNP transistors will do for this project, because the motor is low power. If you are short on low power DC motors, don’t worry, they are everywhere! Specifically, if you have an old cd player, tape player, or computer cd drive, you can usually find plenty of motors inside those devices. Be careful to choose lower power, though. It’s generally a bad idea to source a lot of current from your Arduino. Look for any 3 to 9 volt motor for this project.

To begin, build the schematic below on your breadboard. The PNP transistors are on top, and the NPN transistors are on bottom.

Once the build is complete, copy and paste the following code into a new sketch in your Arduino IDE:
/*
  H bridge test

  This is a simple test for a homemade h bridge using two
  npn transistors and two pnp transistors.

  There are only two control signals, we'll call them A and
  B. When A is 0 and B is 1, the motor should run in one
  direction. When A is 1 and B is 0, the motor should run
  in the opposite direction.

 */

void setup() {
  // initialize the digital pins as outputs.
  pinMode(8, OUTPUT);    // "A"
  pinMode(9, OUTPUT);    // "B"
}

void loop() {
  digitalWrite(8, HIGH);   // begin motion
  digitalWrite(9, LOW);
  delay(2000);              // wait for two seconds
  digitalWrite(8, LOW);    // change directions
  digitalWrite(9, HIGH);
  delay(1000);              // wait for one second
}
The project works by using a two bit input from the Arduino. When A is “1” and B is “0”, current flows as follows:
When A is “0” and B is “1”, current flows in the opposite direction:
H bridge npn pnp transistors
The arrangement works because the NPN transistors allow current to flow when the base voltage is high, and the PNP transistors allow current to flow when the base voltage is low.
Coming soon: Use an H bridge to control a turret!

Review: Samsung Epic 4G Review

Samsung epic 4g review

Samsung Epic 4G review

Samsung Epic 4G on Sprint’s Now Network

 

Physical Aspects: 

Overall, it’s nearly a grand slam. The display gets five stars for sure. I’ll discuss the reasons for the less-than-perfect rating momentarily. The AMOLED screen is incredible. It has excellent color, depth, and contrast. It is great for media application. Also five gold stars for the Gorilla Glass screen. I don’t plan to test the glass, but I feel good knowing it’s there. The back of the phone has a slight contour which feels nice in your hand. The screen is 4 inches, which is a perfect size. Check out more technical specs here. Here’s why I gave it four stars rather than five:

  • The sleep/ screen lock button. The sleep button is in an awkward location. It’s on the upper right side, towards the back. Maybe it’s just me here…but when I push the button with my thumb, my fingers push and slide the screen open a little.
  • Battery life. Powering the giant AMOLED drains the battery very quickly. It also takes a long time to charge (2+ hours). This is a little annoying. The best remedies are to download task killing apps like Advanced Task Killer, actively manage services like Wi-fi, GPS, and 4G, and keep plenty of chargers at work and home!
The camera shoots great pictures and video, especially in natural daylight. The headphone jack is on top, which is great. The Epic also uses a micro USB cable for charging and data transferring. This is convenient, as more and more of Sprint’s phones are using this.
The keyboard is pretty cool. I am used the display keyboard and was a little leery of a keyboard phone, but it is pretty cool. Nice for texting.
Operating System and Speed 
Currently, the phone runs on Android 2.2 (we’re anxiously awaiting the release of 2.3). Everything is satisfyingly fast. Apps open, navigate, and close quickly. As of today, one of the only big quirks with the operating system is in the camera. The camera is orientated for landscape use (which, albeit, takes better pictures), but it will not orientate to “portrait”.
Unfortunately, there is no streaming Netflix for this phone yet. Luckily, the phone is quickly gaining popularity. The HTC Evo and Nexus S 4G both have Netflix, so I’m sure it’s only a matter of time before the Epic will have it.
Signal Strength and Reception 
The Epic gets excellent signal reception. I haven’t encountered any problems yet. It picks up wi-fi and Sprint’s carrier signal very well. No oddities.
Overall 
Nice job, Samsung. The size of the phone and display really make the Epic a fun phone. It’s great for watching youtube and other video, as well as texting, messaging, browsing, and music.

 

 

Review: HTC Evo 4G Review

HTC Evo 4g review

HTC Evo 4g review

HTC’s Evo 4G on Sprint’s Now Network.

Physical Aspects:

This phone is a monster. It’s the biggest screen I’ve ever used (4.3 inches), and I love it. It’s super easy to use, I like the sleep button on top and the volume on the sides. The headphone jack is on top, which I also like. The charging jack is on the bottom. However, here’s why it did not receive a full five out of five stars from me:

  • Screen resolution and brightness– iPhone 4 set a very high standard here. The Evo has great resolution (WVGA 800 x 480), but not as good as the iPhone 4 (640 x 960). The Evo screen is LCD, which is great for low power consumption, but it is not as vibrant as the iPhone 4′s Retina Display or the Samsung Epic 4G’s AMOLED display.
  • Screen glass – Evidently it is just as fragile as the iPhone 4. Wish it had Gorilla Glass like the Samsung Epic 4G. Not a deal breaker for me, just bought an otterbox to keep it safe. I’m pretty careful with my phones anyway…
  • Music and charging, simultaneously, with one cord. Apple nailed this one as well. Wish the Evo could do this, but for now, two cords must be used. Not the end of the world…
The 8 megapixel rear camera is nice (compare to 5 megapixel in iPhone 4).  Photo and Video quality are great, especially outdoors. The Evo also has a front face camera (lower resolution). I haven’t used it yet…
The battery life is acceptable. A full charge lasts me all day, and I use my phone pretty heavily. Be sure the check out Advanced Task Killer, which will help prevent apps from remaining open too long.  You can also disable Wi-fi, GPS, and 4G when you are not using them to preserve battery life.
Operating System and Speed: 
The 1GHz processor is incredible. Everything on the phone is very fast. This is important to me, so the Evo gets five stars here. Everything loads, closes, and transitions quickly. Plus, the phone is equipped with HTC Sense, which is pretty cool. If you’r unfamiliar with HTC Sense, it’s basically a set of features from HTC to make your mobile phone experience a little better. Some of the features include a better navigation system which allows your to preview your entire route, rather than just seeing it turn by turn, and a flip-to-silence feature, which will silence your phone when you flip it on it’s face. Pretty handy for class or meetings or libraries.
Two more bonuses: 1. Android just released Gingerbread for the phone, so the Evo now has the latest release of Android. 2.  Netflix has written their app for the Evo, so the Evo can stream Netflix (so can the Nexus S 4G).
Signal Strength: 
The signal reception is incredible. Not much to say here. It’s leaps and bounds better than the Nexus S 4G. It picks up Sprint’s wireless signal and wi-fi signals very well. Kudos HTC.
Overall: 
Five stars. The phone is great and is a lot of fun. Good job HTC. 🙂

Review: Nexus S 4G Review

Nexus S 4G review

Nexus S 4G review

My wife and I finally liberated ourselves from the tyranny of AT&T Wireless and switched to Sprint. When we made the switch, I bought the Google’s Nexus S 4G. At the time, the phone had been out for only a week. I was excited to try the Google optimized smartphone.

Physical Aspects   

Totally sweet. Perfect size, light weight. The screen is slightly concave, which is very pleasing (don’t know why, but I really liked it). The glass is made of Gorilla Glass, so it is as durable as the Samsung Epic 4G. The headphone jack is on the bottom of the phone, which is a little awkward in the car. But overall, 5 stars for the physical aspects of the phone.

Operating system and speed   

I was super impressed with the phone’s speed. The operating system, Gingerbread, was my first experience with Android, and I was very impressed. Everything was fast and smooth. The Google experience was pretty cool. The operating system was basic…limited bells and whistles, which I liked. It made me feel like it was more efficient and streamlined. The Hummingbird processor is fast.

Signal Strength   

Okay, here’s the only tradeoff. The signal reception (wi-fi and network) was TERRIBLE. Inside my house, only 10 feet from my wireless router, I had only one or two bars out of three. On the road, my carrier signal was the same or worse. I never reached all three bars, and my coverage dropped in areas it should have been fine. I live in metro Atlanta, and basically every wireless provider has great coverage around here. My wife has the Samsung Epic 4G and it has full reception in our house and around town.

Overall   

Ultimately, the signal strength problem was too much. I need a reliable signal, I can’t deal with dropped calls. So I returned the phone and bought an HTC Evo 4G. The reception on the Evo is incredible. Check out my Evo review here.

Three out of five stars from me. The signal is basically the most important part of a smartphone. If Samsung can fix the reception problem, the phone would be a grand slam!

Weekend Project: DIY Home Audio System

For this weekend project, you will build your own powerful home audio system using used parts!

  • Computer tower power supply
  • Car head unit
  • Speakers
  • Electrical tape
  • A weekend

The best part of this project is that you can probably find all the parts for free! Ask your parents, siblings, and friends for the required parts.

Building a box is pretty easy with the right tools. I used a table saw, a router, and a nail gun. If you don’t have the know-how to make a box, try to find an existing box that’s large enough to accommodate all the parts.

Thanks to my dad and older brother for the parts!

Post your comments and questions, good luck!

Binary Search Tree


Heres a fun project to do with your GameBoy Advanced emulator. The Binary Search tree is a famous Computer Science search algorithm that can sort data, and quickly add/delete data from the list. More on Binary Search trees here.

The code is pretty straight forward. As with all GBA projects, the hardest part is configuring the emulator to execute properly on your computer. These projects are complied using Netbeans. The main.c program is only a few lines, but it requires a couple library files. COMPLETE SOURCE FILES HERE. (zip file) The main.c code is as follows:

#include “GBA_basics.h”
#include “BST.h”

/* Structures */
typedef enum {
splash, play
} STATE;

int main(void) {

int add;
STATE gameState = splash;
/* Initiate an empty tree */
BTNode *root = NULL;
int i, depth, dr, value, x;
int t = 0;
DMA_MEMCOPY3_SHRT(PALETTE_MEM, splashPal, 256);

#ifndef _DEBUG

#endif
setup();

/* A GBA program should never end*/
while (keepGoing()) {
/* wait for end of screen write*/
waitForScan();
/* Flip back and front*/
flipPage();
/* erase background*/

#ifndef _DEBUG
switch (gameState) {

case splash:
root = NULL;
x = 1; /* this variable is used at the beginning of PLAY*/
t++; /* increase this number at 60 hz to seed rand(); */
//fillBackGround(22);
copyImage(splashBitmap, 19200);
/* Only play if ENTER is pressed */
if (check_key(BUTTON_NDX_START) == KEY_RELEASED) {
gameState = play;
srand(t);
}
break;

case play:
if (x) {
for (i = 0; i < 10; i++) {//add 10 random nodes
value = rand() % 256;
BSTInsert(&root, value);
}
x = 0; //so this if statement only runs once, but is complied after SPLASH
}

fillBackGround(255);
depth = findDepth(root); //find depth
dr = (SCREEN_HEIGHT – 10) / depth; //find delta row based on depth
drawTree(root, 5, 120, 60, dr); //draw tree

/* ***** CONTROL ***** */

if (check_key(BUTTON_NDX_A) == KEY_RELEASED) {
add = rand() % 256;
/* insert value into the tree */
BSTInsert(&root, add);
}

if (check_key(BUTTON_NDX_START) == KEY_RELEASED) {
gameState = splash;
}

break;

#endif

}
}
finish();
return 0;
}