Thursday, October 25, 2012

Clarifying Mediator pattern

 

 

Introduction

Mediator is design pattern that is primarily used to loose coupling between components in their communication. For instance, if each of components would communicate to each other directly, we could get a complex net of communication lines between these components. Instead of direct communication we are using mediator who will be intermediate component for inside communication between components.
Simple scenario for mediator role would be to gather messages from each component (component is in some books referred as Colleague), and than mediator would broadcast that message to all other components.
In the next image we can see UML class diagram showing us dependencies between classes in implementation of Mediator pattern. Mediator and Component can be either abstract classes or interfaces, depending of the specific implementation.

 
ClassDiagram
UML class diagram representing Mediator pattern
 
Now, there is a question, since mediator using broadcast, how each of components would know that the message is intended just for her. Well, in most cases message contains a key value that would be known to the receiver and sender, and it will be used to determine the originator and receiver of the message. There is also possibility to send sender and recipient information within the message. So, when the message is received by some component, component can determine if the message is intended for her or some other component, in that way message can be processed or ignored.
From the security side, this is not very safe way to distribute all messages as a broadcast, but if implementation is not restricted with security rules (for example, UI classes) than it can have a good purpose to decouple communication between components.

Implementation

In this blog I’ll demonstrate simple chat application written in Java. Application will contain three tabs (three components, i.e. Colleague), and each of the tabs will be able to communicate with other tabs over the Mediator. For the message representation I’ll implement Intent class which instances will be able to contain string messages. Of course, current implementation of Intent can be extended and used to wrap other object types in a message as well.

Mediator demo app
Screenshot of the Mediator demo application

Current implementation of demo project is demonstrated in the next picture:

NewDiagram
UML class diagram representing implementation of Mediator pattern
 

Source code from demo project can be downloaded from here.


Now, let’s take a look at the code.
This is simple Mediator interface that will be implemented in the Mediator class.

package com.testmediator;
public interface IMediator {
  public void addComponent(IComponent _component);
  public void send(Intent _message, IComponent _sender);
}

Class Mediator implements previous interface with two methods. Method addComponent is used for registering components, since the Mediator needs to know all actors of communication. Second method, send, simply broadcasts message to all of the components, except sender component.
package com.testmediator;
import java.util.ArrayList;
public class Mediator implements IMediator{
  private ArrayList<IComponent> components = new ArrayList<IComponent>();
  
  @Override
  public void addComponent(IComponent _component) {
    components.add(_component);
  }
  @Override
  public void send(Intent _message, IComponent _sender) {
    for(IComponent component : components){
      if(!component.equals(_sender)){
        component.receive(_message);
      }
    }
  }
}

In the next code preview you can see Component interface that will be implemented in Component classes.
package com.testmediator;
public interface IComponent {
  public void receive(Intent _message);
  public void send(Intent _message, IComponent _sender);
  public IMediator getMediator();
}

As you can see in the Component implementation, each Component contains the reference to the same Mediator that is set up in the constructor. Other important methods are send and receive which implements sending message via Mediator instance and receiving message from Mediator broadcast, respectively. On the click of the send button message will be send to another component depending of selected recipient from the combo box.
package com.testmediator;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class ComponentOne extends WindowAdapter implements IComponent, ActionListener{
  private IMediator m_mediator = null;
  private JPanel m_panel = null;
  private JComboBox<String> m_tabSelect = null;
  private JLabel m_label = null;
  private JTextField m_text = null;
  private JButton m_button = null;
  private JLabel m_receivedMsg = null;
  private Intent m_message = null;
  
  public ComponentOne(IMediator mediator){
    m_mediator = mediator;
    initGui();
  }
  
  @Override
  public void receive(Intent _message) {
    m_message = _message;
    if(m_message.getStringMsg("ToTab01")!=""){
      m_receivedMsg.setText(m_receivedMsg.getText() + " - " + m_message.getStringMsg("ToTab01"));
    }
    m_panel.repaint();
  }
  @Override
  public void send(Intent _message, IComponent _sender) {
    m_mediator.send(_message, this);
  }
  @Override
  public IMediator getMediator() {
    return m_mediator;
  }
  
  private void initGui(){
    m_panel = new JPanel();
    
    m_tabSelect = new JComboBox<String>();
    m_tabSelect.addItem("tab02");
    m_tabSelect.addItem("tab03");
    m_label = new JLabel("Tab01, enter the message: ");
    m_text = new JTextField(20);
    m_button = new JButton("Send");
    m_button.addActionListener(this);
    m_receivedMsg = new JLabel("Received: ");
    
    m_panel.add(m_tabSelect);
    m_panel.add(m_label);
    m_panel.add(m_text);
    m_panel.add(m_button);
    m_panel.add(m_receivedMsg);
  }
  
  public JPanel getPanel(){
    return m_panel;
  }
  
  public Intent getMessage(){
    return m_message;
  }
  @Override
  public void actionPerformed(ActionEvent _event) {
    Object source = _event.getSource();
    if(source.equals(m_button)){
      Intent intent = new Intent();
      if(m_tabSelect.getSelectedItem() == "tab02"){
        intent.putStringMsg("ToTab02", m_text.getText());
      }else if(m_tabSelect.getSelectedItem() == "tab03"){
        intent.putStringMsg("ToTab03", m_text.getText());
      }
      send(intent,this);
    }
  }
}

