February 17, 2011

Android SQLite Library Example Code

Posted in Android Development tagged , , , , , , at 11:00 pm by tetontech

I have just uploaded QCDBAccess.  It is a SQLite wrapper for Android that is easy to use, thread-safe, and allows you to use transactions if you choose.  It is the same code that has been available for QCAndroid hybrid application developers for a few years.  I thought I would pull it out and give it its own life for those that want to use it on their own.

You can download it from SourceForge and find out more about it, including the API, at the QuickConnectFamily site.

As with all of the things I’m making available I have tried to make this as easy to use, highly functional, and small as possible.

The jar file is only 8k in size but the library doesn’t restrict your use of the databases in any way.

Here is a simple example of how to use the library to do a query against a SQLite database file included in your applications’ assets directory.  Notice that I’m checking to see if the user has entered a name to query against in an EditText object from the user interface.  If they have then I’m going to use a prepared statement.  The EditText object in this example has been passed into the method in which this code exists.

String sql = “SELECT * FROM user”;

String[] statementParams = null;

EditText nameInput = (EditText)methodParameters.get(1);

String name = nameInput.getEditableText().toString().trim();

if(name.length() > 0){

sql += ” WHERE name = ?”;

statementParams = new String[1];

statementParams[0] = name;

}

try {

retVal = DataAccessObject.getData(theActivity, “demo.sqlite”, sql, statementParams);

} catch (DataAccessException e) {

e.printStackTrace();

}

The DataAccessResult variable retVal is going to be returned from this method later.  This DataAccessResult is a Bean that contains resultant field names, the records returned from the query, and a database error description if and only if a database error happened.

the getData method is passed the Activity with which the database is associated with.  This is usually the main Activity in an Android Application.  The second parameter is the name of the SQLite database file to be used.  The third parameter is SQLite SQL assembled either as a standard or prepared statement.  The last parameter is an array of Objects that are to be bound to the ? characters if the SQL is a prepared statement or null if it is not a prepared statement.

Inserting data is done in very much the same fashion.  Once again I have an EditText object in the UI from which I’m getting the name to be inserted into the table.  I’m also generating a unique identifier just to make this a little more interesting.  You could do an auto incremented id in your table if you want.

EditText nameInput = (EditText)parameters.get(1);

String nameToAdd = nameInput.getEditableText().toString().trim();

String[]statementParams = {UUID.randomUUID().toString(), nameToAdd};

DataAccessResult aResult = null;

try {

aResult = DataAccessObject.setData(theActivity, “demo.sqlite”,

“INSERT INTO user VALUES(?,?)”,

statementParams);

return aResult;

} catch (Exception e) {

e.printStackTrace();

}

Notice that once again I have chosen to use a prepared statement.  I’m doing this to avoid SQL insertion attacks.  It never hurts to avoid those.

If you are going to do several insertions you should use transactions to make sure you data stays clean.  There is a startTransaction method and an endTransaction method in the DataAccessObject.  Use those before and after multiple setData calls and you will be safe.

Advertisements

January 25, 2011

QCJSON Now Thread Safe

Posted in Android Development, misc tagged , , , , , , , , , , , , at 7:25 am by tetontech

The changes described here are found in QCJSON v. 1.0.2 available on sourceForge .  The license is BSD.  You can get the source code from the git repository on sourceForge using the command:

git clone git://qcjson.git.sourceforge.net/gitroot/qcjson/qcjson

or look at it online.

I’ve been pondering how to make QCJSON thread safe meaning that you could read and write to the same stream from separate threads safely without impacting any other streams that may be being used in the same or other threads.

The problem description is that you don’t want to start a read when one is part way complete.  Nor do you want to start a write in the middle of another write.  Both of these situations plus mixing read and write can cause serious data corruption.

I briefly played with the idea of creating a Class that would contain a static semaphore.  This static semaphore would control access to the reading and writing behavior of the existing code.  The problem is that with this approach reading or writing to one stream on one thread would cause any other threads to wait at the semaphore claim location even if the stream that it wished to write to was in no way associated with the stream that was currently being used.  In other words reading or writing on one stream would block reading and writing on all streams until it was complete.  Obviously this is an unacceptable solution.  You might as well just write in one thread.

