2016-01-24

Quick tip: Logging in Gradle build scripts

Did you know that it is really easy to log something in your Gradle build files? As the Gradle documentation explains, Gradle adds two log levels: QUIET is used for important information messages, whereas LIFECYCLE should be used to log progress information messages.

To see how it works, take a look at the following screenshot. It demonstrates how to log if Android's new experimental toolchain Jack and Jill is enabled. To enable it, just insert useJack = true.
A small note... You may be asking yourself why I used the unusual == true. It appears that this expression is more reliable if the variable useJack is not present at all.

2016-01-17

Thoughts on the mobile enterprise #7: Apps for employees

In a series of posts I will elaborate on how enterprise applications can embrace mobile devices.

In part 6 we took a look at mobile apps for end users. In this post I will turn to apps that are used by employees. Such apps can be divided into several broad groups, too.

Apps that replace old user interfaces

Imagine this scenario: you have an enterprise application that has been in production for several years. The user interface is implemented as a Java-based rich client. Now, the company decides to give the application a fresh new look. One reason for this may be that management has decided to replace the pcs in the offices with thin clients and to establish a virtual desktop infrastructure. As the execution environment for user interfaces is merely virtualized, the old Java-based user interface could be used further. However, depending on the number of computers to be replaced, the server-side infrastructure needs to be quite powerful.

If a change of technology is inevitable (because it is requested), today new user interfaces are usually implemented as web applications. The underlying reasoning is that such apps will easily run on mobile devices. As you shall see in the course of this series of blogposts, this may be a misconception. To be able to switch the ui technology stack, the corresponding parts of the application must be clearly separated. As I have discussed earlier, this is by definition true for rich clients - although this says nothing about the quality or usefulness of the provided interface. Current Web-based apps, on the other hand, unfortunately tend to be a melting pot with fuzzy, difficult to separate layers. Then, changing the user interface, inevitably means refactoring the whole application. Let me be clear about this: this is no flaw the involved technologies per se, but stems from poor application design.

There may be a more substantial change of technology on its way than moving from traditional pcs to virtualized, centralized desktops. Until recently, touch enabled devices without mice and keyboards had form factors way too small to be used in the office. This might change, as the latest tablet generation offers display sizes up to 15 inch. I expect this development to continue. At the time of writing Microsoft's Surface Hub is a (forgive me) fascinating and exciting curiosity. Smaller-sized versions might well become the office device of the future.

To sum up, apps that replace old uses interfaces are the new, friendly face of the host. Devices that display them are seldom moved, are part of the company intranet and are connected to the backend over high speed networks. If this is done by wire or over the air is a matter of taste (driven, perhaps, by costs and available infrastructure).

Special-purpose apps for in-house use

Special-purpose apps for in-house use form a niche group. The devices that display the user interface are highly portable, usually equipped with sensors or scanners to collect data, and may even have a small printer to produce labels. They are part of the company intranet and exchange data with their backend frequently. Depending on the purpose, the device may have a touch screen, or an old fashioned keyboard that can withstand rough working conditions.

If a special-purpose device is used, the technology stack for the user interface may be restricted by the operating system or the vendor. If the system is even more closed, the only possible connection to an enterprise app may be a (hopefully documented) remote interface, or direct access to the system's database.

Examples include inventory systems to support facility management, measurement of environmental conditions and warehouse management.

Apps for off-site employees

This category subsumes apps for employees who mostly work off-site, for example sales representatives, insurance broker or traveling salesmen. We can distinguish between

  • apps that work with customer data
  • apps that operate on company-related data
  • apps that do something

Customer data is related to, well, customers. This may include addresses, contracts data, income, debts, age, children and other personal information. Such data is highly sensitive. The mobile enterprise application must make everything possible to protect it. As you shall see later, this includes the client, the transport route as well as the backend.

Company-related data may refer to products the organization is selling, but also employees contacts data, sales figures, statistics, organizational charts and assets lists. Such data is highly sensitive, too. Therefore the mobile enterprise application must make everything possible to protect them.

You may argue that stressing those security aspects seems a little over the top as they are obvious. Keep in mind that most mobile enterprise apps are not built from scratch. Instead they evolve from a system that has been running for years. Even if a proper security analysis has been done when the application went online, network topology, app-server configurations and firewall settings have likely changed since then. Besides, if the route from client to the backend used to be secure, some security measures may not be in place just because they have not been necessary. I will talk more about security later.

The choice of ui technology should be based upon the focus of the app. If a considerable amount of data has to be entered or edited, rich client-like frameworks must be considered. If the app is used to visualize content (animations, photo-realistic renderings, charts), possibly handing the device over to the customer, this requires a slick and polished visual appearance.

I will conclude this post with apps that do something. They may collect some sort of telemetry or sensor data, scan barcodes, print labels or program process control computers. Hence, they are similar to special-purpose apps for in-house use, besides that they are used off-site. So what I have said above applies here, too:

  • the devices that display the user interface are highly portable
  • depending on the purpose, the device may have a touch screen, or an old fashioned keyboard that can withstand rough working conditions

2016-01-16

Thoughts on the mobile enterprise #6

In a series of posts I will elaborate on how enterprise applications can embrace mobile devices.

Part 6: Apps for end users

Just as there was a (fortunately long gone) time when company executives used to say We need a website there also has been a time when they wanted an app. There is certainly nothing wrong with this, besides the lack of focus. In this and a few following posts I am going to take a closer look at types of mobile apps (the word enterprise is missing on purpose). Talking about this usually leads quickly to a native vs. cross platform debate. While that decision certainly has to be made, I think it should not be the starting point. Other matters ought to be considered first.

The most important question is Who is going to use the app?. Who will be the target audience? As you shall see soon, its quite short answer end users/customers or employees has a significant impact on further decisions. End user apps can be divided into two broad groups:

  1. apps that solely run on the client (for example games, productivity apps, tools and media players)
  2. apps that connect the user to some service (for example Facebook or Twitter)

The difference lies in the decision if the app itself is the product (which undoubtedly is the case for games) or the service the app connects the user to. In other words: is the app published to make money or gain reputation, or is it put in the app store to promote the underlying service? The distinction between those two groups may not always be easy. For example, what happens if the game saves a highscore list on the publishers' servers? Or if a writing app stores its files there? If the app is tied to the vendor, that is, the user is forced to create an account, the app probably belongs to category 2. If the save function is merely an add-on, the app belongs to the first category.

If the app itself is the product, it has to be as good as possible. What this means depends on its purpose. For example, games must be compelling, that is, graphics, sound and gameplay provide an awesome experience. Do not confuse this with the need to provide super-realistic hd pictures. An app that mimics retro style may be equally fascinating. The important point is that the underlying concept has to be convincing. Especially games are usually implemented as native apps. The decision is often based on the need for maximum performance. Other types of client-side apps may not have this restriction.

Apps that promote a service must do everything possible to make that service shine. Depending on its type, the app may need to integrate deeply into the client system. Here, too, a native app is often the right choice. In such a case, though, not the performance matters, but the need to communicate with other apps and components. For example, the client for a calendar service must make events and appointments available to the system-wide calendar. The same applies to contacts.

Apps of both categories may use wireless communications. Usually apps that solely run on the client will need less transfer capacity. If logins to a backend server are made, both groups have to ensure the security of the users' data. How this can be done is subject to a future blogpost.

Back to part 5

2016-01-10

Thoughts on the mobile enterprise #5


In a series of posts I will elaborate on how enterprise applications can embrace mobile devices.

Part 5: Notes by the editor (the story so far)

In part 4 I discussed how much logic can or should be present in the ui layer of an enterprise application. The series so far motivated the term mobile enterprise application. You have seen how they relate to traditional enterprise apps and what has to be done to make them ready for mobile devices. Future posts will discuss matters in greater detail.
Book cover: On Mobile Enterprise Apps
The posts will be combined, expanded and carefully edited to become a book called On Mobile Enterprise Apps. The book will be available through leanpub. I'd very much appreciate feedback about the topic in general and my writing in particular. If you would like to be informed when the book is finished, please sign up for a notice on the leanpub book page.

2016-01-09

Thoughts on the mobile enterprise #4

In a series of posts I will elaborate on how enterprise applications can embrace mobile devices.

Part 4: About logic on the client

At the end of part 3 I asked you to imagine that your hypothetical enterprise application is well structured and consists of several components that implement the business logic. These components can be accessed through some remote interface. Further, the ui layer is implemented as an individual program running on a pc. It could call the business components through some remote procedure call mechanism. Should it?

If you found this question misleading, you are certainly right. Of course it should. To some extent. The underlying (hidden) question is how much logic is allowed or wished for on the client.

Consider this: who should take care of the orchestration if several remote procedure calls are necessary to complete a business function? Who is in control of the page flow or navigation? Where does validation of user input take place? How much does the client know about data types and dependencies among fields on a form? To answer these questions we need to decide how thick or thin, rich (or poor) the client should be. Especially the term thin client is used in several ways. To escape ambiguity I prefer an alternative means of distinction: business logic vs. presentation logic. The first one drives the application, it is a manifestation of its use cases. Presentation logic, on the other hand, drives the user interface. It is generally agreed upon that within distributed systems no business logic shall be present in the ui layer. One reason is that you would loose functionality if you exchange the client. Presentation logic is specific for each type of client. Hence it seems natural to put it in the corresponding layer.

If the client knows the page flow and knows which forms will be displayed along the way it can do so without bothering the backend. Of course, at some point it will need to persist user input or invoke a business function. Certainly, final consistency checks must be performed by the backend even if the client knows how to validate input. But if the client is self-sufficient to some extent it spares us server roundtrips. Something that may be crucial for mobile apps.

