Last week or so I have been working with the Leight Weight UI Toolkit for Java ME. We started with drawing everything by hand using Java ME LCDUI and Canvas class, but we feel that this is not viable in the long run. We want a toolkit that gives us a higher level API and handles differences between different devices.
Impressions so far are good. It was some work converting our application for Lcdui to Lwuit, but less than expected. Performance is OK, our main problem is network traffic, which has nothing to do with Lwuit, but the toolkit does not seem to slow it down, possible even speeding things up a little (since our old interface repainted the whole screen a bit too often). We haven't really used much of the visual goodies of the toolkit yet, and that is not our main reason for using lwuit, but surely we will use them eventually.
Lwuit is inspired by Swing. In my opinion they follow Swing a bit too close. I don't really see the need for Layout Managers on these very small devices. Our layout in our main screen is position based and needs a scrollable canvas, which lwuit gives us. So far we use the (undocumented) CoordinateLayout, which seems to work as expected, possibly we will have to implement our own, but since we don't want the LayoutManager to ever move the objects and set the X and Y coordinates ourselves, it shouldn't be too difficult.
Handy features, like drawing a text centered or making a dotted line, that exist in Lcdui are not available in Lwuit for compatibility with Swing. We used both these features in our interface, so we had to modify Lwuit so that we can use them, which was not difficult. We don't really see that compatibility with Swing is important, since the interface is designed for mobile devices with small screens and limited keyboards and possibly touch screen.
Thursday, October 16, 2008
Thursday, August 21, 2008
Error preverifying class - java/lang/NoClassDefFoundError: java/lang/Object
Is an error you might see when preverifying your midlet. Basically the problem is that the verifier can not find the referenced classes - and if it complains about java.lang.Object it basically can not find anything.
We had this today, and the reason was that our tool (IntelliJ) generated a not so good ant file, with the classpath for the jre. That is not what the preverifier expects. Rather it should be something like:
-classpath C:\WTK2.5.2\lib\cldcapi11.jar;C:\WC:\WTK2.5.2\lib\midpapi21.jar
We had this today, and the reason was that our tool (IntelliJ) generated a not so good ant file, with the classpath for the jre. That is not what the preverifier expects. Rather it should be something like:
-classpath C:\WTK2.5.2\lib\cldcapi11.jar;C:\WC:\WTK2.5.2\lib\midpapi21.jar
From applet to MIDlet
We have started to look into making a mobile client. Our current approach is to make a JME client, partly based on our existing Java client, based on Java SE and Swing and runnable as an applet or a standalone application. The rendering part will need to be rewritten but we hope to be able to reuse communication with the server and some of the internal logic.
Items we found so far:
Items we found so far:
- we use both socket and http communication. Both need to be rewritten to use the microedition Connector. So far the changes are small, but we will need to keep different classes for Java ME and SE versions
- we use gzip, in the SE version java.util.GZIPInputstream which is not included i Java ME
- enums is a big problem, looks like we will have to convert those used to old-fashioned int and classes with constant definitions.
- minor problems like String.split() (no such method in JME, and no StringTokenizer either) needs to be solved.
Thursday, July 31, 2008
Multiple applet instances problem solved (?)
We have had some problems with our applet getting instanciated several times. Seems like it is not only started twice but there are also several instances created by the browser. We have spend quite a lot of time on troubleshooting this and trying to find a solution, and now it seems like we have found a solution:
We changed the APPLET tag in our HTML page to a OBJECT tag. This has to be made specifically for Microsoft Internet Explorer, since it is not supported in other browsers like Firefox and Safari. So in our HTML file we check which browser the user has, and use the OBJECT tag if it is Internet Explorer, the APPLET tag otherwise, something like this:
It seems like this helps, but we do need more testing. Possibly we need to change to using the EMBED tag for other browsers but for now we stick to the APPLET tag.
There is a discussion on this in the Java developer forums here.
We changed the APPLET tag in our HTML page to a OBJECT tag. This has to be made specifically for Microsoft Internet Explorer, since it is not supported in other browsers like Firefox and Safari. So in our HTML file we check which browser the user has, and use the OBJECT tag if it is Internet Explorer, the APPLET tag otherwise, something like this:
var html = "<applet archive='MyJar.jar' code='MyApplet.class' height='700' width='1000'>";
if (navigator.appName == 'Microsoft Internet Explorer'){
// Use object tag for MS Internet Explorer
html = "<object classid='clsid:8AD9C840-044E-11D1-B3E9-00805F499D93'" +
" width='1000' height='700'>";
html += "<param name='code' value='MyApplet.class'/>";
html += "<param name='archive' value='MyJar.jar'/>";
}
It seems like this helps, but we do need more testing. Possibly we need to change to using the EMBED tag for other browsers but for now we stick to the APPLET tag.
There is a discussion on this in the Java developer forums here.
Thursday, July 03, 2008
Formatting java log records
While configuring logging levels for different parts of your software is flexible in java logging, formatting log records are not. In terms of what is delivered with the jre you have two alternatives:
Most important change (besides printing it all on one line in a more compact format) is that the Thread ID is included. The date is actually not very interesting for us, we just display part of the timestamp to give a rough idea of what takes time in the system.
This works very well, when we run our application standalone or in NetBeans applet viewer. But when we run the application as an applet it will not (for security reasons) load the log formatter class. Feels like the guys at Sun didn't think about logging from applets when the designed java logging. What we would need is a standard log formatter where you can configure the log format, without needing to load your own class. Perhaps we will get that in a later version....
- SimpleFormatter
- XMLFormatter
public class ThreadFormatter extends Formatter {
public String format(LogRecord record) {
return "Thread-" +
record.getThreadID() + " " +
record.getMillis() % 10000 + " [" +
record.getSourceClassName() + ":" +
record.getSourceMethodName() + "] " +
record.getMessage() + "\n";
}
}
Most important change (besides printing it all on one line in a more compact format) is that the Thread ID is included. The date is actually not very interesting for us, we just display part of the timestamp to give a rough idea of what takes time in the system.
This works very well, when we run our application standalone or in NetBeans applet viewer. But when we run the application as an applet it will not (for security reasons) load the log formatter class. Feels like the guys at Sun didn't think about logging from applets when the designed java logging. What we would need is a standard log formatter where you can configure the log format, without needing to load your own class. Perhaps we will get that in a later version....
Wednesday, July 02, 2008
Mac Java logging
Continued with the java logging work, specially on the mac. Found the following:
- logging to console is not possible, since java intercepts all console ouput and writes it to the logg... Creates a loop that fills th console. I have not found any way to turn this off, please drop me a line if you find one..
- logging to file with the standard XMLFormatter (the default if you dont change the configuration) produces (almost) an xml file.
- The 'XML' file has encoding "MacRoman" , which I have never heard of, but it seems like it is almost standard. Safari (Apple's own browser) does not know it, and complains 'Unsupported encoding MacRoman'. Firefox does not complain about the encoding however.
- The 'XML' file has a root tag of <log>. There is no closing tag, so it's an invalid xml. If you want to open the file in Firefox you have to add </log> by hand.
- If you print xml strings to your log (which we do) the XMLFormatter tries to escape them, but does not succeed, so you might have to remove them.
Friday, June 27, 2008
Java Applet logging
The last couple of days I have been working on logging from our applet. Frustrating indeed, but finally it works, almost as planned.
Our first approach was to do the configuration programatically, something like:
Now, this works very well in the Applet Viewer, but when you run your applet in a browser you'll get an exception, since the applet can not change the Handler configuration.
Well, there is the getAnonymusLogger() function, which is designed for use in applets. An anonymous logger would mean that we miss much of the benefits of the flexibel configuration, which is based on named loggers, but I guess it is better than nothing. But while using this method makes it possible to the the level on the Logger, you still can not configure the handler, so you will not get any logging output still.
So, we had to go for the configuration file. This is actually not so bad. You find the logging.properties file (it is under jre.lib) and configure your logging there. For console logging, you have to change the level of the ConsoleHandler (configured by default, but set to INFO level):
If you want logging to file, you can add the FileHandler instead:
And of course, you turn your logging on:
Now on my Windows PC this works both in applet viewer and in browser. But when I try the ConsoleHandler on my Mac, there is another gotcha, Bug ID 6585429 LoggerTraceListener causes infinite loop under some circumstances. On my mac the console simply loops and writes the same message over and over again. Seems like this is a known bug, and there should be a fix available, but for now we are stuck with logging to file on the Mac.
Our first approach was to do the configuration programatically, something like:
//get the root logger
Logger logger = Logger.getLogger("");
//create a ConsoleHandler
Handler handler = new ConsoleHandler();
handler.setLevel(Level.FINE);
logger.addHandler(handler);
logger.setLevel(Level.FINE);
Now, this works very well in the Applet Viewer, but when you run your applet in a browser you'll get an exception, since the applet can not change the Handler configuration.
Well, there is the getAnonymusLogger() function, which is designed for use in applets. An anonymous logger would mean that we miss much of the benefits of the flexibel configuration, which is based on named loggers, but I guess it is better than nothing. But while using this method makes it possible to the the level on the Logger, you still can not configure the handler, so you will not get any logging output still.
So, we had to go for the configuration file. This is actually not so bad. You find the logging.properties file (it is under jre.lib) and configure your logging there. For console logging, you have to change the level of the ConsoleHandler (configured by default, but set to INFO level):
java.util.logging.ConsoleHandler.level = FINE
If you want logging to file, you can add the FileHandler instead:
handlers= java.util.logging.FileHandler, java.util.logging.ConsoleHandler
And of course, you turn your logging on:
com.xx.package.level = FINE
Now on my Windows PC this works both in applet viewer and in browser. But when I try the ConsoleHandler on my Mac, there is another gotcha, Bug ID 6585429 LoggerTraceListener causes infinite loop under some circumstances. On my mac the console simply loops and writes the same message over and over again. Seems like this is a known bug, and there should be a fix available, but for now we are stuck with logging to file on the Mac.
Monday, June 23, 2008
Shopping List gadget updated
My shopping list gadget was one of my first, and is still my most popular. It was originally written as an inline gadget, and has been inline all the time, up till a few days ago. But lately I had complaints about problems with it. So this weekend a took a look. It seems like inline gadgets do not work as before anymore. Inline is actually not supported for new gadgets, so this is not a surprise. So I had to rewrite it and change the type. I also removed all the __MODULE_ID__, which are no longer needed, since it is rendered in an IFRAME.
Saturday, June 21, 2008
Web site revised
I have spent some hours on revising my private web site jubic.se. The new site is based on css positioning instead of the old one, based on html tables. Much esiser to maintain and hopefully a bit more modern look. Some changes to the content too, mainly on the main page, which is re-written. The site contains motsly material on my Google gadgets. I hope to have the time to add some more the following weeks, and possibly also some MySql material later.
Friday, June 13, 2008
Blogger problem solved!!
At last I manged to get my javascript code into blogger. The problem was with < and > which Blogger don't like. So i had to create small strings and use instead:
var lt = String.fromCharCode(60);
var gt = String.fromCharCode(62);
And now everything works as it should! Check it out at http://rockpopfavorites.blogspot.com/
It is behind the YouTube search at the right, which is actually a Google gadget (not yet published) where parameters are set dynamically.
var lt = String.fromCharCode(60);
var gt = String.fromCharCode(62);
And now everything works as it should! Check it out at http://rockpopfavorites.blogspot.com/
It is behind the YouTube search at the right, which is actually a Google gadget (not yet published) where parameters are set dynamically.
Blogger hates me.....
I have been trying most of the week to add some HTML and javascript code to a blog. It looks OK in the edit window but every time I save it, Blogger destroys my beautiful javascript code... It tries to format it, moves fragments of code around and destroys it completely. Escpecially special chars (including the not so special " and ' chars and whitespace!!!) seems almost impossible. I have spent several hours of my precious spare time on this.
Wednesday, June 04, 2008
Applet lifecycle
Lately I have been working with applets. This is new to me, since I have been mostly a server and web guy, with J2EE and servlets as my specialities, and some J2ME. And now I have run into a strange problem....
An applet's life cycle has four methods:
- init() when it is created
- start() when it is shown
- stop() when it is no longer shown
- destroy() for releasing resources
There is an old exception to this, that som browsers (Internet Explorer, possibly some other too) sometimes i9nvokes init() more than once. We had some problems with our applet which seemed to be caused by this. But when it made a fix for this, it did not help...
Some more investigation showed that actually Internet Explorer did not only invoke init() twice but also created two instances and invoked both init() and start() on both. This seems to happen the first time an applet is run, but possibly not the second. Very strange indeed....
An applet's life cycle has four methods:
- init() when it is created
- start() when it is shown
- stop() when it is no longer shown
- destroy() for releasing resources
There is an old exception to this, that som browsers (Internet Explorer, possibly some other too) sometimes i9nvokes init() more than once. We had some problems with our applet which seemed to be caused by this. But when it made a fix for this, it did not help...
Some more investigation showed that actually Internet Explorer did not only invoke init() twice but also created two instances and invoked both init() and start() on both. This seems to happen the first time an applet is run, but possibly not the second. Very strange indeed....
Tuesday, March 18, 2008
Create thumbnail in J2ME
The latest week I have been working on a J2ME project where we need to display thumbnails of piuctures from the mobile camera. I suppose this is a common scenario, but we had some unexpected problems..
The main reason for the problem is that mobile cameras today are very good. This means that images often will be very big, too big to display, but also to big to handle as an image in the J2ME environment. If you try Image.createImage() you will get an out-of-memory exception. This means that you can not create an Image even to create a thumbnail. In stead you have to create the thumbnail image straight from the stream, without creating a full-size image first.
There are different ways to do this, but since we work with a target platform that is quite new, and supports JSR-234 we chose to use this feature. A small utility function to do the resize could look something like this:
The main reason for the problem is that mobile cameras today are very good. This means that images often will be very big, too big to display, but also to big to handle as an image in the J2ME environment. If you try Image.createImage() you will get an out-of-memory exception. This means that you can not create an Image even to create a thumbnail. In stead you have to create the thumbnail image straight from the stream, without creating a full-size image first.
There are different ways to do this, but since we work with a target platform that is quite new, and supports JSR-234 we chose to use this feature. A small utility function to do the resize could look something like this:
public static Image resizeImage(InputStream src, int width, int height)
{
MediaProcessor mp;
try {
mp = GlobalManager.createMediaProcessor("image/jpeg");
mp.setInput(src, MediaProcessor.UNKNOWN);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
mp.setOutput(bos);
ImageTransformControl fc = (ImageTransformControl) mp
.getControl("javax.microedition.amms.control.imageeffect.ImageTransformControl");
fc.setTargetSize(width, height, 0);
fc.setEnforced(true);
fc.setEnabled(true);
mp.complete();
src.close();
return Image.createImage(bos.toByteArray(), 0, bos.size());
} catch (MediaException e) {
System.out.println("MediaException in Utils.resizeImage():" + e.getMessage());
} catch (IOException e) {
System.out.println("IOException in Utils.resizeImage():" + e.getMessage());
}
return null;
}
Wednesday, February 13, 2008
RSS Reader Gadget updated
I have made a minor update to the RSS reader gadget. You can now set how old items that should be displayed. Increases usability quite a lot.
Check it out here.
Check it out here.
Subscribe to:
Posts (Atom)