Simple Intent class represents wrapper for all messages. As you can see for now it contains only methods for putting string message and reading the same message. This class can be extended to wrap all other kinds of objects.
package com.testmediator;
public class Intent {
  String m_stringMsgKey;
  String m_stringMsg = "";
  public void putStringMsg(String _key, String _value){
    m_stringMsgKey = _key;
    m_stringMsg = _value;
  }
  
  public String getStringMsg(String _messageKey){
    if(_messageKey == m_stringMsgKey){
      return m_stringMsg;
    }
    else{
      return "";
    }
  }
}

Other classes from project are excluded from code preview since primary role of this blog was to present Mediator pattern. In a context of the project it is basically a simple desktop app developed using swing library.


Conclusion


Mediator pattern is pretty common to meet in a different solutions. For instance, Android platform is using very similar principle regarding communication between Activities using Intent objects as messages that will be broadcasted to all Activity instances in the app. This way complex peer-to-peer communication is replaced by the Mediator who is in charge of distributing messages, providing loose coupling between components which is in the almost all cases very good practice.

Monday, September 24, 2012

Installing Windows Phone SDK on Windows 8 RC1

 

In this blog I’ll tell you about little issue that occurred to me during installation of Windows Phone SDK on Windows 8 RC1. Since it could happen to anyone running Win8 RC I thought it would be a good idea to share this tip.

Since I have already had installed Visual Studio on my PC, I went to Windows Phone Dev Center and downloaded the last version of Windows Phone SDK 7.1.1. After that, I started the installation but than the error message occurred: “KB2669191 does not apply, or is blocked by another condition on your computer”.

What is causing the error?

During installation, XNA Game Studio tries to install a version of the Games for Windows - LIVE Redistributable. The system reacts with the previously mentioned error since the install process wants to replace a file with an older version. So, the main reason of this compatibility issue is that the Win8 comes with the newer version of Games for Windows.

Solution

If you preinstall the the new version of Games for Windows before WP SDK, install process will recognize his presence and use the new version instead the old one. So, basic workaround is this:

1. Install the new version of Games for Windows from the XBOX site

2. Download and install WP SDK 7.1.1

3. Download and install WP SDK 7.1.1 Update (recommended)

After you did these steps you are ready to go.

Launch your Visual Studio and in File->New->Project you should see the next screen:

WP7 projects

Thursday, June 21, 2012

Create your resource’s icons for Android app with ease

 

Introduction

Android Asset Studio is a part of android-ui-utils project and in essence it is a web site that provides you online tool for generating necessary icons for buttons or menus. This service allows you to automatically and rapidly generate required icons in all sizes you need, and by that you can save a lot of time.

About

If you visit Android Asset Studio web site you will notice two parts. Icon generators contains several categories that allow you to generate icons for particular purpose.

ScreenShot01






Using foreground option you can upload image, use default clipart icons or use text as icon foreground.
Also, you can adjust padding by using percentage scroll to determine width of image margins.
Besides, you can also adjust background shape and color.

After you adjusted your icon look, you can download single image in desired dpi or you can download .zip file that will contain “res” folder with photos of all image sizes.