2016-01-04

A look in the crystal ball

There has been quite a buzz around Android N (supposedly to be released some time this year) switching to OpenJDK. But what exactly could that mean? What parts or components might be affected? Attendees of my talk Nummer 5 lebt at HerbstCampus 2015 in Nuremberg (Sep 1 2015) know since then that being related to Apache Harmony Android is somehow stuck in Java 6. Because Google has extended the old code on its own, developers coming from pure Java find it especially hard to guess what class library features are present and which are not. If you have not had a chance to see me, come join me at TopConf Linz 2016. In my talk Beyond Harmony I will give you an update on what you can expect today, and what you might expect from Android N.

While it seems clear that Google will be updating the code base of the Java class libraries to OpenJDK it is mere speculation if and how this move will affect the Java runtime and the use of tools, especially the Java compiler. Unlike when I gave my talk at HerbstCampus last year, it is now common knowledge among developers that since Android 5 the platform no longer uses its own register based virtual machine named Dalvik, but exclusively relies on a runtime named ART (Android Runtime) which is based upon an advanced ahead of time compiler. In doing so, Android apps become native Linux apps at installation time, hence benefiting from all the goodness the Linux kernel has to offer, such as kernel samepage merging. Though I have no inside knowledge whatsoever I doubt Mountain View will be giving this up.

Something not so common place is that since more than a year there is a new (experimental) tool chain around two tools named Jack and Jill, aiming to speed up compilation and build time. Jack (Java Android Compiler Kit) comprises a compiler from Java programming language sources to the Android dex file format. Jack has its own .jack library format and provides most tool chain features as part of a single tool, for example repackaging, shrinking and obfuscation. Jill (Jack Intermediate Library Linker) is a tool that translates existing .jar files to the .jack library format. At the time of writing Jack knows Java 7 language features.

It will be interesting to see if Google will be expanding on this, or giving it up. In any case for us Java lovers this all is quite good news.

2015-12-27

Thoughts on the mobile enterprise #3

In a series of posts I will elaborate on how enterprise applications can embrace mobile devices.

Part 3: Logical units

I concluded part 2 by saying that the business logic must be accessible from the outside world through some remote interface. What outside world really means, remains to be defined in a future post. For now it shall suffice to say accessible by a remote front end. This interface must reflect the whole functionality of the application. If it does, we meet the prerequisites I posted in part 2.

Applications need to be distributed.

If we have a remote user interface layer... Check.

Applications need to be properly layered.

You might frown upon this one. At this point I merely mean that the data access layer is properly separated from the business layer, which in turn is properly separated from the user interface layer. And the ui layer does not have direct access to the database layer (and vice versa). Nothing extraordinary, just well-behaved architecture. If this is something we see often, is, of course, another story...

Functionality must be accessible individually.

What does this mean? How do you structure an application in blocks or parts or components or services in a way that makes sense? Fortunately it is not up to me to answer these questions. I am in the comfortable position to just demand that these building blocks be there. ;-) To identify them, you can take a look at the use cases of an app (as a first step). Send a message. Dial a number. Send an email. Such simple sentences describe what an actor does to achieve something with or within a system.

Android uses this concept as one of the main building blocks for its applications. An activity is an action (for example, play a song) combined with a particular user interface (what the user sees on screen while the song is playing). If an activity wants to initiate another action it sends so-called intents. Hence, the action (play song) is the business logic (playing a song) combined with what the user sees on the display while the action takes place.

Another way to find individually accessible parts may be to look at business processes. Each step may be a candidate for a building block, especially if the step is reused among multiple business processes.

Let us stop here for now.

Imagine, your enterprise application is well structured. It consists of several components that implement the business logic. They can be accessed through some remote interface. The ui layer is implemented as an individual program running on a pc. It could call the business components through some remote procedure call mechanism. Should it?

2015-12-25

Thoughts on the mobile enterprise #2

In a series of posts I will elaborate on how enterprise applications can embrace mobile devices.

Part 2: Improvement to the worse?

In the first part we remembered that using full-fledged pc's for running the user interface of enterprise applications had become expensive. Each new application required a new front end on the client, which in turn reached its limits increasingly often. Keep in mind, that at that time (the first half of the first decade) there were no dual cores, no gigabytes of ram, no 64 bit systems, no gigabit Ethernet - at least not in the offices.

So, was the idea of building the user interfaces of enterprise applications using traditional client technologies bad? By no means. It offered tight integration with the client, for example by accessing local hardware (printer, scanner, chip card reader, ...), or to communicate with other apps. Today, Android developers take it for granted that they can utilize functionality of other apps simply by firing and consuming intents. In the early 2000s (and even before) that would have been possible, too. Typical Windows apps heavily relied on the component object model, which exposed functionality of a program to other apps. Sadly, competing technologies relied on incompatible object models. Out of the box, it was impossible to have a Java Swing-based client app talk to, say, MS Office, and vice versa. The constraints imposed by the hardware have already been mentioned. As I wrote in the first part of this series, the solution seemed simple.

A web browser seemed like a reasonable execution environment for user interfaces. If the user interface is rendered by the browser, there is no need for an additional rollout when a new enterprise application is introduced. What the browser would render, had to be prepared by the backend and then sent to the client. Hence, this transmission contains data and display instructions. User input is sent back to the backend and processed. Early web frameworks produced user interfaces that could not compete with well-designed rich client applications. No validation of user input, bad usability, delays due to server roundtrips, ... Even a decade later some aspects still require ridiculous workarounds. For example, have you asked yourself why generally agreed upon shortcuts (hotkeys) are not used in web based apps?

Anyway... This is not meant to be a rant against certain technologies. I am merely trying to set the stage for what I would like to call the mobile enterprise, that is, how organizations and their applications can embrace mobile devices. To do this, quite a few prerequisites must be met. A few of them are:

  • Applications need to be distributed.
  • Applications need to be properly layered.
  • Functionality must be accessible individually.

If a physically distant client program is used as the user interface of an enterprise application, there MUST be a public interface. If this was well-written and thoughtfully designed remains to be seen, but at least it is there. My experience is that in typical web apps the separation between business logic and the ui layer is often fuzzy, if present at all. If all melts into one single .war or .ear file, why bother a costly separation of layers? Test yourself. What is a front controller or a business delegate?

The take away of this part: the need to properly structure an application and to establish well-defined interfaces is as urgent as ever. How this can be achieved shall be the topic of a future installment.

Go to Thoughts on the mobile enterprise #1

2015-12-22

Android to reach out for desktops?

You won't need a crystal ball to see the future of Android. Android is reaching out for the desktop. As ars technica points out in a superb article there is quite some way ahead. But there is already a lot there. Yes, right now there is no real window support (available to end users). But earlier reports made it clear that Google is working on supporting split screen windows, which we can see in Windows 10 and on the iPad Pro, and more. So, to take an educated guess, we will see this in Android 7. Once rolled out, it'll be up to Google and third party vendors alike to adapt their apps as fast as possible.
If the market wants another desktop-like system remains to be seen. Still, the Chromebooks have been quite a success. If Google is really planning to phase them out, Mountain View needs to make sure that the key advantages of Chrome OS are present in a future Android, too. Among others, these are...

  • low maintenance costs
  • reliability
  • stability
What do you think - is there a scenario you would trade your Mac OS X or Windows machine for a Android-based desktop or laptop?

2015-12-19

Thoughts on the mobile enterprise #1

In a series of posts I will elaborate on how enterprise applications can embrace mobile devices.

Part 1: Once upon a time

For a long time, the basic building blocks of enterprise applications were easy to choose: a programming language, a distributed component model infrasturcture, a relational database management system and a ui library. The database often resided on a dedicated database server, an (app) server hosted the business logic, and the ui was put on the client. The client usually was a Windows-based pc, running apps written in C++, Java, Basic, Pascal, or any other language the developer saw fit, the only prerequisite being access to some graphical user interface toolkit. Conceptionally, each enterprise application lived in its own world. Exchange of data with one of the few other applications was neither planned nor wanted. Why would department a share its information with department b?

And then came the problems.

Throughout the years, business processes became more complex. What once was done in one department, became a shared effort among several business units, requiring the use of several programs. Consequently, the users wanted the applications to cooperate with each other.

And then came the complaints.

Rolling out client software became expensive, time-consuming, prone to error. Building the user interface was said to be expensive, too. As was the necessity of frequently updating the hardware: more programs on the pc required more ram, bigger hard drives, faster cpus, networks with higher bandwidths. The solution seemed simple. If rolling out the ui is expensive, why roll it out at all? If upgrading the pc is expensive, why do an upgrade at all? The rise of the web brought a browser to every client (pc). Hence, wasn't it natural to use it as a runtime environment for the ui?

Let us stop here for a moment. As I have said at the beginning, enterprise applications used to be distributed: different layers ran on different pieces of hardware. Usually the ui layer (a program on a desktop pc) communicated with the business logic layer using some binary protocol, for example IIOP, RMI over IIOP or T3. The amount of data that needed to be transferred depended on the interface the business logic provided. If it was well designed, only small amounts of data had to be transmitted. And that data was just... data.

As we shall see in the second installment, this was going to change...

2015-12-17

Reflections on a suggested coding convention

Today I read an interesting post by Sam Atkinson about a few new Java coding conventions. One of his suggestions is to use zero comments. While I am not saying the idea per se is wrong I am suggesting to stay open for exceptions. Consider this:

// manage your api key at http://www.example.com
private static final String apiKey = "...";


I think we agree that hinting at where to manage the api key is sensible. Any developer maintaining this code may have to manage the key. But if we remove the comment we need to pass the info elsewhere. I doubt that we should name a variable apiKeyCanBeManagedAtHttpWwwExampleCom. Should we?

