Berichten met label mobility
GraniteDS and AIR for mobile
Geplaatst door Walter Treur in Flex / AIR, iPhone/ iPad, java, mobility, technical op 5 september 2011
In this article I will briefly show how to resolve some obstacles I came across when I developed my first application with AIR for mobile and GraniteDS. The most noteworthy reason of using AIR to create mobile applications is of course the multi-platform deployment using a single codebase. Furthermore, with Granite you are able to disclose the services of an existing Java backend to a mobile platform without significant changes to the backend. This offers great potential for enterprises who are struggling with the fragmented mobile market and don’t want to completely rewrite their existing Java backend.
I will assume you have some familiarity with AIR for mobile and Granite. It’s mostly the same as for Flex but there are some things you have to take into account.
1. Get the right version of Granite
The latest version of Granite is 2.2.1 GA. However, in the most recent version of AIR and Flex Adobe made some changes in the API which breaks backwards compatibility for some features of Granite. Therefore this release of Granite won’t work using the newest SDK. Refer to this post on the Granite form for more info on how to make these changes yourself. If you don’t want be bothered with building Granite yourself just download this version of GraniteDS to get started immediately.
2. Connecting to the right server
A problem for AIR applications in general (both desktop and mobile) is setting the right server settings. It is quite simple when running within the browser: The server address is changed with a single reconfiguration of the swf-file and all clients are using the new address on a browser refresh. With AIR it is a bit different and you’re not always at liberty to ‘hardcode’ the service settings in the AIR distribution package.
Granite offers a method for dynamic server configuration using the server initializer component:
Tide.getInstance().addComponentWithFactory( "serviceInitializer", DefaultServiceInitializer, { contextRoot: '/my-app', serverName: “10.0.0.1”, serverPort: “8080” });
Note that once a connection is made, it is not possible to reconnect with another configuration, because the service initializer is only used once. You have to restart the application to enable the new connection settings or reset Tide’s RemoteObject. Unfortunately Tide’s API doesn’t support this reset. I came up with a small workaround which requires you to extend the EJB class with an extra reset method with the following body:
public class Ejb extends org.granite.tide.ejb.Ejb { /** * Reset the Tide Connection to allow new server settings */ public function resetConnection():void { if (_ro) { _ro.disconnect(); } _ro = null; } }
This method resets Tide’s RemoteObject so the next remote call will force a reinitialization using the current settings of serviceInitializer. Refer to Granite’s issue tracker or forum thread for more details.
3. Automatic logout
Applications running on mobile platforms are always susceptible to unpredictable interruptions. For example when a phone call or text is received. Mobile AIR applications provide a deactivate event which is dispatched when the application is halted somehow. The application I wrote was using Tide’s Identity class for user login. Therefore I added an event handler to automatically logout the user and push the LoginView on top of the navigator stack:
private function deactivateHandler(event:Event):void { if (identity.loggedIn) { identity.logout(); } navigator.popAll(); // Purge the navigator history to disable back button usage navigator.pushView(LoginView); }
4. Build, build, build!
This isn’t directly related to Granite or AIR for mobile. But since they can both be used for enterprise scale applications I thought I’d mention it shortly: Make sure you have a proper build script. Now, I’ve got an example from Chris Black which provides a good starting point. I’ve only added the metadata compiler options required for Tide and of course a reference to the Granite libraries and generated Actionscript classes.
<mxmlc ... > <!-- .... --> <!-- location of generated as classes with gas3 --> <source-path path-element="${gen.src.dir}" /> <compiler.library-path dir="${basedir}/libs" append="true"> <include name="granite-essentials.swc" /> <include name="granite.swc" /> </compiler.library-path> <keep-as3-metadata name="Bindable" /> <keep-as3-metadata name="ChangeEvent" /> <keep-as3-metadata name="Destroy" /> <keep-as3-metadata name="Id" /> <keep-as3-metadata name="In" /> <keep-as3-metadata name="Inject" /> <keep-as3-metadata name="Managed" /> <keep-as3-metadata name="ManagedEvent" /> <keep-as3-metadata name="Name" /> <keep-as3-metadata name="NonCommittingChangeEvent" /> <keep-as3-metadata name="Observer" /> <keep-as3-metadata name="Out" /> <keep-as3-metadata name="PostConstruct" /> <keep-as3-metadata name="Transient" /> <keep-as3-metadata name="Version" /> </mxmlc>
One plus one
I can imagine one must be thinking: ‘Everyone could have figured that out!’ And I totally agree, because that’s exactly what this article is about. With some experience with Flex, a developer can write a mobile application on top of a Java EE backend. It doesn’t take much to utilize an existing backend from a mobile platform. Since the latest release of AIR the performance for iOS and Android is pretty good and together with the Granite Enterprise Platform the barrier to emerge an enterprise application to a mobile platform has become much lower.
PhoneGap, een alternatief voor native mobiele applicaties
Geplaatst door Erik Sanders in Uncategorized, android, mobility op 17 augustus 2010
PhoneGap, een alternatief voor native mobiele applicaties
PhoneGap is een interessante open source alternatief voor het schrijven van native applicaties voor elk (mobiel) platform dat er is. In het kort komt het erop neer dat PhoneGap zorgt dat je een HTML applicatie met javascript. De specifiek API, zoals location, contact, e.d. worden afgeschermd door een standaard API van PhoneGap.
iPhone
Voor de iPhone kan de HTML applicatie gewoon worden aangeboden via de appstore. Dit is dan ook direct de truc waardoor er voldoende rechten zijn om de hardware aan te spreken. Er zijn al vele applicatie geplaatst in de appstore (zie een selectie in www.phonegap.com/apps). Er is tevens een getting started en er zijn extra plugins beschikbaar
Ondersteunde platformen
Naast iPhone wordt zowel Android, Blackberry, Symbian, Palm, N900 en Windows Mobile. Ook Windows Mobile 7 is zodra dit uitkomt eenvoudig te ondersteunen en ze zullen ook geen blokkade opwerpen in het voordeel van silverlight. Interesante gedachte is natuurlijk ook de iets minder mobiele system met Linux, Windows MacOS hebben ook allemaal een browser.
| IPHONE | ANDROID | BLACKBERRY | SYMBIAN | PALM | |
| GEO LOCATION | √ | √ | √ | √ | √ |
| VIBRATION | √ | √ | √ | √ | √ |
| ACCELEROMETER | √ | √ | OS 4.7 | √ | √ |
| SOUND | √ | √ | √ | √ | √ |
| CONTACT SUPPORT | √ | √ | √ | √ | N/A |
Voor meer informatie zie www.phonegap.com
Building iPhone applications using MonoTouch, part 4: the UISearchDisplayController
Geplaatst door Richard de Zwart in .NET, mobility, technical op 3 november 2009
In my previous post I wrote about the Interface Builder and things like outlets. Last night (with the help of some colleagues) I cracked one of the more advanced Classes in the Interface Builder: the UISearchDisplayController.
In the previous version of my application I had a UITableView and a UISearchBar. I hooked them up with some code and it worked fine. But I didn’t get the effect that you see in (for instance) the iPod application. When you scroll up, uncover the search-bar and start typing, the original view is greyed-out. And when your search gives no result, you get a “No Results” message. Like this:
For that, you need the UISearchDisplayController. This controller does the work of hooking up a couple of UI-elements for you:
- The search bar
- The view with the results from the search (called the searchContentsController)
- The delegate that handles all the events that come from the search bar and the results view (called the searchResultsDelegate)
- The data source that provides the data to search in (called the searchResultsDataSource)
- Your original view
When you drag a UISearchDisplayController and drop it at the top of your UITableViewController, all the outlets get connected to your controller automatically. Apparently the Interface Builder thinks that your class can play all these roles. This makes sense when you program Objective-C, since that language is quite capable of inheriting from lots of base classes (as is so eloquently explained in the Cocao With Love blog), but asks some more attention when used from MonoTouch.
Designers should not write code, and vice versa
I will explain again what Interface Builder does for you. Maybe you already know, but I had to get used to it, and have to keep reminding myself that you use it to, well, build interfaces. Nothing else. Interface Builder provides a clean separation between the GUI and the code, and that’s a good thing, right? Right. I love Design Patterns, and I try to convince as much progammers as possible to take at least notice of them. But iPhone apps are mostly very small apps with one or two screens, being very good in just one or two things. Do I need to implement this whole pattern for my simple app? Well, apparently. And so will you, so let me try to help you find out how to do some of these things.
Steps to follow
Begin with a UITableViewController. Then go to the Library Window, the Objects button and drag-n-drop a UISearchDisplayController just at the top of your UITableViewController.
In the MainWindow you will have the UISearchDisplayController added. Click it there, and then go to the Outlets-tab in the Inspector Window. You will see that all the outlets will be connected to your UITableViewController, except for the searchBar-outlet since that is of course connected to the SearchBar.
When you run your app, you will have the Table-View and the SearchBar above it. When you tap the text-field you will see the desired gray-out and the “No Result” if you enter some text. So far so good.
Providing the view with data
Now we need to hook up some of our own code to the events that the UISearchDisplayController fires. Let’s start with some data in our own TableView to filter on.
As said in one of my first posts, data for a view is delivered by a DataSource. In this case a UITableViewDataSource. So add a class to your project that inherits from UITableViewDataSource. Something like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | public class LeesPlankjeDataSource : UITableViewDataSource { private string[] woordjes = new string[] {"aap", "noot", "mies"}; public LeesPlankjeDataSource() { } public LeesPlankjeDataSource(string filter) { woordjes = woordjes.Where(f => f.StartsWith(filter)).ToArray(); } public override UITableViewCell GetCell (UITableView tableView, MonoTouch.Foundation.NSIndexPath indexPath) { UITableViewCell cell = tableView.DequeueReusableCell("plankje"); if (cell == null) { cell = new UITableViewCell(UITableViewCellStyle.Default, "plankje"); } cell.TextLabel.Text = woordjes[indexPath.Row]; return cell; } public override int RowsInSection (UITableView tableview, int section) { return woordjes.Length; } } |
The complete code of this solution is at the bottom of this post.
The class has two constructors. The default constructor (at line 5) is called when initializing our own view, the constructor that takes a string (at line 9) will be called when filtering is started.
The GetCell() and RowsInSection() methods need to be implemented to make your data source work. The implementation is pretty straightforward. The GetCell() method will be called “RowsInSection” times. The call to DequeueReusableCell() is some trick to limit the amount of resources that your iPhone application will use. Just make sure you pass in some string that you reuse a few lines down.
To be able to set this datasource on the table-view we have to have some programmatic access to the view. Well, we did that before in the previous post. Go to Interface Builder, select the AppDelegate in the Library Window, add an outlet and connect it to your UITableViewController. Then you can have code like this in your main.cs:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | public partial class AppDelegate : UIApplicationDelegate { // This method is invoked when the application has loaded its UI and its ready to run public override bool FinishedLaunching (UIApplication app, NSDictionary options) { tableView.DataSource = new LeesPlankjeDataSource(); // If you have defined a view, add it here: window.AddSubview (tableView); window.MakeKeyAndVisible (); return true; } // This method is required in iPhoneOS 3.0 public override void OnActivated (UIApplication application) { } } |
We simply set the DataSource on the tableView to our own DataSource and then add the tableView to the current window. Run your app and you will have some data in your view!
Building the delegate
Now we need some code to handle the events of the search bar. The most interesting event is “ShouldReloadForSearchString()”.
Add a new class to your project that inherits from UISearchDisplayDelegate. The code should look something like this:
1 2 3 4 5 6 7 8 9 10 11 | [MonoTouch.Foundation.Register("LeesPlankjeDelegate")] public class LeesPlankjeDelegate : UISearchDisplayDelegate { public override bool ShouldReloadForSearchString (UISearchDisplayController controller, string forSearchString) { Console.WriteLine("In ShouldReloadForSearchString"); controller.SearchResultsDataSource = new LeesPlankjeDataSource(forSearchString); return true; //return base.ShouldReloadForSearchtring (controller, forSearchString); } } |
The first line is interesting. This is the magic that brings your classes into the Interface Builder. By registering the name of your class it will be added to the XIB (although not visible in the designer file). I’ll show you in a minute what you do with this in Interface Builder.
In the override of the ShouldReloadForSearchtring() I instantiate a new data source using the constructor that accepts a filter string. I set this on the SearchResultsDataSource property of the passed in controller object. As you can see in the code of the LeesPlankjeDataSource it will use a Lambda to filter the fixed array of words.
Hooking up the UISearchDisplayController with your Delegate
The Register-attribute on your delegate class makes it available in Interface Builder. So you go to the Library Window, choose the Objects button, then Controllers folder and then the general NSObject. Something like this: 
Drag it to the MainWindow, select it there, go to the Inspector, choose the Identity tab. Now change the class field to the name of your own class. LeesPlankjeDelegate in my case. Your class will not be listed, but that doesn’t matter. When you hit Enter, you’ll see in the MainWindow that both the class name and the instance name have changed. That is just fine.
Now the next magical thing: you have to connect the default delegate of the UISearchDisplayController to your Delegate class. Here is how: select the UISearchDisplayController in the MainWindow, go to the inspector, select the Outlets tab. The first outlet there is called “delegate” and is connected to your TableView. Now remove that connection by clicking the X. Then connect this delegate to your own Delegate class in the MainWindow.
Save in Interface Builder, go to MonoDevelop, run! Type something in the search and “Lo and behold!” it works!
Ain’t live sweet?
If it doesn’t work, feel free to leave a comment. I’ll see if I can help you.
P.S.
The last step is actually more complex than it should have been. If I make my UISearchDisplayController visible to my AppDelegate by adding an outlet, I can do with just one more line of code in my main.cs:
searchDisplayController.Delegate = new LeesPlankjeDelegate();
That way I go one-way: from Interface Builder to MonoTouch. But I thought it more interesting to go the other way too: from MonoTouch to Interface Builder.
LWUIT – een lichtgewicht ui toolkit voor Java ME
Geplaatst door admin in Uncategorized op 17 april 2009
Introductie
Ooit al eens een Java ME applicatie ontwikkeld voor een specifiek type mobiele telefoon? Wanneer het aankomt op het ontwikkelen van een gelikte interface loop je er al snel tegen aan dat de MIDP implementatie van de telefoon van invloed is op hoe de widgets van de applicatie getoond worden. Nadeel daarvan is dat de UI er op een ander type mobiel nogal anders uit kan zien. Om die reden was men voorheen nog wel eens geneigd om wat dieper in de code te duiken en de wat specifiekere (geliktere) widgets op de (javax.microedition.lcdui.)Canvas uit te werken. Deze Canvas ondersteunt sinds MIDP-2.0 een fullscreen modus: het is mogelijk om de complete applicatie direct op Canvas te ontwikkelen. Hiervan maakt LWUIT gebruik.
Mogelijk, maar wel bijzonder tijds-intensief, tenzij je gebruik maakt van het werk van anderen die al wat voorwerk hebben verricht op dit gebied. Een mooi voorbeeld hiervan is “LWUIT”, een door Sun ontwikkelde open-source UI toolkit. In tegenstelling tot het ontwerpen van UI’s met standaard Java ME is het met LWUIT mogelijk om op een Swing-achtige manier user interfaces te maken: layout managers, maar ook de pluggable look & feel, het MVC concept en “lightweight componenten” (componenten maken geen gebruik van de native UI controls, maar verzorgen zelf hun rendering en event handling) zijn terug te vinden.
Setup simpele MIDlet
Een MIDlet maken waarin met LWUIT een paar knoppen wordt getoond is simpel voor elkaar te krijgen via de volgende stappen:
Binnen NetBeans is het handig om de LWUIT jar toe te voegen als library via ‘Tools’, ‘Libraries en dan de ‘New Library…’ knop. Geef naam, type = ‘Class Libraries’, dan: ‘OK’ en ‘Add JAR/Folder…’: en selecteer het bestand “LWUIT.jar” dat te vinden is in de ‘lib’ dir van de LWUIT installatie (unzippen van de zip file). Het ‘LWUIT_stripped.jar’ bestand is de LWUIT library zonder code die gebruik maakt van JSR 184 (M3G: Mobile 3D Graphics), JSR 75 (PIM: Personal Information Management, FC: File Connection) of JSR 226 (SVG: Scalable 2D Vector Graphics).
Start vervolgens een nieuw project, kies als categorie ‘Java ME’ en als project ‘Mobile Application’ en druk op ‘Next’. Het is niet nodig om NetBeans een default MIDlet aan te laten maken; het vinkje bij ‘Create Hello MIDlet’ mag weg. Druk weer op ‘Next’. Selecteer de WTK die je hebt geïnstalleerd als ‘Emulator Platform’. LWUIT vereist minimaal MIDP-2.0 bovenop CLDC-1.1, dus i.p.v. MIDP-2.1 die default geselecteerd is zou je MIDP-2.0 kunnen kiezen, maar dit hoeft niet. Druk op ‘Finish’. Maak nu een nieuwe MIDlet aan met de naam ‘MyMIDlet’ en kopieer de volgende code er naartoe:
import com.sun.lwuit.*;
import com.sun.lwuit.events.ActionEvent;
import com.sun.lwuit.layouts.BoxLayout;
import javax.microedition.midlet.MIDlet;
public class MyMIDlet extends MIDlet {
Form form1;
public void startApp() {
Display.init(this);
form1 = new Form("LWUIT Demo Form");
form1.addCommand(new Command("Quit") {
public void actionPerformed(ActionEvent ae) {
destroyApp(true);
notifyDestroyed();
}
});
form1.setLayout(new BoxLayout(BoxLayout.Y_AXIS));
Button l = new Button("Left");
l.setAlignment(Label.LEFT);
Button r = new Button("Right");
r.setAlignment(Label.RIGHT);
Button m = new Button("Middle");
m.setAlignment(Label.CENTER);
form1.addComponent(l);
form1.addComponent(r);
form1.addComponent(m);
form1.show();
}
public void pauseApp() {
}
public void destroyApp(boolean unconditional) {
}
}
Omdat het project de LWUIT jar nog niet kent zal je een aantal foutmeldingen zien: via de project properties kan je onder de ‘Build’ categorie ‘Libraries & Resources’ kiezen. Voeg de LWUIT library die je eerder hebt aangemaakt toe. Omdat er slechts 1 MIDlet in het project zit zal deze MIDlet automatisch gestart worden wanneer je het project right-clickt en dan ‘Run’ selecteert. Het resultaat hiervan is een simpele LWUIT applicatie met een paar knopjes!
MVC
Een aardige illustratie van het MVC concept bij LWUIT is de List. Voeg het volgende stuk code in voor de ‘form1.show()’ uit het vorige voorbeeld.
String[] bands = new String[]{
"AC/DShe",
"Public Enema",
"Beverly Beerbellies",
"Shirley Temple Pilots",
"Wynona Riders"};
List list = new List(bands);
form1.addComponent(list);
.
Resultaat
Zelf de implementatie van ListModel en ListCellRenderer verzorgen heeft als extra voordeel dat je de reeds bestaande data types direct kan gebruiken en er geen sprake hoeft te zijn van “state copying”: er is geen voorbepaald data type wat in de List past.
Ook goed om te weten is dat de List z’n Model alleen maar vraagt naar de data-elementen die op het scherm zichtbaar zijn. Dit (performance) aspect wordt belangrijker naarmate de hoeveelheid data groeit of bijv. vanaf een remote locatie moet worden binnengehaald.
Conclusie
Via de bovenstaande stappen is het relatief makkelijk om snel een simpele LWUIT applicatie te maken. Met name voor de ontwikkelaars die hun app op meerdere typen mobiele telefoons willen draaien zal het een aangename verrassing zijn om te zien dat deze voorbeeld-applicatie op alle mobieltjes (die MIDP-2.0/CLDC-1.1 supporten) in uiterlijk en gedrag hetzelfde zal zijn. In een volgende blog zal ik wat verder ingaan op “fancier features” zoals Transitions en Theming; het oog wil immers ook wat!