The second part contains nice online tool called Device frame generators for wrapping your previously taken screenshots of mobile screen. You can use it if you just need to create a couple of screen images to assemble screen flow for your mobile app usage scenario. In this case you will be provided better context for your frames which can be pretty handy. It also allows you to use correct screen resolutions for particular devices. Only requirement is that your image is in exact resolution as it is specified for particular device.

ScreenShot03

 

 

  • Drag&drop image to area for wanted mobile device. Notice that you will need to use image that has exactly the same size as a mobile device’s screen size.
ScreenShot04

 

 

  • After image is loaded you can export it back to your desktop by using drag&drop.

Saturday, February 11, 2012

Link Android application with eBay web service



Introduction

 

In this tutorial I'll demonstrate a way of linking your hybrid Android applications (Android native + HTML) with eBay web services.

You can download file project source from here.
(Notice that you will need to insert AppID in url string at RestClient.java. Procedure is described in Sign up - ebay Developer Network section and Web service client section.)

We'll create simple Android app with service client for searching eBay items by a keyword. After search is completed, application will list a correct number of items with their hyperlinks to details and images.
For developing applications with eBay integration, Ebay Developer Network gives a good insight in some of the products for developers. From current featured products there are 4 categories:
1. Search - offers eBay finding API that enables application to search for eBay items.
2. Trading - offers API for authenticated access to private eBay data
3. Buying - offers eBay shopping API access to public read-only data
4. Go Local - offers Milo Open API that allows developers to access local availability information from 50,000+ stores all across the country

These APIs give you a powerfull tools for developing e-commerce apps using integration with eBay web services.

The same as in previous tutorial we'll develope hybrid Android application that is using native Java code for backend logic and HTML with jQuery for UI.

 

Screen flow


In this sample, our application will contain two HTML pages. The first page will be search interface that has search keyword input and number input that represents a number of searched result items that will be displayed in second screen. The second screen will display search results with item titles with hyperlinks and their images.
First page - (index.html) Search page
Second page - (searchitems.html) Search results
 

Sign up - ebay Developer Network

 

In case with developing application that will use eBay services, you'll need to have some application parameters that we'll be provided to you after you sing up on developer.ebay.com web site. In order to do that:
1. go on previous URL and click Join now section.
2. Fill in required data and register.
3. After you confirm your account, go back to web site and sign in.
4. Go to My Account
5. At application keys pane click Generate Keys


6. After you generate your keys you should get list of ids that will be used in your app configuration.

Setting up Android project

 

Android Manifest

Create new Android project in Eclipse environment - File -> New -> Android project, and choose target platform (in my case I used Android 2.1-update1).
1. After you created project enter AndroidManifest.xml and go to Permissions section.
2. Click Add... and choose Uses Permission
3. From Name option set choose android.permission.INTERNET
4. Save your changes

Layout XML

In project solution go to res folder and in layouts open main.xml. Go to main.xml section and replace your xml layout with next:

<!--?xml version="1.0" encoding="utf-8"?-->
<linearlayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<webview android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/webview">
</webview>
</linearlayout>



In this step we added webView component which will be used to display HTML pages and execute JavaScript.

Assets folder

The same as in previous tutorial we'll use jQMobi library for jQuery development. Follow next steps to set up necessary resources for UI development:
1. Create directories in assets folder with following paths - assets/www/css-js and assets/www/img
2. Download jQMobi and extract js libraries in assets/www/css-js/
3. Store some PNG in img folder that we'll be used in search screen
4. Create two empty HTML files in www directory and name them as index.html and searchitems.html
Now your assets folder should look like this





Web service client


 

To establish link to eBay web service we'll need to write a client side class that is going to access eBay Finding service. In this case, we'll use REST-full eBay service and since these services are based on HTTP methods, we'll implement HTTP client to send HTTP requests to eBay service. In response, web service will send JSON object with items data as a search result.
Remark: You're not limited on using REST-full services, their is also a way of using SOAP based eBay web services. In that case you'll need to use kSOAP2 project. SOAP services won't be covered in this tutorial.


First step is to create new class in your package called RestClient. Then enter this code in your class:


 import java.io.IOException;  
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;

public class RestClient {

public static String getEbayItems(String term, String number){

String json = null;

String url = "http://svcs.ebay.com/services/search/FindingService/v1?OPERATION-"+
"NAME=findItemsByKeywords"+
"&SERVICE-VERSION=1.0.0"+
"&SECURITY-APPNAME=000000000-0000-0000-0000-00000000000"+
"&RESPONSE-DATA-FORMAT=JSON"+
"&REST-PAYLOAD"+
"&keywords="+term+
"&paginationInput.entriesPerPage="+Integer.parseInt(number);

HttpClient httpClient = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(url);
ResponseHandler<String> responseHandler = new BasicResponseHandler();
String response;
try {
response = httpClient.execute(httpGet,responseHandler);
json = response.toString();
}catch (ClientProtocolException e) {
e.printStackTrace();
}catch (IOException e) {
e.printStackTrace();
}
return json;
}
}

 

As we can see, this class contains single method getEbayItems that will retrieve search results. Notice in url string HTTP POST arguments. These arguments represents our web service call parameters.
- In SECURITY-APPNAME you will enter your generated AppID key from Production keys section under your account at developer.ebay.com.
- RESPONSE-DATA-FORMAT represents data type that web service will return in response (JSON or XML).
- keywords is a search term.
- and paginationInput.entriesPerPage represents item number in search result.
If you set your parameters correctly, you will be able to see your JSON result when you enter this url in your web browser. In continue, we'll create simple HTTP client that will send HTTP GET request to eBay web service. In response it returns JSON result.

 

Main Activity class


In source of project, we'll edit Activity class that was generate when project was created. Modify your code:

import java.util.ArrayList; 
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.view.KeyEvent;
import android.webkit.WebView;

public class MainActivity extends Activity {
WebView webView;
String json;
String callback;

//Searched item data
ArrayList<String> titles = new ArrayList<String>();
ArrayList<String> imageUrl = new ArrayList<String>();
ArrayList<String> viewItemUrl = new ArrayList<String>();

private Handler handler;
private static final String HTML_ROOT = "file:///android_asset/www/";

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
webView = (WebView)findViewById(R.id.webview);
webView.getSettings().setJavaScriptEnabled(true);
webView.addJavascriptInterface(this, "jsInterface");
handler = new Handler();
loadPage("index.html");
}

public void loadPage(String page){
final String url = HTML_ROOT + page;
loadURL(url);
}

private void loadURL(final String url){
handler.post(new Runnable(){
public void run(){
webView.loadUrl(url);
}
});
}

public void callSearchService(String term, String number, String callback){
try {
json = RestClient.getEbayItems(term,number);
this.callback = callback;
//Parsing JSON result
JSONObject jObjectMain = new JSONObject(json);
JSONArray jArrayMain = jObjectMain.getJSONArray("findItemsByKeywordsResponse");
JSONObject jObjectResult = jArrayMain.getJSONObject(0);
JSONArray jArrayResult = jObjectResult.getJSONArray("searchResult");
JSONObject jObjectSearch = jArrayResult.getJSONObject(0);
JSONArray jArraySearch = jObjectSearch.getJSONArray("item");

JSONObject jObjectItems = new JSONObject();
titles = new ArrayList<String>();
imageUrl = new ArrayList<String>();
viewItemUrl = new ArrayList<String>();
for(int i=0; i<jarraysearch.length(); i++){
jObjectItems = jArraySearch.getJSONObject(i);
titles.add(jObjectItems.getString("title").replaceAll("[\"]|[\\[]|[\\]]", ""));
imageUrl.add(jObjectItems.getString("galleryURL").replaceAll("[\"]|[\\[]|[\\]]", ""));
viewItemUrl.add(jObjectItems.getString("viewItemURL").replaceAll("[\"]|[\\[]|[\\]]", ""));
}
loadPage("searchitems.html");
} catch (JSONException e) {
e.printStackTrace();
}
}

public void getSearchedItems(){
String innerHtml = "";
for(int i=0; i<titles.size(); i++){
innerHtml += "<div class="resultItem">" +
"<a href=""+viewItemUrl.get(i)+"">"+titles.get(i)+"</a>" +
"<img src=""+imageUrl.get(i)+"">" +
"</div>";
}
final String callbackMethod = "javascript:"+callback+"(\""+innerHtml+"\")";
loadURL(callbackMethod);
}

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

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

1. onCreate method - This method is called at creating activity state. In this part, we'll set our layout that was previously edited (main.xml) and in WebView component will enable JavaScript execution and register JavaScript interface. Using this interface we'll be able to call JavaScript from our Java code and vice versa (see previous tutorial). In the end of this method we'll load our first page (index.html).
2. loadPage method is used to load page in WebView component using page URL and loadURL is used for running HTML page and jQUery in WebView.
3. callSearchService method - this method gets three arguments: term (search keyword), number (item number in search result) and callback (name of JavaScript method to be called back). All of these arguments represent input data that will be forwarded from HTML page to Java by JavaScript method that will make callSearchService method call using jsInterface. In the first part, method gets search results by calling getEbaysItems from RestClient class. After that we parse our JSON result.
Basically, it re-encapsulates JSON arrays in result to get to item data. After we get our specific JSON Array with items data, we'll read their titles, image urls and url to details page. Don't get confused by replaceAll("[\"]|[\\[]|[\\]]", "") method. It is using Regex to remove redundant JSON characters - [" and "].
After we store JSON parsed results in class attributes, we load second page (searchitems.html) that is going to display search results.
4. getSearchedItems method - will send inner HTML with JSON prased results as an argument in callback JavaScript method in searchitems.html page.
5. onKeyDown method - overrides button "Back" functionality to go to previous HTML page.
 

HTML pages


Replace your index.html with following HTML:

<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<script src="css-js/ui/jq.ui.js"></script>
<script src="css-js/jq.mobi.js"></script>
<script>
function sendSearchTerm(){
var inputString = $("#term").val();
var dropdown = document.getElementById("itemNum");
var index = dropdown.selectedIndex;
var inputNumber = dropdown.options[index].value;

if(inputString == "")
{
alert("Please enter search term.");
}
else
{
jsInterface.callSearchService(inputString, inputNumber, "getResult");
}
}
</script>
<style>
.info{
display: block;
line-height: 22px;
padding: 0 5px 5px 0;
color: #36558e;
}
#finding{
height: 152px;
padding: 80px 0 0 30px;
background: url('img/search.png') transparent no-repeat 0 0;
margin: 30px auto;
}
</style>
</head>
<body>
<div id="search">
<div id="finding">
<label for="input" class="info">Search
<strong style="color:red">e</strong>
<strong style="color:blue">b</strong>
<strong style="color:#ffcc00">a</strong>
<strong style="color:green">y</strong>
</label>
<input type="text" id="term" name="term">
number of items:
<select id="itemNum">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
<option value="6">6</option>
<option value="7">7</option>
<option value="8">8</option>
<option value="9">9</option>
<option value="10">10</option>
</select>
<button onclick="sendSearchTerm()">Search</button>
</div>
</div>
</body>
</html>

This HTML contains two input elements for input search term and select list for number of search items. JScript function sendSearchTerm reads values from input fields and sends that to Java callSearchService method.

Second page will display search results:


<!DOCTYPE html>  
<html>
<head>
<meta charset="ISO-8859-1">
<script src="css-js/ui/jq.ui.js"></script>
<script src="css-js/jq.mobi.js"></script>
<script>
$(document).ready(function () {
jsInterface.getSearchedItems();
});
function getResult(innerHtml){
$("#result").html(innerHtml);
}
</script>
<style type="text/css">
.resultItem{
border: 1px solid #60672B;
}
</style>
</head>
<body>
<div>
<label>Searched items:</label>
<div id="result">
</div>
</div>
</body>
</html>

At a page load, $(document).ready function is called and Java getSearchedItems method gets executed. From this execution getResult function is called in callback and it will load results as innerHtml to "result" div element.

 


Conclusion



Voila! You just created Android hybrid application with connection to eBay service.
Through this tutorial I showed how to work with Android hybrid application using HTML and jQuery and how to expand Android functionality using web service clients. The purpose of this tutorial was to give some insights of working with web service clients and make your mobile apps a little more advanced.

Sunday, January 29, 2012

Development of Android application using native Android, jQ.Mobi and HTML



Introduction


In this tutorial we'll develope a simple Andorid application using combination of native Android development, jQ.Mobi framework and HTML. Application sample can be downloaded from this link.

The main point of this tutorial is too use adventages of HTML and JavaScript for UI design, and native Android development and Java language for business logic development. For UI development, we'll use jQ.Mobi framework and HTML. JQ.Mobi is an HTML5 optimized rewriting JQuery JavaScript library, which offers way much faster execution than some other JS frameworks (JQuery Mobile, Zepto...). It is compatible for Andorid and iPhone platforms.

The basic concept of this sample lies in integration of HTML/JavaScript based UI with Android Java backend. Andorid provides a generic way of exposiong Android Java objects in JavaScript code through interface that is registered using WebView class. This interface provide us a set of abilities:

1. accessing Java methods from JavaScript
2. accessing HTML/JavaScript from Java code
3. parameter data types in method calls between Java-JavaScript

Screen flow


This very simple aplication will contain two HTML pages. First page will be used for saving fruit data in Andorid SQLite database and the second page will show all fruits from database table.

First page (index.html) - Add new fruit
Second page (viewall.html) - View all added fruits

Database access


First, create a new Andorid project in Eclipse. After that, create a new package where we'll add some classes for database access. Create a new class named DataSQLHelper that will extend SQLiteOpenHelper class.

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.provider.BaseColumns;
import android.util.Log;

public class DataSQLHelper extends SQLiteOpenHelper {
 
 public static final String DB_NAME = "fruitapp.db";
 public static final int DB_VERSION = 1;
 public static final String TABLE_FRUIT = "fruit";
 //columns
 public static final String FRUIT_NAME = "fruit_name";
 public static final String FRUIT_NUMBER = "fruit_number";
  
 public DataSQLHelper(Context context) {
  super(context, DB_NAME, null, DB_VERSION);
 }

 @Override
 public void onCreate(SQLiteDatabase db) {
  String sql = "CREATE TABLE " + TABLE_FRUIT +" ( " 
  +BaseColumns._ID+" integer primary key autoincrement, "+
  FRUIT_NAME+" text, "+
  FRUIT_NUMBER+" int)";
  Log.d("FruitData","onCreate: "+sql);
  db.execSQL(sql);
 }

 @Override
 public void onUpgrade(SQLiteDatabase arg0, int arg1, int arg2) {
  // TODO Auto-generated method stub

 }
}

After creating first instance of this class, SQLite will create new database called "fruitapp.db". Method onCreate(SQLiteDatabase db) will add table "fruit" to previosly created database.

FruitEntity class is used as a representation of database table.

public class FruitEntity {
 private long id;
 private String name;
 private int number;
 
 public long getId() {
  return id;
 }
 public void setId(long id) {
  this.id = id;
 }
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
 public int getNumber() {
  return number;
 }
 public void setNumber(int number) {
  this.number = number;
 }
}

Another class called DBRepository contains methods for inserting fruit data in "fruit" database table - insertFruit(String dbtable, Context context, FruitEntity fruit). It also contains method getFruits(String dbtable, Context context) which returns JSON String representation with all records from "fruit" table. For purpose of parsing JSON objects in this sample was used Jackson JSON processor.


import java.io.StringWriter;
import java.util.ArrayList;
import org.codehaus.jackson.map.ObjectMapper;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;

import org.fruit.db.FruitEntity;

import org.fruit.db.DataSQLHelper;

public class DBRepository{
 
 DataSQLHelper sqlHelper;
 
 public DBRepository(Context context){
  this.sqlHelper = new DataSQLHelper(context);
 }
 
 //returns Cursor for reading reocrds from database table
 public Cursor getCursor(String dbtable, Context context){
  SQLiteDatabase db = sqlHelper.getReadableDatabase();
  Cursor cursor = db.query(dbtable,null,null,null,null,null, null);

  return cursor;
 }
 
 public String getFruits(String dbtable, Context context){
  Cursor cursor = getCursor(dbtable, context);
  StringWriter ret = new StringWriter();
  ArrayList fruits = new ArrayList();
  while(cursor.moveToNext()){
   FruitEntity t = new FruitEntity();
   t.setId(cursor.getLong(0));
   t.setName(cursor.getString(1));
   t.setNumber(cursor.getInt(2));
   fruits.add(t);
  }
  try{
   //using jackson mapper for generating JSON object
   ObjectMapper mapper = new ObjectMapper();
   mapper.writeValue(ret, fruits);
  }catch(Exception e){
   e.printStackTrace();
  }
  closeDB();
  return ret.toString();
 }
 
 public void insertFruit(String dbtable, Context context, FruitEntity fruit){
  SQLiteDatabase db = sqlHelper.getWritableDatabase();
  ContentValues values = new ContentValues();
  values.put(DataSQLHelper.FRUIT_NAME, fruit.getName());
  values.put(DataSQLHelper.FRUIT_NUMBER, fruit.getNumber());
  db.insert(DataSQLHelper.TABLE_FRUIT, null, values);
  
  closeDB();
 }
 
 public void closeDB(){
  sqlHelper.close();
 }
}


Main Activity class


After creating new Project in Eclipse, go to your main Activity class and add this code:
import org.fruit.db.DBRepository;
import org.fruit.db.DataSQLHelper;
import org.fruit.db.FruitEntity;

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

public class FruitAppActivity extends Activity {
 WebView webView;
 DBRepository dbRepository;
 private Handler handler = null;
 private static final String HTML_ROOT = "file:///android_asset/www/"; 
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);
        webView = new WebView(this);
       
        setContentView(webView);
        webView.getSettings().setJavaScriptEnabled(true);    
        dbRepository = new DBRepository(this);
        
        handler = new Handler();  //creates handler instance for page loading 
        webView.addJavascriptInterface(this, "fruitInterface");        
        loadPage("index.html");
    }
 
 public void loadPage(String in){
     final String url = HTML_ROOT + in;
     loadURL(url);
    }
    
 //Loads pages and executes JavaScript. 
    private void loadURL(final String in){
     handler.post(new Runnable() {
            public void run() {
             webView.loadUrl(in);
            }
        });
    }
}

In onCreate method we create new WebView component that will be used for HTML preview and JavaScript execution. We'll also need to enable JavaScript for WebView component. In the next step, we'll create an instance of BDRepository class. Creating this instance, it will be created fruitapp.db database with "fruit" table. After that, we'll register "fruitInterface" for current context. This JavaScript interface represents the interface that will be used for calling Java methods from JavaScript, and vice versa. In the end, we'll load index page.

Add additonal methods to main Activity class:

 public void addNewFruit(String fruit_name, String fruit_num){
  FruitEntity fruit = new FruitEntity();
  fruit.setName(fruit_name);
  fruit.setNumber(Integer.parseInt(fruit_num));
  
  dbRepository.insertFruit(DataSQLHelper.TABLE_FRUIT, this, fruit);
 }
 
 public void sendResultToJavaScript(String callback){
  String result = dbRepository.getFruits(DataSQLHelper.TABLE_FRUIT,this);
  final String callbackFunction = "javascript:" + callback + "('" + result + "')";
  loadURL(callbackFunction); 
 }
 
 @Override
 public boolean onKeyDown(int keyCode, KeyEvent event){
  if((keyCode == KeyEvent.KEYCODE_BACK) && webView.canGoBack()){
   webView.goBack();
   return true;
  }
  return super.onKeyDown(keyCode, event);
 }

Method addNewFruit is used to insert data from HTML form into database table. On the other hand, method sendResultToJavaScript is used to read all the records from "fruit" table in form of JSON representation and send JSON string to HTML by sending it like argument of javascript function. Both of these methods will be called from JavaScript using JavaScript interface.

Override method onKeyDown to define event on click of back button. In our case, default behavior is to go to previuos page.

Adding HTML pages and JavaScript


In assets create folders www and css-js:

In folder css-js add exported files from downloaded jQ.Mobi archive.

In folder www create new "index.html" page. In this case, it was used HTML 5, but you can use any version of HTML.


 
 
 
 

 
 

In "head" tag we add css and jQ.Mobi libraries. After that, create simple form with basic input fields and buttons. In the end, add JavaScript functions.

  • saveFruit function reads values from input fields and use it as arguments in Java method addNewFruit call. Notice that for Java method calls, we use interface that we added before in our Activity class.
  • goToAllRecordsPage function redirects to next page.
  • clearFields function clears values from input fields.

In folder www create another HTML page called "viewall.html".

 
 
 
 

 
 

Again, in the "head" tag we add css and jQ.Mobi libraries. In body part, add an unordered list element that will be used to display fruit data.

After page loads, Java sendResultToJavaScript method will be called. As argument of this method we use name of JavaScript method that we'll be invoked. JavaScript function getRecords we'll parse JSON result set and add records data to list items.