2015-12-14

Join me at TopConf Linz

Join me at TopConf Linz Feb 1-3 2016 Linz, Austria. I will be talking about Android and Java, subtle and not so subtle differences, origins and possible futures.




The title of the talk is Beyond Harmony: Java SE vs. Android. It's scheduled 2016-02-02 at 12:00. Abstract: It is common place that most Android apps are written in Java. But what does that mean? Are enhancements to the language available immediately, or can't they be used at all? Do developers benefit from improvements to the class library? This talk not only addresses these questions, but explains how to use features that are not meant to be available.

2015-12-09

Touch is the new click (most of the time)

Recently, I made an interesting discovery. I found out that – while my computer was in touch mode – NetBeans did not respond to double taps. Generally speaking, double taps are a common gesture on touch devices, for example to expand or collapse nodes in tree views, or to open a file. Now you might argue that touch devices are not particularly well-suited for developing purposes, and therefore, it does not matter. That is true. The purpose of this post is to find out what is going on, as NetBeans is a very well-crafted Swing-based application, and it is quite unlikely that NB is doing something wrong here.
My machine is a Surface 3 Pro. If connected to the so-called Type Cover, it is an ordinary Windows 10-PC. The Type Cover has a keyboard and a trackpad which controls mouse pointer movements. In this mode, of course, double clicks on tree views work flawlessly. Touch mode kicks in if the Type Cover is removed. You can still see and use the desktop, and you can still use all apps. There is no mouse pointer, however, so which object is accessed depends on where you touch the screen with your finger. Single taps work like single mouse clicks. Double taps work like double clicks. Well, or should. To see if Java or Swing have issues here, I ran a pre-compiled SwingSet2. Double taps work as expected. So, I then wrote a small program that uses both JavaFX and Swing. Here is the source. And this is how it looks like:
Screenshot of a sample program
Tap detection works as expected, too. At least most of the time. Once in a while the double tap does not get delivered, though.
At that point, I decided to get the NetBeans sources and try to debug then. Building does take some time, but in the end I was able to debug NetBeans - in NetBeans. Guys, this is awesome. I decided to debug org.openide.explorer.view.TreeView. It attaches an instance of PopupSupport which in turn extends MouseAdapter to a ExplorerTree using addMouseListener(). Everything is fine here. Debugging shows that mouseClicked() is correctly called twice when not in touch mode, but only once when touch mode is active. When or where the tap gets lost still needs to be investigated. As of today I would assume that NB has nothing to do with this strange behaviour.

2015-12-07

Auf Wiedersehen. Hello and welcome

Heute wende ich mich einmal nicht mit einem technischen Thema an Sie, liebe Leserin, lieber Leser. Dies ist der letzte Post auf Deutsch. Nicht, weil ich mein Blog schließe, sondern weil ich mich entschieden habe, ab sofort auf Englisch zu posten. Der einzige Grund hierfür ist, hoffentlich eine noch größere Leserschaft zu erreichen. Bitte bleiben Sie Tommis Blog dennoch gewogen. Vielen Dank.

2015-11-28

Neues von Notes and Tasks

Erinnern Sie sich noch an meinen Ultimate Swing-Marathon, der irgendwann ein jähes Ende zu nehmen schien? Heute hatte ich mal wieder Lust, an der im Zuge der zahlreichen Blogposts entwickelten App Notes and Tasks zu schrauben. Da Google Code bald nicht mehr unter den Lebenden weilen wird, hatte ich das Repository im April nach Bitbucket migriert.
Die Codeänderungen beseitigen ein paar generics-Warnungen des Compilers und binden die App besser in Mac OS X ein. Konkret lässt sich der Programminfo-Dialog über die Menüleiste aufrufen. Gleiches gilt für die Settings. ...wobei es den dazu passenden Dialog in der Anwendung noch nicht gibt.

Vielleicht fragen Sie sich ja, warum ich mich mit diesem alten Kram befasse. Ich schraube einfach gern, und außerdem habe ich ja mal versprochen, eine schöne Notizanwendung zu bauen. Und da es JavaFX nicht besser geht als Swing, kann ich das gerne auch weiterhin mit Swing tun. ;-)

2015-11-23

Ans Aufräumen denken

Seit ein paar Tagen gibt es Android Studio 1.5. Wer das Update gemacht und die Migration seiner alten Installation erfolgreich abgeschlossen hat, sollte prüfen, ob das alte Datenverzeichnis noch gebraucht wird. Denn auch in Zeiten großer Platten/SSDs lohnt es sich, gelegentlich zu entrümpeln.

Belegten Speicherplatz freigeben

2015-11-21

Auf das Offensichtliche muss man erst einmal kommen

Mein Firmenrechner ist ein MacBook, mein privater Computer ein Surface 3 Pro. Zuhause hängt der Mac an einem externen Monitor, das Tablet ruht im Dock. Wenn ich am Surface arbeiten wollte, habe ich bisher Monitor und Tastatur an das Dock angeschlossen. Auf Dauer etwas nervig. Deswegen wollte ich mir eigentlich einen Tastatur- und Monitorumschalter besorgen.

Heute hatte ich nun eine zündende Idee. Warum nicht einfach mittels Remote Desktop auf das Surface zugreifen? Die App kann aus dem Mac App Store bezogen werden:

Screenshot: Microsoft Remote Desktop

So. Falls sie jetzt denken – das sind doch olle Kamellen… Ja, mag sein, aber manchmal braucht man für das Offensichtliche eben etwas länger. Smiley

2015-11-16

Android-Emulator wieder flott machen

Vor kurzem hatte ich mein Surface 3 Pro auf Windows 10 1511 aktualisiert. Kurz vorher gab es zudem ein Firmware-Update. Und Android Studio wollte ebenfalls auf den aktuellen Stand gebracht werden. Und das Ergebnis? Eine Fehlermeldung, dass der Emulator nicht im fast virt mode gestartet werden kann. Der Versuch, einfach auf die neueste Version vom HAXM zu aktualisieren, schlug mit der ermutigenden Fehlermeldung fehl, dass mein Computer kein VT-x kennt. …ich weiß schon, “musst du nur im BIOS-Setup einschalten”. Ja, nach gefühlten 20 Klicks landet man ja auch in den UEFI-Booteinstellungen, nur kann ich da nichts bzgl. Virtualisierung konfigurieren. Und nun?

Ich erinnerte mich an die ersten Tage mit meinem Surface 3 Pro, damals hatte ich Spaß mit Visual Studio und Hyper-V. Und dem neuen Connected Standby. Es half, Hyper-V zu deaktivieren. Genau dasselbe ist nötig, um Intels Hardware Accelerated Execution Manager nutzen zu können. Einfach in einer Administrator-Eingabeaufforderung bcdedit /set hypervisorlaunchtype off eingeben und zur Sicherheit neu starten. Nanach lässt sich HAXM ganz prima aktualisieren, und der Emulator-Start aus Android Studio klappt auch wieder.

Was letztlich den ganzen Schluckauf verursacht hat, weiß ich nicht. Da Windows 1511 ein richtiges Upgrade war, liegt die Vermutung nahe, dass dabei Hyper-V wieder aktiviert wurde. Belegen kann ich das aber nicht…

2015-11-12

TKWeek 1.8.5

Würden Sie gerne für bestimmte Tage kurze Textschnipsel hinterlegen? TKWeek 1.8.5 führt auf seiner Tagesübersicht einfache Notizen ein. Wie das aussehen kann, ist in der folgenden Abbildung dargestellt.
Klicken Sie einfach den Button mit dem Tastatursymbol an, um Notizen zu erfassen oder zu ändern.
Notizen werden tageweise gespeichert und dank des neuen Backup-Mechanismus von Android 6 automatisch gesichert.
Gefällt Ihnen TKWeek? Haben Sie Ideen für weitere Funktionen? Schreiben Sie mir...

2015-11-08

Linktipp: Hilfe bei High DPI-Problemen

Es ist schade, dass sich die beiden IDEs NetBeans und Eclipse auf Anzeigen mit hoher Pixeldichte nach wie vor so schwer tun. Gestern habe ich mir NetBeans 8.1 geholt und bin wieder über dasselbe Problem gestolpert - auf meinem Surface sind Fonts und Icons lächerlich klein. Dabei ist die (Übergangs)Lösung doch so einfach, wie Ken Fogel in seinem Beitrag auf jaxenter schreibt: einfach im Installationsverzeichnis unter etc die Datei netbeans.conf so abändern, dass dort bei -J-Dsun.java2d.dpiaware= anstelle von true ein false steht.
Auch Eclipse lässt sich mit wenigen Schritten nutzbarer machen, wie Fogel zu berichten weiß. Ein Registry-Eintrag sorgt dafür, dass Windows so genannte Manifeste nachladen kann. In einem zweiten Schritt wird einfach eine Datei <programmname>.exe.manifest im selben Verzeichnis wie die zu startende Anwendung abgelegt. Genaueres entnehmen Sie bitte dem verlinkten Post.

2015-11-05

Windows Live Writer-Tipp

Kennen Sie diese Fehlermeldung?

Screenshot 1

Sie erscheint, wenn man versucht, sich mit seinem Google Konto in Live Writer bei blogger.com anzumelden. Das Problem scheint dadurch entstanden sein, das Google das alte Client Login-Protokoll deaktiviert hat. Bis eine neue Version des Live Writer erscheint, können Sie versuchen, in den Google Kontoeinstellungen den Zugriff durch weniger sichere Apps zu aktivieren.

Screenshot 3

Aktuelles zu TKWeek

In den letzten Tagen habe ich ein bisschen an TKWeek geschraubt. Die neue Version ist noch nicht hochgeladen, aber vielleicht können die folgenden Screenshots etwas Appetit machen.

Screenshot 1

In der Tagesübersicht können Sie nun abgeschlossene Aufgaben anzeigen und so deren Status zurück auf nicht abgeschlossen setzen. Ebenfalls praktisch finde ich, dass Sie direkt einen Termin anlegen können.

Screenshot 2

Screenshot 3

Was ich aber echt cool finde, ist die Integration in die Sprachsteuerung. Sagen Sie OK Google, Notiz an mich, Brot kaufen, können Sie dies an TKWeek weiterreichen und auf diese Weise eine Aufgabe anlegen.

Wie gesagt, noch ist diese Version nicht live, kommt aber bald.

2015-10-18

Kleines Update für C64 Tribute Watchface

Es gibt ein kleines Update für mein Android Wear-Zifferblatt C64 Tribute Watchface. Bislang sah das Startdisplay (ich habe bis heute nicht verstanden, warum Google diesen merkwürdigen Begriff verwendet) auf runden Anzeigen (ja, ich weiß, ist bei Uhren was Exotisches ;-)) nicht besonders schick aus. Jetzt schon:
Ziemlich nervig auf runden Displays war auch, dass man man die Einstellungsseite nicht richtig bedienen konnte. Auch das ist nun behoben. Falls jemand fragt - ich hab immer noch die erste LG G Watch. ;-)

2015-09-17

Ausgemauert

In Android gibt es viele skurrile Dinge. Mancher Leser dieses Blogs mag sich an meinen Talk Android Puzzlers erinnern. Nicht hinein geschafft hatte es die Stringkonstante BRICK. Über sie ist viel geschrieben und spekuliert worden, Echten Schaden angerichtet hat sie wohl nie. Und mit Android 6 ist sie nun Geschichte. R.I.P.
Auszug aus der Android-Entwicklerdoku

2015-09-15

Clip4Moni unter Linux

Heute wollte ich meine kleine Textschnipselverwaltung Clip4Moni in mein virtuelles Ubuntu 14.04 integrieren. Die .jar-Datei als automatisch startende Anwendung zu hinterlegen, sollte doch eigentlich ein Kinderspiel sein. Oder? Nicht ganz. Clip4Moni wollte nämlich einfach nicht starten... Pfade? Korrekt. Java? Vorhanden und im Suchpfad.
Nun ist die Krux bei Autostart-Programmen, dass das System einen die Fehlermeldungen nicht direkt um die Ohren haut, sondern man danach suchen muss. :-) Es hat sich herausgestellt, dass das Programm mit einem system tray not supported abbricht. Was insofern verwundern darf, als der Start aus der IDE heraus prima klappt. Ich vermute ein Timing-Problem. Vielleicht (Achtung: Spekulation) werden Autostart-Programme von Unity zu früh aufgerufen, so dass Java kein Systemtray findet. Ich konnte das Problem umgehen, indem ich in das Startscript von Clip4Moni ein sleep 5 eingebaut habe.
Eine kleine Unschönheit ist noch, dass der Hintergrund des Programmicons nicht wie gewünscht transparent ist, sondern grau. Hierfür gibt es einen Eintrag in der Fehlerdatenbank.

2015-09-13

Sonntägliches Kaffeesatzlesen

Heute schiebe ich mal einen zweiten Post nach... Bei einer schönen Tasse Kaffee philosophiert es sich so gut... :-)
Apple hat auf seinem September-Event ja nicht nur das iPad Pro vorgestellt, sondern auch gezeigt, was man mit großen Bildschirmen anstellen kann. Zum Beispiel zwei Apps nebeneinander darstellen. In der Desktop-Welt ist das natürlich ein alter Hut, man darf dabei aber nicht vergessen, dass die mobilen Betriebssysteme eben doch von den kleinen Bildschirmen her kommen. Weder auf dem ersten iPhone, noch auf dem Google G1 wäre so etwas sinnvoll gewesen. Hinzu kommt, dass die Rechenleistung der mobilen Geräte eben erst in den letzten Jahren auf Desktop-Niveau gebracht wurde. Selbst wenn man also dem ersten iPad eine für so etwas geeignete Bildschirmgröße zugestehen muss - seine Leistung wäre einfach nicht ausreichend gewesen. Microsoft hat auf seinen Surface-Geräten den (sogar recht flexiblen) side by side-Betrieb von Modern UI-Apps schon vor geraumer Zeit verfügbar gemacht. Nur konsequent ist deshalb, dass iOS hier nachzieht.
Und Android? Google hinkt nur scheinbar hinterher. Schon vor einigen Monaten hat ein verstecktes Feature in Android M-Previews für Aufsehen gesorgt. Ganz marktreif ist die Funktion wohl noch nicht, denn die letzte Vorschauversion für die Nexus-Reihe hat sie nicht an Bord. Da Android 6 Marshmallow aber in Verbindung mit neuen Smartphones debütieren wird, ist das Fehlen verzeihlich. Sinnvoll ist ein Zwei-Fenster-Modus bei 5,5 Zoll sicher nicht. Schon eher bei größerformatigen Tablets. Es würde mich daher nicht wundern, wenn es - wenn mal wieder ein neues Nexus-Tablet erscheint - ein Android 6.1 gibt, dass das Feature nachrüstet. So etwas ähnliches hat es früher ja schon beim Mehrbenutzermodus von Android gegeben. Der war zunächst nur auf Tablets verfügbar und hat etwas später auf Smartphones Einzug gehalten.
Was meinen Sie? Brauchen Sie den Zweifenster-Modus? Schreiben Sie mir...

Marshmallows mögen keine analogen Uhren

Ab API-Level 23 gilt die View AnalogClock als veraltet. Ich verneige mich vor der Komponente mit einer Abbildung aus meinem Android-Buch.
Abbildung aus meinem Buch Android 5
Die Frage ist nun - haben Zifferblätter und Zeiger keinen Platz im Material Design? Was denken Sie? schreiben Sie mir.

2015-09-07

Neu in Marshmallow: ArraySet

Es sind nicht immer die großen Neuerungen, die Entwicklern das Leben leichter machen. Auch die kleinen Dinge können helfen. Ob dies für die neue Klasse android.util.ArraySet zutrifft, sollte jeder für sich selbst entscheiden. Sie soll, so die Doku, effizienter mit dem Speicher umgehen als ein traditionelles HashSet. Ich zitiere:
“This implementation is separate from ArrayMap, however, so the Object array contains only one item for each entry in the set (instead of a pair for a mapping). [...] Because this container is intended to better balance memory use, unlike most other standard Java containers it will shrink its array as items are removed from it. Currently you have no control over this shrinking -- if you set a capacity and then remove an item, it may reduce the capacity to better match the current size. In the future an explicit call to set the capacity should turn off this aggressive shrinking behavior.”
Die spannende Frage ist: lohnt dies den vendor lock-in? Werden Sie die neue Klasse in Ihrem Code verwenden? Schreiben Sie mir...

2015-08-26

Wenn die Vortragsglocke dreimal läutet

Der August neigt sich dem Ende zu. Ein freudiges Ereignis, weil dann der Herbstcampus vor der Tür steht (31. August bis 3. September). In diesem Jahr bin ich mit drei Vorträgen vertreten:

App-ocalypse now - The dark side of your App (gemeinsam mit meinem Kollegen Tim Bourguignon)
A33 Donnerstag, 3. 9., 14:00 – 15:10 Uhr

Nummer 5 lebt - Aktuelle Java-Features unter Android nutzen
B13 Dienstag, 1. 9., 14:00 – 15:10 Uhr

Wer hat an der Uhr gedreht? - App-Entwicklung für Android Wear
B15 Dienstag, 1. 9., 17:20 – 18:30 Uhr

Ich freue mich auf regen Austausch, vor und nach den Vorträgen sowie während der ganzen Woche.

2015-08-22

DatePicker Dilemma

Ich habe kürzlich mein Nexus 5 mit der aktuellen Android 6-Preview bespielt. Nach der Installation von TKWeek war ich irritiert, dass ein altes Problem wieder da zu sein schien: die App zeigt eine Kalenderblatt-Ansicht anstelle einer eigentlich gewünschten Tag-Monat-Jahr-Auswahl:
TKWeek zeigt den falschen DatePicker
Dabei dachte ich, das Fehlverhalten schon vor geraumer Zeit korrigiert zu haben. Seit API Level 21 muss man laut Doku nämlich bei der DatePicker-Komponente mit android:calendarViewShown="false" und android:datePickerMode="spinner" dafür sorgen, dass man die Walzen-ähnliche Darstellung erhält. Dann sollte es so aussehen:

Tut es aber leider nicht. Nach langen Ausprobieren habe ich dann herausgefunden, dass es an der Zeile android:minSdkVersion="8" in der Manifestdatei liegt. Tausche ich die gegen android:minSdkVersion="21" aus, funktioniert die Komponente wie erwartet. Offenbar hat Android ein Problem, wenn ich sage, dass die App ab Android 2.x lauffähig sein soll. Dass dies Auswirkungen auf die Darstellung auf neuen Systemen hat, ist meiner Meinung nach bizarr. Vor allem, weil ich das Problem nicht fixen kann, ohne Nutzer alter Systeme im Regen stehen zu lassen.
Haben Sie damit auch schon einmal zu tun gehabt? Schreiben Sie mir...

2015-07-26

Here's to jjsb4a

Vielleicht erinnern Sie sich an meinen Post über den glücklosen Versuch, JSR 223 unter Android lauffähig zu machen. Damals habe ich beschrieben, dass es nicht klappt, weil in javax.script.ScriptEngineManager auf die nicht vorhandene Klasse sun.misc.Service zugegriffen wird. Und ich hatte angedeutet, mir Gedanken über eine entsprechende Wrapper-Klasse zu machen. Denn seit Java 6 gibt es mit ServiceLoader ja eine Alternative, die auch unter Android vorhanden ist.

Der Wrapper ist in trivialer Form fertig. Damit steht JSR 223 unter Android zur Verfügung. Oder auch nicht, denn die Rhino-Version, die mit der Referenzimplementierung ausgeliefert wird, erzeugt zur Laufzeit Bytecode. Und das klappt unter Android aus naheliegenden Gründen nicht. Wer mehr darüber erfahren möchte, kann dies in zwei Talks tun, die ich auf dem Herbstcampus und der TopConf Linz halten werde.

Allerdings ist in Android ja ein moderner JavaScript-Interpreter enthalten. Auf ihn zugegriffen werden kann über die Klasse WebView, also die Browser-Komponente. Warum sollte sich dies nicht nutzen lassen, um doch noch JSR 223 lauffähig zu bekommen?

Hier kommt mein Mini-open source-Projekt jjsb4a ins Spiel, das seit heute auf GitHub zu finden ist. Der unaussprechliche Name bedeutet übrigens Java-JavaScript-Bridge for Android. Derzeit kommt die Brücke noch nicht als eigenständiges Jar daher, sondern in Gestalt einer Demo. Sie befindet sich nämlich noch im Rohbau. Erste kleine Versuche sind aber möglich.

Übrigens wäre Android vermutlich nicht Android, wenn es nicht auch hier ein kleines caveat geben würde. Mehr dazu finden Sie im readme.

2015-07-12

Es will einfach nicht klappen, Ausgabe 20150712

Seit vielen Versionen ist es out of the box möglich, aus Java heraus Scriptsprachen aufzurufen. Der JSR 223 (Scripting for the Java Platform) hat nämlich schon mit Java SE 6 Einzug in die Plattform gehalten.

ScriptEngineManager m = new ScriptEngineManager();

ScriptEngine engine = m.getEngineByMimeType("application/javascript");

String program = "print('Hello, World!')";

try {

    engine.eval(program);

catch (ScriptException ex) {

    LOGGER.log(Level.SEVERE, null, ex);

}


Regelmäßige Leser meines Blogs wissen, dass ich meine Java-Gewohnheiten gerne auch unter Android ausleben möchte. Warum also nicht zum Beispiel auf die oben gezeigte Weise JavaScript integrieren? Erste Antwort: weil das Paket javax.script einschließlich seiner Unterpakete nicht in der Android-Klassenbibliothek enthalten ist. Gut, aber zu jedem Java Specification Request gibt es eine Referenzimplementierung. JSR 223 macht da keine Ausnahme. Warum also nicht diese nutzen? Die wenigen Jars sind schnell hinzugefügt, der Code wird übersetzt, die App startet. ...rrruuuuuuummmmsssss...... Vielleicht erinnern Sie sich ja an meine glücklosen Versuche, JAX-WS zu nutzen. Der Pessimist in mir ist nun geneigt zu fragen, warum es gerade jetzt hätte funktionieren sollen. Aber natürlich ist einfach so aufgeben uncool, und deshalb habe ich kurz den Debugger bemüht. Das ernüchternde Ergebnis: die Implementierung möchte gerne die Klasse sun.misc.Service nutzen. Und die ist (natürlich) nicht vorhanden. Was bedeutet das?

JSR 223 setzt auf einen einfachen Serviceprovider-Mechanismus, der an unterschiedlichen Stellen in der Java-Standardklassenbibliothek Verwendung findet. Dazu wird in einem .jar-Archiv eine Textdatei META-INF/services abgelegt, die der Java-Konvention für Klassennamen folgt, zum Beispiel javax.script.ScriptEngineFactory. Sie enthält eine Liste von Klassen, die das Interface mit dem Namen der Datei implementieren. Auf diese Weise findet eine Entkopplung zwischen Vertrag und Implementierung statt. Bleibt die Frage, wie die Auflösung bzw. das Finden der implementierenden Klassen funktioniert. Tja, und hier kommt sun.misc.Service ins Spiel. Übrigens gibt es seit Java 6 die Klasse ServiceLoader. Sie scheint aus Service hervorgegangen zu sein. Die kennt Android seit API Level 9 sogar.

Dumm nur, dass die Referenzimplementierung von JSR 223 sie nicht nutzt. Mal sehen, ob ich mir in einer ruhigen Minute mal ansehe, wie aufwendig der Umzug wäre...

2015-07-08

Android Emulator funktioniert nicht mehr – und was man dagegen tun kann

Kennen Sie das? Man ärgert sich über ein Problem, geht ihm aber nicht entschlossen genug nach. Bei mir war dies bei dem folgenden Dialog so…:

Screenshot: Android Emulator-Absturz

Er erschien sehr oft, wenn ich das Android Emulator-Fenster schließen wollte. Aber eben nicht immer. Heute habe ich mir vergegenwärtigt, was ich (üblicherweise) in welcher Reihenfolge tue:

  1. Android Studio beenden
  2. Emulator beenden

Halt. Warum nicht einfach diese Reihenfolge umkehren? Um es kurz zu machen – die Abstürze sind weg. Ich verkneife mir an dieser Stelle eine tiefgreifende Analyse und freue mich über den nicht mehr erscheinenden Dialog.

2015-07-03

Schöne neue Welt, Teil 3

In meinem vorherigen Post hatte ich eine Lösung für das nicht so ganz einfache Speichern von Fenstergröße und -position in JavaFX angedeutet. Wer sich meine Implementierung ansehen möchte, sollte einen Blick auf folgendes Bitbucket Snippet werfen.
Das Dilemma war ja, dass die vier Propertyänderungen zu unterschiedlichen Zeiten auflaufen. Ich sorge nun einfach dafür, dass Aktualisierung innerhalb einer Sekunde genau einmal betrachtet werden - und zwar nochmal eine Sekunde später. Nehmen Sie an, das Fenster wurde verschoben oder vergrößert. In diesem Fall ändert sich entweder das Paar x/y, oder Breite/Höhe. Die erste Änderung sorgt dafür, dass ein Thread gestartet wird. Dieser wartet eine Sekunde, und schreibt dann Position und Größe in die Benutzereinstellungen. Die zweite Änderung darf nicht noch einen neuen Thread starten. Das verhindere ich auf triviale Weise, indem ich einfach prüfe, vor wie vielen Millisekunden die letzte Änderung stattgefunden hat. Alles was kürzer als 1 Sekunde zurück liegt, wird verworfen. Da es sehr wahrscheinlich ist, dass alle vier Änderungen innerhalb von 1000 Millisekunden feuern, wird nur einmal der Zustand gesichert.
Auf diese Weise bekomme ich auch den inkonsistenten Zustand beim Maximieren in den Griff. Probeiren Sie es am besten einfach aus.

2015-06-29

Schöne neue Welt, Teil 2

In meinem vorherigen Post hatte ich geschrieben: Deshalb bietet es sich an, auch Positions- und Größenänderungen des Fensters zu überwachen, und die Werte im nicht maximierten Zustand zu sichern. Allerdings sieht JavaFX 8 meines Wissens nach keine Möglichkeit vor, sich mittels setOn…() über Änderungen der Fenstergröße oder –position informieren zu lassen. Meine Intention war deshalb, für die Properties x, y, width und height jeweils einen ChangeListener zu registrieren. Diese hätten zunächst geprüft, ob das Fenster maximiert wurde. Ist dies nicht der Fall, wären die jeweiligen Eigenschaften in die Preferences geschrieben worden.

Nun ist klar, dass das Anklicken des Volle Größe-Widgets zu Änderungen an allen vier Eigenschaften führen muss. Unerwartet ist für mich aber gewesen, dass die gemeldeten Koordinaten nicht zur maximized-Property passen. Hierzu ein Screenshot. Die Ausgaben sind unmittelbar nach dem Anklicken des Fensterwidgets entstanden. Die ersten beiden Ausgaben beziehen sich auf die ursprüngliche Breite und Höhe des Fensters. Die letzten beiden hingegen (x- und y-Position) entsprechen dem maximierten Zustand.

Bildschirmausgaben in der NetBeans-Console

Warum ist dies unbefriedigend? Da es keine Möglichkeit gibt, alle vier Angaben (Position und Größe des Fensters) in einem Rutsch zu ermitteln, tröpfeln die Änderungen in nicht vorhersehbarer Reihenfolge ein. Für das Speichern in den Benutzereinstellungen wäre es aber wichtig, alle Werte zum selben Zeitpunkt ermitteln zu können. Ich glaube, dass so etwas in das Framework gehört. Bis es soweit ist, können Sie sich aber mit einem Workaround behelfen, den ich im nächsten Post vorstellen werde.

Wie gehen Sie mit dem Problem um? Schreiben Sie mir…

2015-06-28

Schöne neue Welt

Kann sich noch jemand an den JSR 296 erinnern? Er spezifiziert ein Swing Application Framework, das die reichlich vorhandenen Bausteine von Swing insbesondere für den unerfahrenen Entwickler sinnvoll zusammenfasst. Leider wurde der Java Specification Request nie in eine Java-Version übernommen. Gut, mittlerweile ist Swing ebenfalls obsolet. Jedenfalls war ein recht nützliches Feature das sich Kümmern um Fensterzustände. Wird die Anwendung beendet, speichert das Framework Größe und Position in einer .properties-Datei. Warum man in der Referenzimplementierung seinerzeit nicht die Preferences API genutzt hat, verstehe ich übrigens bis heute nicht. Anyway. Die spannende Frage ist nun: wie sieht das unter JavaFX aus? Unterstützt der Swing-Nachfolger den Entwickler mit fertigen Hilfsklassen? Die nicht überraschende Antwort ist: im Prinzip ja. Eigentlich ist alles vorhanden. Wie schon bei Swing muss man sich den entsprechenden Code aber selbst zusammenhacken.

Man findet im Netz einige Posts zu dem Thema. Meistens wird vorgeschlagen, mit stage.setOnCloseRequest() einen EventHandler zu setzen, der Position und Größe der main stage ausliest und mit der Preference API persistiert. Beim (erneuten) Start der Anwendung werden die gespeicherten Werte ausgelesen und vor dem Aufruf von stage.show() gesetzt. Soweit, so gut. Was ich bislang nirgendwo gelesen habe: man sollte zusätzlich abspeichern, ob das Fenster beim Beenden maximiert war, und diesen Zustand beim Start wiederherstellen. Andernfalls erscheint das Fenster nämlich nur “irgendwie groß”, weil zwar Breite und Höhe auf volle Größe gesetzt werden, aber das korrespondierende Widget nicht den richtigen Zustand hat. Noch ein Caveat: ist das Fenster maximiert, dürfen Position und Größe nicht übernommen werden, damit beim erneuten Anklicken die ursprüngliche Größe wiederhergestellt werden kann. Also:

  • beim Beenden immer abspeichern, ob das Fenster maximiert ist (stage.isMaximized())
  • nur wenn das Fenster nicht maximiert ist, Position und Größe sichern

Beim Start der Anwendung…

  • immer setMaximized() mit dem gespeicherten Wert setzen; Standardwert ist false
  • Position und Größe auslesen und, sofern vorhanden, setzen

Es gibt einen Sonderfall, den meine Lösung nicht berücksichtigt. Verschiebt man ein nicht maximiertes Fenster oder ändert seine Größe, maximiert es danach, und beendet dann die Anwendung, so erscheint das Fenster nicht an der erwarteten Position und in der erhofften Größe, wenn man nach einem Neustart die Maximierung aufhebt. Deshalb bietet es sich an, auch Positions- und Größenänderungen des Fensters zu überwachen, und die Werte im nicht maximierten Zustand zu sichern.

Ein Tipp zum Schluss: Stages können noch einige weitere Zustände haben, die man unter Umständen persistieren und wiederherstellen möchte…

2015-06-20

Hätten Sie’s gewusst? Project ThreeTen

Das Java-Ökosystem ist so riesig, dass man eigentlich gar nicht alles kennen kann… Zumindest ging mir das so mit ThreeTen. Ziel dieses Projekts war die Implementierung von JSR 310 Date and Time API in das JDK 8. Dies ist seit geraumer Zeit abgeschlossen; das Projekt wurde beendet. Die Weiterentwicklung findet in den bewährten OpenJDK-Prozessen statt. Spannend ist aber, dass es einen Backport für Java SE 6 und 7 gibt. Dieser lässt sich dank Maven leicht in eigene Projekte integrieren:

<dependency>
  <groupid>org.threeten</groupid>
  <artifactid>threetenbp</artifactid>
  <version>1.2</version>
</dependency>

Ich habe mich gefragt, ob sich die neuen Zeit- und Datumsfunktionen auch unter Android nutzen lassen. Und siehe da – es funktioniert. Sie können in Android Studio entweder Maven Central als Repository hinzufügen, oder einfach die .jar-Datei händisch herunterladen und in den libs-Ordner kopieren. In diesem Fall müssen Sie mit Add As Library (Rechtsklick auf die Datei) dafür sorgen, dass Android Studio sie in das Buildfile übernimmt. Probieren Sie danach einfach das folgende Codeschnipsel aus:

private void time() {
    LocalDateTime now = LocalDateTime.now();
    System.out.println(now.toString());
    LocalDate bd = LocalDate.of(1970, Month.AUGUST, 29);
    System.out.println(bd.toString());
}

Bei der Übernahme von Codebesipielen für JSR 310 müssen Sie nur eine Kleinigkeit beachten: der Paketname des Backports ist org.threeten.bp.

2015-06-06

Clip4Moni Downloads

Clip4Moni-LogoClip4Moni ist open source, kann deshalb jederzeit aus Bitbucket geklont werden. Aber vielleicht möchten Sie das Progrämmchen ja einfach nur ausprobieren. Da ist klonen und selber bauen vielleicht etwas mühselig. Deshalb stelle ich seit heute zwei fertige Archive bereit. Für Windows gibt es ein gezipptes .msi-File. Die  wenigen Dateien landen nach der Installation in AppData\Roaming\Clip4Moni. Der Installer erzeugt zwei Verknüpfungen, eine unter Programme\Clip4Moni, sowie eine unter Programme\Autostart. Für den Mac habe ich ein App-Bundle geschnürt. Nach dem Entpacken einfach in den Programme-Ordner verschieben. Da Clip4Moni keine Java Runtime an Board hat, muss unter beiden Betriebssystemen die JRE vorher installiert werden. Es ist mindestens Java 7 erforderlich.

Nach dem Start befindet sich ein Clip4Moni-Icon unter Windows im Infobereich der Taskleiste, unter Mac OS X im rechten Bereich der Menüleiste. Auf dem Mac wird das Menü durch Anklicken mit der linken Maustaste geöffnet, unter Windows mit der rechten (das ist unter Java so vorgesehen!).

Das Clip4Moni-Popupmenü

Um einen neuen Eintrag anzulegen, klicken Sie auf Neuer Eintrag…. Daraufhin öffnet sich der gleichnamige Dialog. Sofern sich zu diesem Zeitpunkt Text auf dem Klemmbrett befindet, wird dieser als Inhalt übernommen. Beschreibung erscheint nach dem Schließen des Dialogs mit OK im Clip4Moni-Menü. Probieren Sie es aus und tippen Testeintrag in das Beschreibungsfeld. Tipp: klicken Sie doch einmal mit der rechten Maustaste, wenn sich der Mauszeiger über dem Feld Inhalt befindet.

Der Dialog Neuer Eintrag

Nun sieht das Menü so aus:

Clip4Moni-Menü nach dem Hinzufügen eines Eintrags

Möchten Sie in einer Anwendung ein Textschnipsel einfügen, klicken Sie den korrespondierenden Eintrag im Clip4Moni-Menü an, und wählen danach in der Zielanwendung Paste bzw. Einfügen. Das Menü Klemmbrett listet Operationen auf, die Sie mit dem Text auf dem Klemmbrett ausführen können.

Das Klemmbrett-Menü

Recht praktisch ist Inhalt anzeigen….

Der Dialog Inhalt anzeigen

Auch für das Bearbeiten bestehender Einträge gibt es einen Dialog. Er ist im Folgenden zu sehen:

Der Dialog Einträge bearbeiten

Clip4Moni gibt es schon recht lange, seit 2008. Wie der Name andeutet, war das Programm ursprünglich eine Spezialanfertigung für meine Frau. Da Moni möglichst kleine Programme mag, habe ich es immer schlank und schlicht gehalten. Deshalb gibt es zum Beispiel keine Tastenkürzel und keine Validierung. Gelegentlich bastle ich etwas daran, so dass das eine oder andere vielleicht doch noch hinzugefügt wird. Auf der anderen Seite… die Dateigröße der Archive spricht für sich, oder? Smiley

2015-06-05

Liebling ich habe die GUI geschrumpft

Zugegeben, es ist nicht mehr besonders hip, über AWT oder Swing zu bloggen. Auf der anderen Seite gibt es noch so viele Programme, die man gerne weiter benutzen möchte. Bei mir ist das unter anderem meine kleine Textschnipselverwaltung Clip4Moni. Unglücklicherweise macht(e) diese ungewollt auf ganz modernen Geräten mit high dpi-Anzeige keine besonders gute Figur. Das (bekannte) Problem ist, dass AWT und Swing alle Komponenten zu klein rendern. Das mag insbesondere bei AWT überraschen, weil native Komponenten doch eigentlich wissen sollten, wie sie sich korrekt darstellen müssen.

Screenshot von einem high dpi-Gerät

Mein Surface Pro 3 löst bei 12 Zoll Bildschirmdiagonale üppige 2160 x 1440 Pixel auf. Das sind 216 dpi. Auf dem Screenshot ist schön zu sehen, wie groß eine 9-Punkt Segoe UI bei einer Skalierung von 200% eigentlich sein müsste. Und wie lächerlich klein dagegen das AWT-Menü ist. Die Frage ist nun: kann man eine lesbarere Darstellung erzwingen, indem man dem AWT befiehlt, einen größeren Zeichensatz für Menüs zu verwenden? Die Größe von Fonts wird in Punkt angegeben; ein Punkt entspricht einem Zweiundsiebzigstel Zoll. Für die Segoe UI 9 Punkt wären dies bei 200% dann 18 Punkt. Welchen Zeichensatz AWT und Swing für Menüs verwenden, kann man auf zweierlei Weise abfragen: Font f = UIManager.getFont("MenuItem.font") oder Font f = (Font) Toolkit.getDefaultToolkit().getDesktopProperty("win.menu.font"). Letzteres liefert aber nur unter Windows ein Ergebnis.

Skurril ist, dass beide Abfragen auf meinem Rechner Segoe UI 18 Punkt liefern. Heißt das, dass der Workaround mit dem größeren Font nicht funktioniert? Aus Verzweiflung habe ich den gelieferten Zeichensatz mit setFont() für alle Einträge des Clip4Moni-Menüs gesetzt. Das Ergebnis ist überraschend:

Screenshot eines korrigierten Menüs

Sieht so aus, wie es soll.  Es reicht also, für jedes Menüelement explizit den Font zu setzen, den Java als Standard liefert. Noch sind in Clip4Moni die Swing-Dialoge zu klein, aber das müsste sich mit ähnlichen Workarounds ebenfalls beheben lassen.

2015-05-30

Seifenkisten wieder im Rennen


In meinem Post Seifenkisten auf Abwegen hatte ich von meinen frustrierenden Erfahrungen mit JAX-WS unter Android berichtet. Im aktuellen KaffeeKlatsch zeige ich, wie man mittels kSOAP auf recht einfache Weise doch noch auf SOAP-Services zugreifen kann.




2015-05-17

Know thy tags...

Mit den beiden Swing-Klassen RTFEditorKit und HTMLEditorKit lässt sich recht schnell ein einfacher HTML-nach-RTF-Converter schreiben. Wie, ist unter anderem in diesem Stackoverflow-Post beschrieben.

Aufpassen muss man allerdings bei einigen Tags. Zumindest <em> und <strong> werden nicht in RTF-Codes umgesetzt, man sollte sie also von Hand in <b> und <i> konvertieren.

2015-05-15

Mac OS X-Quicktipp: eingebauten Webserver nutzen

Mac OS X hat schon seit vielen Versionen einen eigenen Webserver an Board. Früher konnte man ihn über ein eigenes Modul in den Systemeinstellungen konfigurieren. Unglücklicherweise hat Apple es vor einiger Zeit entfernt. Der Webserver an sich ist aber noch vorhanden und funktoniert auch.

Bevor man ihn mit sudo apachectl start startet, legt man den Inhalt unter /Library/WebServer/Documents ab. Für den Schreibzugriff auf dieses Verzeichnis sind Admin-Rechte erforderlich.

Danach kann man im Browser mit http://localhost/... auf die Seiten zugreifen.

Weitere Kommandos für apachectl sind stop und restart.

Zwar bringen viele Tools und Sprachen ihren eigenen Webserver mit, aber ich finde, es ist gut zu wissen, dass man auch ohne Download schnell mal lokale Tests aufsetzen kann.

2015-05-14

Mac-Quicktipp: Schlagschatten in Screenshots loswerden

Kennen Sie das auch? Dinge, die nur ein klein wenig nerven, toleriert man recht lange. Bei mir waren das die Schlagschatten, die Mac OS X Screenshots hinzufügt. Dabei sind nur zwei Eingaben im Terminal nötig, um Bloggern das Leben leichter zu machen:

defaults write com.apple.screencapture disable-shadow true schaltet den Schlagschatten aus.

killall SystemUIServer sorgt dafür, dass die Änderungen übernommen werden.

2015-05-09

Living in the past (Teil 2)

In meinem vorherigen Post habe ich angedeutet, dass man unter neueren Android-Versionen Live Folder noch nutzen kann, obwohl Google die korrespondierenden Klassen mit API-Level 14 für veraltet erklärt und den Zugriff über den Home Screen ausgebaut hat.

Das Installieren einer App, die Live Folder bereitstellt, klappt selbst unter Android 5.1 noch reibungslos. Die beteiligten Frameworksklassen sind also (zum Glück) noch vorhanden. Eigentlich ist das auch logisch, denn das harte Entfernen hielte ich schon für einen ziemlich signifikanten Einschnitt. Über den Home Screen ist das Hinzufügen von Live Foldern aber nicht mehr möglich. Die Frage ist also, wie man Zugriff erhält. Hierzu muss man wissen, dass Live Folder keine Benutzeroberfläche bereitstellen, sondern nur die Daten, und zwar in Gestalt eines (auf eine ganz bestimmte Weise konfektionierten) Content Providers.

Die Idee ist deshalb, selbst für die UI zu sorgen, und den Content Provider einfach nach seinen Daten zu fragen. Die folgende Activity zeigt einen entsprechenden Proof of Concept, den ich Tin Opener genannt habe. Ich werde die App in den nächsten Tagen auf Bitbucket bereitstellen. Wenn das erledigt ist, füge ich diesem Post einfach einen Kommentar hinzu.

public class TinOpenerActivity extends ListActivity 
    implements LoaderManager.LoaderCallbacks<Cursor> {

    private static final String TAG = 
            TinOpenerActivity.class.getSimpleName();
    private static final int RQ_PICK_LIVE_FOLDER = 42;
    private static final int URL_LOADER = 0;

    private Uri uri;
    private String[] mFromColumns = {
            LiveFolders.NAME, LiveFolders.DESCRIPTION
    };
    private int[] mToFields = {
            android.R.id.text1, android.R.id.text2
    };
    private SimpleCursorAdapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setListAdapter(adapter = new SimpleCursorAdapter(this, 
                android.R.layout.simple_list_item_2, null, 
                mFromColumns, mToFields, 0));
        getListView().setOnItemClickListener(
            new AdapterView.OnItemClickListener() {

            @Override
            public void onItemClick(AdapterView<?> parent, 
                                    View view, int position, 
                                    long id) {
                Cursor c = (Cursor) adapter.getItem(position);
                if (c != null) {
                    String url = c.getString(
                        c.getColumnIndex(LiveFolders.INTENT));
                    if (url != null) {
                        Intent i = new Intent(Intent.ACTION_VIEW);
                        i.setData(Uri.parse(url));
                        startActivity(i);
                    }
                }
            }
        });
        Intent i = new Intent(LiveFolders.ACTION_CREATE_LIVE_FOLDER);
        Intent chooser = Intent.createChooser(i, 
                getString(R.string.choose));
        startActivityForResult(chooser, RQ_PICK_LIVE_FOLDER);
    }

    @Override
    protected void onActivityResult(int requestCode, 
                                    int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if ((RESULT_OK == resultCode) && 
                (RQ_PICK_LIVE_FOLDER == requestCode)) {
            if (data != null) {
                uri = data.getData();
                if (uri != null) {
                    getLoaderManager().initLoader(URL_LOADER, 
                            null, this);
                }
            }
        }
    }

    @Override
    public Loader<Cursor> onCreateLoader(int loaderID, 
                                         Bundle args) {
        switch (loaderID) {
            case URL_LOADER:
                return new CursorLoader(this, uri, 
                        null, null, null, null);
            default:
                return null;
        }
    }

    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
        adapter.changeCursor(data);
    }

    @Override
    public void onLoaderReset(Loader<Cursor> loader) {
    }
}

Die App TinOpener ist sehr einfach gestrickt. Sie besteht aus einer ListActivity, die ihre Daten von einem SimpleCursorAdapter bezieht. So wie sich das gehört, geschieht das Laden mit Hilfe eines Loaders im Hintergrund.

Die eigentlich spannende Frage ist, wie Live Folder gefunden werden. Hierfür baue ich ein Intent mit der Action LiveFolders.ACTION_CREATE_LIVE_FOLDER und lasse es auf die systemeigene Intent-Auswahl los. Sind mehrere Live Folder installiert, kann der Benutzer einen auswählen. Ist nur einer vorhanden, wird dieser automatisch angezeigt.

Statt in eine Activity könnte man dies auch in ein Appwidget packen. Na, hat jemand Lust darauf?

Nachtrag: Ja, das Listing enthält keine Kommentare... Ich werde dies in der Version auf Bitbucket nachholen. Und den Fall berücksichtigen, dass gar kein Live Folder vorhanden ist. Dann sollte zumindest ein entsprechender Hinweis erfolgen.

2015-05-07

Living in the past (Teil 1)

In diesem Post schwelgen wir in einer (weit zurück liegenden) Vergangenheit…

Android hat viele Features kommen und gehen sehen. Ein schönes Beispiel hierfür sind die sogenannten Live Folder. Diese wurden mit API-Level 3 (Cupcake) eingeführt und mit API-Level 14 (Ice Cream Sandwich) für veraltet erklärt. Hier ein paar Screenshots unter Android 2.3.7.

Tippen und Halten an einer freien Stelle des Home Screens öffnet das folgende Popup-Menü:

Live Folder #1

Tippt man auf Folders, öffnet sich ein weiteres Menü. Hier ist eine App von mir, die Live Folder zur Verfügung stellt, zu sehen. LiveFolderDemo war Bestandteil meines Buches Android 3.

Live Folder #2

In der Folgeauflage, Android 4, musste ich das Projekt schon wieder entfernen, da Google die API für veraltet erklärt und in der Entwicklerdoku mit deutlichen Worten von der Nutzung abgeraten hat:

Screenshot der Entwicklerdoku

Tippt man auf den Namen eines Live Folders, wird ein Icon auf dem Hintergrund des Home Screens abgelegt.

Live Folder #3

Das Antippen des Icons öffnet den Live Folder.

Live Folder #4

Ich habe auf Bitbucket ein Reopsitory abgelegt, das die App LiveFolderDemo enthält. Denn auch wenn man den Code in modernen Android-Versionen (eigentlich…) nicht mehr nutzen kann, wäre es doch schade, in einfach so zu löschen…

Und wenn Sie wissen wollen, was es mit eigentlich auf sich hat, warten Sie einfach auf einen der folgenden Posts.

2015-05-03

TKWeek 1.8.0

Nach einer etwas längeren Pause gibt es ein Update von TKWeek. Es waren ein paar Anpassungen an Lollipop nötig. Insbesondere die Navigation musste ich anpassen. Jetzt sollte aber wieder alles wie gewohnt funktionieren.

Screenshot TKWeek

2015-04-18

Android-Apps im Browser

Auf der Google IO 2014 wurde ein Proof of Concept gezeigt, der einige Android-Apps unter Chrome OS lauffähig machte. Im September desselben Jahres folgte dann eine erste Beta-Version der App Runtime for Chrome. Die Software basiert auf Googles Sandbox-Lösung Native Client. Seit einiger Zeit kann über den Chrome Web Store die Beta-Version einer App namens ARC Welder geladen werden. Das englische Verb to weld bedeutet schweißen – passend dazu zeigt das Programmsymbol den kleinen grünen Roboter mit Schutzbrille. Das Tool integriert eine .apk-Datei in die Laufzeitumgebung. Wie man hierzu vorgeht, ist auf den Chrome-Entwicklerseiten beschrieben. Als Appetithappen ein paar Screenshots:

ARC Welder Setup (1)
ARC Welder Setup (1)

ARC Welder Setup (2)
ARC Welder Setup (2)

ARC Welder Setup (3)
ARC Welder Setup (3)

Meine App TKWeek im Browser
Meine App TKWeek im Browser

Was Google mit ARC noch vorhat, ist nicht ganz klar. Tatsache ist, dass Besitzern von Chromebooks auf einen Schlag eine Unmenge an Programmen zur Verfügung stehen würde, wenn sie Apps direkt aus dem Play Store herunterladen könnten. Das Gleiche gilt für Windows-, Linux- und Mac OS X-Anwendern, die Chrome als Browser nutzen. Das Bundlen einiger weniger, vorausgewählter Apps würde doch den ganzen Aufwand kaum rechtfertigen, oder? Derzeit müssen .apk-Dateien einzeln installiert werden. Um ein Programm in die Laufzeitumgebung zu übernehmen, muss also das Installationsarchiv vorliegen. Dies wird Google dem klassischen Endanwender nicht zumuten wollen.

Note to myself: Ich muss bei Gelegenheit mal herausfinden, ob sich ARC-Apps kennen, oder jeweils in ihrer eigenen Welt leben.

Die Ausführungsgeschwindigkeit von TKWeek war auf meinem Surface 3 Pro übrigens recht gut. Dass ARC noch mit Stabilitätsproblemen kämpft, ist angesichts des Beta-Status völlig ok. Wie auch der Android-Emulator kämpft ARC derzeit mit der Hardwareanbindung: es stehen nur sehr wenige Sensoren zur Verfügung.

2015-04-14

Seifenkisten auf Abwegen

Der Zugriff auf (üblicherweise) leichtgewichtige REST-Webservices ist unter Android kein Problem – sein Java-Erbe verhilft dem kleinen grünen Roboter  zu einem ansehnlichen (Netz)Werk(zeug)-Koffer. Nur mit den (meist) etwas schwergewichtigeren SOAP-Webservices will es “out of the box” nicht so recht klappen. Zwar hat Java mit JAX-WS ab Java SE 6 entsprechende Klassenbibliotheken an Board, aber Androids Harmony-Spin-off ist irgendwie bei Java 1.5 stehen geblieben (naja, skurrile Erweiterungen und Portierungen mal außen vor gelassen). Glücklicherweise gibt es zu jedem Java Specification Request eine Referenzimplementierung. Bis einschließlich JAX-WS RI 2.2.6 ist “nur” Java SE 5 erforderlich. Warum also nicht einfach die Runtime-Bibliotheken mit einer Android-App ausliefern, und auf diese Weise auf SOAP-Services zugreifen können? Der Abschnitt Jar dependency der Release Notes listet auf, welche Bibliotheken der App hinzugefügt werden müssen. Eigentlich könnte man das Unterfangen an dieser Stelle abbrechen, denn die 18 Jars bringen üppige 4,8 MB auf die Waage. Wer möchte das schon als zusätzlichen Ballast mitgeben, “nur” um einen Webservice aufzurufen? Aber falls der Forscherdrang siegt, und man die Jars in das libs-Verzeichnis des Android-Projekts kopiert, wartet die nächste unangenehme Überraschung.

Screenshot: Fehlermeldung beim Hinzufügen eines Jars
Screenshot: Fehlermeldung beim Hinzufügen eines Jars

Google nennt den Versuch, Jars hinzuzufügen, die bestimmte Paket-Namensräume abdecken, “Ill-advised or mistaken usage of a core class” und unterbindet die Integration. Fairerweise muss man sagen, dass die Motivation durchaus legitim ist. Bestimmte Paketnamen sind eben der Standardklassenbibliothek vorbehalten. Schade nur, wenn sie dann nicht vorhanden sind. Glücklicherweise lässt Google dem Entwickler ein Hintertürchen offen, in Gestalt der Option --core-library, die man dem monierenden Tool (dex) übergeben kann. Wie, ist freilich kaum herauszubekommen. Ganz so einfach geht das nämlich nicht, wenn man mit Hilfe von Gradle baut. Hier ein Rezept, das zumindest bei mir funktioniert. In der Modul-spezifischen build.gradle-Datei ist folgendes Quelltextfragment einzufügen:

   dexOptions {  
     preDexLibraries = false  
   }  
   project.tasks.withType(com.android.build.gradle.tasks.Dex) {  
     additionalParameters=['--core-library']  
   }  

Jetzt klappt der Build zwar immer noch nicht, aber zumindest erhält man eine andere Fehlermeldung.

Screenshot: Fehlermeldung beim Build
Screenshot: Fehlermeldung beim Build

Auch dies bekommt man in den Griff, indem man build.gradle abermals erweitert:

   packagingOptions {  
     exclude "META-INF/LICENSE"  
   }  
   

Nun lässt sich das Projekt bauen und starten. Leider klappt der Zugriff auf den Webservice aber trotzdem nicht. In der Konsole findet man die Meldung, dass die Klasse java.awt.Image nicht gefunden wird.

Screenshot: Klasse java.awt.Image nicht gefunden
Screenshot: Klasse java.awt.Image nicht gefunden

Tja, schade. Wieder ein guter Zeitpunkt, das ganze sein zu lassen.

Zwinkerndes Smiley

Aber hey, warum nicht weiter forschen…? Dass es eigentlich nicht funktionieren kann, “einfach so” eine entsprechende Klasse zu bauen, ist logisch. Aber vielleicht lässt sich auf diese Weise ja herausfinden, was von java.awt.Image benötigt wird. Eine leere Implementierung lässt den Start-Vorgang dann auch etwas später abbrechen. Diesmal fehlt javax.activation.DataHandler. Diese Klasse gehört zum JavaBeans Activation Framework. Hierzu könnten Sie dessen activation.jar in das libs-Verzeichnis kopieren. Ich spare mir das und lege stattdessen wieder eine Dummy-Klasse an. Warum, sehen Sie gleich…

Screenshot: Fehler beim Initialisieren der Klasse DatatypeFactory
Screenshot: Fehler beim Initialisieren der Klasse DatatypeFactory

Diesmal schlägt das Initialisieren der Klasse DatatypeFactory fehl, weil eine andere (die Implementierungsklasse) nicht vorhanden ist:

Screenshot: Die Klasse org.apache.xerces.jaxp.datatype.DatatypeFactoryImpl ist nicht vorhanden
Screenshot: Die Klasse org.apache.xerces.jaxp.datatype.DatatypeFactoryImpl ist nicht vorhanden

Das ist sogar vergleichsweise einfach erklärbar, weil es so spezifiziert wurde. Die Doku der Klasse DatatypeFactory beschreibt den Initialisierungsvorgang, beim Aufruf der Methode newInstance(). Dort ist auch Folgendes zu lesen: “Note that you must supply your own implementation (such as Xerces); Android does not ship with a default implementation.” Die Idee ist nun, den Teil von Xerces hinzuzufügen, der die fehlende Klasse enthält. Es gibt sogar ein passendes Jar, xercesImpl.jar. Wiederstehen Sie aber der Versuchung, die Datei in das libs-Verzeichnis zu kopieren. Dann nämlich gibt es eine Fehlermeldung, die meiner Meinung nach mit dem zu alten Klassenformat der Binärdistribution zu tun hat. Der Bau von Xerces aus den Sourcen klappt auch nicht so ohne Weiteres, weil weitere Libs aus dem Apache-Fundus vonnöten sind.

Irgendwie frustrierend, oder? Es scheint einen vermeintlichen Rettungsanker zu geben, in Gestalt einer Android-Portierung von Xerces. Aber auch die hilft nicht, weil alle Paketnamen mit dem Präfix mf. versehen wurden. Deshalb findet DatatypeFactory die benötigte Implementierung DatatypeFactoryImpl nicht (sie befindet sich ja im Paket mf.org.apache.xerces.jaxp.datatype). Wenn Sie jetzt sagen “Dann nutze ich eben die Übergabe zum Beispiel mit System.setProperty()”, muss ich Sie wieder enttäuschen. Dann gibt es zur Laufzeit eine Exception, weil die Implementierung nicht von der originalen DatatypeFactory ableitet, sondern der aus einem Paket, das mit mf. beginnt.

Wie geht es jetzt weiter? Nun, ich habe als letzten Versuch die wenigen benötigten Klassen aus der Xerces-Source-Distribution in das Projekt kopiert. Damit wird tatsächlich alles gefunden. Glauben Sie, es funktioniert?

Screenshot: Noch eine Exception
Screenshot: Noch eine Exception

Man könnte natürlich noch analysieren, was es mit den IllegalAnnotationExceptions auf sich hat, aber darauf hatte ich dann doch keine Lust mehr. JAX-WS und Android mögen sich also offensichtlich nicht besonders gerne. Wie man aber doch noch auf SOAP-Services zugreifen kann, lesen Sie in einer der kommenden KaffeeKlatsch-Ausgaben.