Since there is no way of interrogating an input our output stream object in Java it isn’t possible to hide the threading locks from the programmer using the QCJSON library and allow independent streams to work in independent threads.

While I’ve thought through several options the one that seems the best is to allow you, the developer, to pair input and output streams and include a semaphore in this pairing.  This is going to require a new class.

For lack of a better name I am calling this new class org.quickconnect.json.JSONStreamProtector.  It has a default constructor that takes no parameters and has one public method, protectJSONStream(JSONStream aStream).

If you instantiate a JSONStreamProtector you can pass the protectJSONStream method any number of JSONInputStreams and JSONOutputStreams.  Any streams that you pass as a parameter to this method will share the same semaphore.  Thus when you call readObject or writeObject on the protected streams any threads that would be using these streams will block in their readObject or writeObject methods until it is safe to proceed.

Using JSONStreamProtector

Changes have been made in the JSONInputStream and JSONOutputStream classes so that  if a protector has been set for them the stream will claim or wait until it is able to claim the semaphore in its defined protector.

You needn’t put the protector in a collection or some other class’ attributes in order for it to not be garbage collected.  Passing one JSONStream to the protectJSONStream method is sufficient.

In Example 1 the code shows how to protect a single output stream from three separate threads trying to write to the stream simultaneously.  Input streams work the same way.  Protecting an input/output stream pair that work on the same underlying resource would just mean using the same protector for both streams.

Any stream can only have one protector at a time.  This keeps your code from accidentally getting in a cross-locking situation.  You can switch the protector is is using at any time by calling the new protectors’ protectJSONStream method.

Example 1:

try {
/*
* Add three output streams to the same file and then have each of them send
* json to the stream. Make sure that no data corruption occurs.
*/
JSONStreamProtector aProtector = new JSONStreamProtector();
FileOutputStream testOut = new FileOutputStream(aFile);
/*
* stuff to write to file
*/
int[] testIntArray = {7,10,0,-789};
String[] testStringArray = {"What","is","happening?"};
TestObject anObject = new TestObject("Hello there.", 7, new Date(1067899));

 

/*
* do the running
*/
JSONOutputStream jsonTestOut1 = new JSONOutputStream(testOut);
aProtector.protectJSONStream(jsonTestOut1);

Thread testThread1 = new Thread(new ProtectorTestWriteRunnable(jsonTestOut1, testIntArray));

JSONOutputStream jsonTestOut2 = new JSONOutputStream(testOut);
aProtector.protectJSONStream(jsonTestOut2);

Thread testThread2 = new Thread(new ProtectorTestWriteRunnable(jsonTestOut1, testStringArray));

JSONOutputStream jsonTestOut3 = new JSONOutputStream(testOut);
aProtector.protectJSONStream(jsonTestOut3);

Thread testThread3 = new Thread(new ProtectorTestWriteRunnable(jsonTestOut1, anObject));
testThread1.start();
testThread2.start();
testThread3.start();

 

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

 

The source code for the protector class is simple so I’ll just put it here.


package org.quickconnect.json;

import java.util.concurrent.Semaphore;

public class JSONStreamProtector{
private Semaphore semaphore = new Semaphore(1, true);
public void protectJSONStream(JSONStream aJsonStream){

aJsonStream.setProtector(this);

}
protected void claim() throws InterruptedException{
semaphore.acquire(1);
}
protected void free(){
semaphore.release(1);
}
}

 

January 21, 2011

Android and JSON

Posted in Android Development, misc tagged , , , , , , , , , at 7:12 pm by tetontech

As I have been working with Android I found that the JSON library included in the standard Android library set was the one from JSON.org which is intended as a reference implementation.  When using that implementation I found that it is much more confusing than it needs to be.  To solve this problem I created a generic Java implementation usable in any Java situation including Android.  You can get it from sourceForge.  A JavaDoc API is included in the download.

Like the JavaScript implementation from JSON.org that is being embedded in all new browsers my implementation has stringify and parse methods.  These methods behave just like the ones in JavaScript and are static methods of the JSONUtilities class.

The stringify method  receives most any Serializable object, runs up its inheritance tree, and returns a JSON string that includes all of the attributes of all of the objects and all of the values from all of the collections found.  The only Serializable objects not accepted are raw Java Objects, since they have no attributes, and anything that inherits from java.awt.container.

The JSONUtilities.parse method takes a JSON formatted string as its parameter and returns either a HashMap or an ArrayList.  What is returned is dependent upon if the JSON container is an array or an associative array(object/map).

Here is an example from the JavaDocs of the string being parsed and what is produced.

  • Example 1 JSON: [“1”, “hello”, {“name”:”fred”,”age”:”23″}]
  • Example 1 Result: An ArrayList with three values: a String “1”, a String “hello”, and a HashMap as the third value in the ArrayList. This HashMap has two key/value pairs: “name”/”fred” and “age”/”23”.

 

  • Example 2 JSON: {“state”:”Idaho”, “city”:”Rexburg”, “people”:[“bob”,”sue”]}
  • Example 2 Result: A HashMap with three key/value pairs: “state”/”Idaho”, “city”/”Rexburg”, and “people”/ArrayList. The ArrayList that is the value for the “people” key has two String values “bob” and “sue”.

Object anObject = JSONUtilities.parse(aJSONString);

Here is an example of how the JSONUtilities stringify method works.

  • Example 1 Object: An ArrayList with three values: a String “1”, a String “hello”, and a HashMap as the third value in the ArrayList. This HashMap has two key/value pairs: “name”/”fred” and “age”/”23”.
  • Example 1 JSON result: [“1”, “hello”, {“name”:”fred”,”age”:”23″}]

 

  • Example 2 Object: A HashMap with three key/value pairs: “state”/”Idaho”, “city”/”Rexburg”, and “people”/ArrayList. The ArrayList that is the value for the “people” key has two String values “bob” and “sue”.
  • Example 2 JSON result: {“state”:”Idaho”, “city”:”Rexburg”, “people”:[“bob”,”sue”]}

String  jsonString = JSONUtilities.stringify(anObject);

 

In addition to these two utility methods there are two stream wrapper classes.  These behave much the ObjectOutput stream methods that are part of JavaSE.  They allow you to JSON an object into a stream and parse an object out of a stream.  These streams can be anything that inherits from InputStream or OutputStream.  For example, these could be a FileInputStream, a FileOutputStream, an input or output stream from a socket, etc.

Here is a code sample where the JSONOutputStream is wrapped around a FileOutputStream.  This would write the JSON to a file on disk.

HashMap aMap = new HashMap();

aMap.put(“stringOne”, “Some sort of string”);

aMap.put(“aNumber”, 16.5);

aMap.put(20,”some other stuff” );

aMap.put(“aTesterDate”,new Date());

try{

FileOutputStream aFileOutStream = new FileOutputStream(“testFile.txt”);

JSONOutputStream aJSONFileStream = new JSONOutputStream(aFileOutStream);

aJSONFileStream.writeObject(aMap);

}

catch(Exception e){

//do your exception handling

}

 

The code to read and parse JSON from a stream is similar.  Here is an example reading from a file.

try {

FileInputStream aFileInputStream = new FileInputStream(“testFile.txt”);

JSONInputStream inFromFile = new JSONInputStream(aFileInputStream);

Object anObject = inFromFile.readObject();

//if anObject is expected to be an ArrayList cast it as such and use it.

//if anObject is expected to be a HashMap cast it as such and use it.

} catch (Exception e) {

//do your exception handling here

}

 

I hope this helps you with your data communications in Android, JavaSE, and Java Enterprise.

 

September 5, 2009

QuickConnectAndroid 1.5 RC_1 Available

Posted in Android Development tagged , , , , , , , , , , , , , at 5:56 pm by tetontech

QuickConnectAndroid 1.5 RC_1 is now available for download from sourceForge.  It includes SQLite access with transactions, recording and playing recorded audio, playing system sounds, vibrating the device, and getting device information such as OS version, time zone, country, etc.

There are examples and source code for each of these capabilities.  QCAndroid is now updated to use the same version of the JavaScript QuickConnect framework that QCiPhone 1.5.0 and QCMac 1.5.0 uses.  Now all JavaScript should be portable between these platforms.  The next upgrade will be QCLinux.

May 1, 2009

Scrolling individual elements in hybrid or web applications

Posted in Uncategorized tagged , , , , , , , , , , , , at 6:24 pm by tetontech

A request has been made to show how individual elements in a hybrid or web application can be scrolled on the iPhone.  I have included some code below that has all of the JavaScript requried to accomplish this.  It comes from the QCUtilities.js file of QuickConnect iPhone 1.5 release that will be posted within a couple of days.

Because it is from QuickConnect it includes the ability to add request handling for when the user touches the screen in preparation for scrolling, as well as each time the finger is moved and when the scroll action is complete.  If you want to use this code outside of QuickConnect then remove everything regarding the startDragCmd, dragCmd, and dropCmd parameters.

If you want to use this within an older version of QuickConnectiPhone place the code in your version of the QCUtilities.js file and it works.

This approach uses the CSS transitions, proposed for HTML 5,  available in WebKit instead of the standard JavaScript approach since that approach is much to slow for both the iPhone and iPod touch devices.

To make an element scrollable call the makeScrollable function and pass the element you want to be scrollable as the first parameter.  If you want the element to not be scrollable below its original y axis location pass true as the second parameter of makeScrollable.  Here is the onload event code from the scrollingElements example of the  upcoming QuickConnectiPhone 1.5 release that sets three views in a view stack to be scrollable.

Making elements scrollable

function load()

{

dashcode.setupParts();

makeScrollable(document.getElementById(‘view1’));

makeScrollable(document.getElementById(‘view2’));

makeScrollable(document.getElementById(‘view3’));

}

Scrolling Functions to Add

/*

* Pass any DOM element to this function to make it scroll

* The *Cmd parameters are optional commands to be handled for

* scroll events.

*/

function makeScrollable(anElement, scrollBothUpAndDown, startDragCmd, dragCmd, dropCmd){

anElement.ontouchstart = prepareScroll;

anElement.ontouchmove = scrollIt;

anElement.ontouchend = scrollDone;

anElement.scrollBothUpAndDown = scrollBothUpAndDown;

//do not set or reset the commands if none are passed in.

if(startDragCmd){

anElement.startDragCmd = startDragCmd;

}

if(dragCmd){

anElement.dragCmd = dragCmd;

}

if(dropCmd){

anElement.dropCmd = dropCmd;

}

}

/*

* This function is triggered each time an ontouchmove event is

* fired for an element that has been passed to makeDraggable.

*/

function scrollIt(event)

{

stopDefault(event);

this.y = event.targetTouches[0].clientY – this.offsetY;

if(this.lastY){

this.y += this.lastY;

}

if(this.scrollBothUpAndDown || this.y < 0){

this.style.webkitTransform = ‘translate(0px, ‘ + this.y + ‘px)’;

}

else if(this.y >= 0){

this.style.webkitTransform = ‘translate(0px, 0px)’;

}

if(this.dragCmd){

var params = new Array();

params.push(event);

params.push(this);

handleRequest(this.dragCmd, params);

}

}

/*

* This function is triggered every time an ontouchstart event is

* fired for an element that has been passed to makeDraggable.

*/

function prepareScroll(event)

{

stopDefault(event);

//store off any timing and duration set anywhere else in the app

//and turn them off so they don’t interfere with the scrolling

this.timing = this.style.webkitTransitionTimingFunction;

this.style.webkitTransitionTimingFunction = null;

this.duration = this.style.webkitTransitionDuration;

this.style.webkitTransitionDuration = null;

this.touches = event.targetTouches;

this.offsetY = event.targetTouches[0].clientY;

if(this.startDragCmd){

var params = new Array();

params.push(event);

params.push(this);

handleRequest(this.startDragCmd, params);

}

}

/*

* This function is triggered every time an ontouchend event is

* fired for an element that has been passed to makeDraggable.

*/

function scrollDone(event)

{

//this.ontouchmove = null;

//this.ontouchend = null;

if(this.scrollBothUpAndDown || this.y < 0){

this.lastY = this.y;

}

else{

this.lastY = 0;

}

//restore any timing or duration that was set anywhere else in the app

this.style.webkitTransitionTimingFunction = this.timing;

this.style.webkitTransitionDuration = this.duration;

if(this.dropCmd){

var params = new Array();

params.push(event);

params.push(this);

handleRequest(this.dropCmd, params);

}

}

March 7, 2009

QuickConnectiPhone 1.5 Beta 2 now available

Posted in iPhone development tagged , , , , , , , , , , , , at 11:14 pm by tetontech

The second beta of QC 1.5 is now available for download from the SourceForge link found in the right-hand bar of this blog.

It contains several changes and fixes requested by you as well as the new Charting and Graphing Library.  Using this library you can create Pie, Line, Filled Line, and bar charts quickly and easily.  If you take a look at the source code for the library you will find that it uses the new HTML5 canvas tag and JavaScript.  You can now create this easily from within your JavaScript application.

Another change is the inclusion of Xcode code completion macros for the common QuickConnect JavaScript functions.  Also included are macros for inserting the new pie, line, and bar charts.

I’ll make a video of how to use these.

I will also make a video on how to use the new Dashcode snippets for creating the charts.

Here are the changes, not including the earlier beta 1 changes, for beta 2.

Changes for 1.5 beta 2

1.  Charting library added (line, filled line, bar, and pie charts).

2.  apostrophe’s and ampersands now can be used in native database data without issue.

3.  Links in your html files are now handled by launching of all known and custom applications.

a.  http://, https://, feed:// – launches Mobile Safari

b.  mailto:// – launches Mail app

c.  http://maps.google.com – map app

d.  http://www.youtube.com – YouTube app

e.  itms:// – iTunes store app  (get the full URL from running iTunes onyour desktop machine);

f.  http://phobos.apple.com – App Store app(get the full URL from running iTunes on your desktop machine)

g. tel:// – iPhone only.  Dial a phone number (any phone number entered automatically becomes a link)

h. sms: – iPhone only.  Launch the sms app (notice that there are no // characters)

i. yourCustomURL:// – a custom URL for an application you have created.

4.  The play() JavaScript function now automatically detects if the audio file name passed as a parameter is part of your application package resources and plays it if it is.  If it is not, it will look to see if it is a recorded audio file and then play it.  Supported audio file types are:

a. mp3

b. wav

c. aifc

d. aiff

e. m4a

f. mp4

g. caf

h. aac

5.  Language, region, and TimeZone are now included in the device description received from the call to the getDeviceDescription() JavaScript function.

6.  Custom Dashcode code snippets that let you drag and drop QuickConnect functionality to your JavaScript application

a. Pie Chart

b. Line Chart

c. Bar Chart

7.  Custom Xcode JavaScript auto-completions that let you quickly add available QuickConnect functionality to your JavaScript application

a. piechart – insert pie chart creation code

b. barchart – insert bar chart creation code

c. linechart – insert line chart creation code

d. draggable – code to make an element draggable

e. resuzable – code to make an element resizable

f. changeable – code to make an element draggable and resizable

g. vmap – mapCommandToVCF call

h. bmap – mapCommandToBCF call

i. emap – mapCommandToECF call

j. valmap – mapCommandToValCF call

k. smap – mapCommandTo SCF call

l. vcf – create a View Control Function

m. bcf – create a Business Control Function

n. ecf – create an Error Control Function

o. valcf – create a Validation Control Function

p. scf – create a Security Control Function

q. debug – code to make a debug message call

r. logerror – code to log an error

s. findloc – findLocation call

t. device – getDeviceDescription call

u. showmap – showMap call

v. syssound – playSystemSound call

w. vibrate – vibrate call

x. showpicker – showPicer call

y. recordaudio – recordAudio call

z. playaudio – play call

aa. stopplayaudio – stopPlaying call

%d bloggers like this: