You are on page 1of 58

Building Native iPhone/iPad Applications In Java

Shai Almog & Chen Fishbein

Agenda
Who are we? Introducing Codename One Lets Build An Application Q&A

Couple Of Hackers
Shai Almog Chen Fishbein

Codename One allows Java developers to build true native apps for all mobile devices Its free & Open Source!

API

Designer Simulator

Plugin

Build Server Service Cloud

Features
GPS Maps Camera Video Social Analytics Storage Network Ads L10n Push E-Mail SMS XML JSON Contacts and
more...

Lets Start!

The Todo App

Get Codename One


Download Eclipse Or NetBeans Go to codenameone.com, click

download and setup your update center

New App Wizard


Start new

project in NetBeans or Eclipse

New App Wizard


Pick the
Codename One project type

New App Wizard

Standard project
directory name

New App Wizard


Package name
is really important!

We select the

leather theme & the tab application entries

Lets Look At The App


We have 3 source
les:

StateMachine StateMachineBase Main class

We have one
resource le

Main Class
Callback for
application lifecycle events operates the basics

Initializes and You normally dont


do much here

Statemachine Base
Auto generated by the GUI builder Never touch this class Contains resource le boilerplate code Subclass of UIBuilder

Statemachine
Subclass of
StateMachineBase code should reside invoke methods in StatemachineBase and UIBuilder

Here most of your Override and

Lets run the app & see what we have right now

Resource File
Data le containing
everything the app needs:
Screen designs Images Localization Data les Themes

Go To The GUI Builder Screen

Select The Form, set the title to: Todo

Delete the map container tab (its redundant)

Edit The Tab Titles


Set them to: Tasks, New Task &
Settings

Edit The First Tab


Delete the text
area and rename the container to tasksContainer

Set The Layout


tasksContainer

should use box layout Y

Layout Managers
Layout managers dene a ow for
components within a Container managers can be nested

Containers can be nested hence layout

Flow Layout
Positions components Allows alignment of
naturally automatic line breaks
!

components and similarly related features

Box Layout
Positions components in a
line or a column

Components occupy the full


height of the line or the full width of the column

Grid Layout
Positions the components in
equal size within a xed grid of rows/columns
!

Table Layout
Similar to HTML tables Variable width columns Complex component sizing/spanning

Lets Place a Sample Todo Item


Drag a multi button to the tasksContainer

Select the button & move to the properties tab

Edit the properties


Set line1 to: My task, line2 to: details
set emblem to: [null] & enable the checkbox ag

Add Icon
Select Images->
Quick Add Multi Images image

Select a 100x125 Choose the Very


High option

Multi Image
Multi Images deliver
the right image for every given DPI

Select The Icon In The Multi-Button

Select The Second Container

Update The Tab


Rename the
container: newTask

Remove the

content of the component group

Populate The Tab


Drag to the ComponentGroup 2 text elds & a
button. Drag another ComponentGroup to the to the newTask container & place a button within that

Edit Texts
Double click every entry, remove the
text from the text elds. Set the rst button text to Capture Photo and the second button text to Add Task

Set The Hint


Set the hint attributes of the text elds
to Title & Description respectively

Edit The Names


Name the components in the tree:
titleField, descriptionField, captureButton & addTaskButton.

Note: make sure to press save often!

Lets See What We Built

Press Simulator Button

Lets Start Coding


Select the GUI & select the events tab, select
capturePhoto in the tree & click ActionEvent

Back In The IDE


Add an import: Add a member: Edit the method:
import com.codename1.capture.Capture; private Image photo;

@Override protected void onMain_CaptureButtonAction(final Component c, ActionEvent event) { Capture.capturePhoto(new ActionListener() { public void actionPerformed(ActionEvent evt) { try { if(evt == null){ return; } String path = (String) evt.getSource(); photo = Image.createImage(path); ((Label)c).setIcon(photo.scaledWidth(Display.getInstance().getDisplayWidth() / 3)); c.getParent().getParent().animateLayout(400); } catch (Exception ex) { ex.printStackTrace(); }

});

Deep In

Exposes variable within the inner class event callback

@Override protected void onMain_CaptureButtonAction(final Component c, ActionEvent event) { Capture.capturePhoto(new ActionListener() { public void actionPerformed(ActionEvent evt) { Standard event callback try { when the photo is if(evt == null){ return; captured or dismissed } String path = (String) evt.getSource(); if(ImageIO.getImageIO() != null) { String photoName = "" + System.currentTimeMillis(); java.io.OutputStream os = Storage.getInstance().createOutputStream(photoName); ImageIO.getImageIO().save(FileSystemStorage.getInstance().openInputStream(path), os, ImageIO.FORMAT_JPEG, imageWidth, imageHeight, 0.9f); os.close(); Image img = Image.createImage(Storage.getInstance().createInputStream(photoName)); photo = photoName; ((Label)c).setIcon(img); c.getParent().getParent().animateLayout(400); } catch (Exception ex) { Log.e(ex); } After making changes that might

} }); }

affect the layout of the UI we need to reow the UI manually. This allows the UI to be more performant.

We scale on the lesystem to avoid loading a VERY large image which will crash a typical phone

Build The Tasks Tab


In the GUI builder click the before show
event button this will add an event that will be invoked before the form is shown:
@Override protected void beforeMain(Form f) { }

Populate The Todos


Add the following imports:
import import import import com.codename1.io.Log; com.codename1.io.Storage; java.util.Vector; java.util.Hashtable;

And the following members:


private Vector<Hashtable<String,String>> todos; private int imageWidth; private int imageHeight;

The Method
@Override protected void beforeMain(Form f) { imageWidth = icon.getWidth(); imageHeight = icon.getHeight(); Container tasksContainer = findTasksContainer(f); tasksContainer.removeAll(); if(todos == null) { todos = new Vector<Hashtable<String,String>>(); return; } for(Hashtable<String,String> entry : todos) { MultiButton mb = createEntry(entry); tasksContainer.addComponent(mb); } }

We fetch the resource le and extract the multiimage of the default icon so we can get the default icon size based on the design

Image icon = fetchResourceFile().getImage("shai_100x125.jpg");

Find methods are automatically generated into statemachine base when we save the resource le

todos = (Vector<Hashtable<String,String>>)Storage.getInstance().readObject("todos");

We load the todo data from application storage

There is no need to revalidate since the form wasnt shown yet. We create a multi button for every stored todo

Creating The Entry


private MultiButton createEntry(final Hashtable<String, String> entry) { final MultiButton mb = new MultiButton(); mb.setCheckBox(true); mb.setTextLine1((String)entry.get("title")); Loading from application storage mb.setTextLine2((String)entry.get("description")); not lesystem! String photo = (String)entry.get("photo"); if(photo != null) { try { mb.setIcon(Image.createImage(Storage.getInstance().createInputStream(photo))); } catch (IOException ex) { Log.e(ex); Print stack trace will be useless on the device but } codename one can send stacks by email from the phone } mb.setEmblem(null); mb.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { Adding/removing listeners Container parent = mb.getParent(); parent.removeComponent(mb); allows us to track events on parent.animateLayout(500); components and in the UI todos.remove(entry); Storage.getInstance().writeObject("todos", todos); } }); return mb; We instantly save the data to }

storage

Add A Task
Go back to the GUI builder and click
Action Event for the addTaskButton

And Now The Code


@Override protected void onMain_AddTaskButtonAction(Component c, ActionEvent event) { TextField title = findTitleField(c.getParent()); TextField description = findDescriptionField(c.getParent()); Hashtable<String, String> entry = new Hashtable<String, String>(); entry.put("title", title.getText()); entry.put("description", description.getText()); if(photo != null) { entry.put("photo", photo); } title.setText(""); description.setText(""); findCaptureButton(c.getParent()).setIcon(null); MultiButton mb = createEntry(entry); photo = null; todos.add(entry); Storage.getInstance().writeObject("todos", todos); findTabs1(c.getParent()).setSelectedIndex(0); Container tasksContainer = findTasksContainer(c.getParent()); tasksContainer.addComponent(mb); tasksContainer.animateLayout(500); }

Apple Certicate
You need a developer certicate from
Apple which requires that you pay them. There are instructions in our developer guide

Building For iOS


Right click and send the
iOS debug build (assuming proper certicate and provisioning prole) build server

Get the result from our

On Device Demo

Learn More
Codename One - codenameone.com Blog - codenameone.blogspot.com Source Code - code.google.com/p/
codenameone

Support Forum - codenameone.com/


discussion-forum.html

Q&A