02.01.2012 - Abstände bei Bildern in Listen (Android 2.3.3)

Ich verwende für eine App eine ListView. Diese ListView wird mit Layoutelementen befüllt, die aus einem Bild links und einem Text rechts bestehen. Soweit so trivial. Eine Zeile muss dabei nicht immer ein Bild haben und es ist natürlich viel schöner, das Nachladen der Bilder über einen Task zu machen. Dieser Task lädt die Bilder von einem Server herunter, der sie vorher auf die gewünschte Größe skaliert hat.

public class DownloadImageTask extends AsyncTask {

 private final ImageView image;

 public DownloadImageTask(ImageView image) {
  this.image = image;
 }

 protected Drawable doInBackground(String... url) {
  return HttpUtil.getDrawableFromUri(url);
 }

 protected void onPostExecute(Drawable drawable) {
  if (drawable != null) {
   image.setImageDrawable(drawable);
  }
 }
}

Damit erhält ist das übergebene Drawable in onPostExecute immer ein 120×120 Pixel großes Bild. Sobald dieser Code allerdings durchgelaufen ist, sind über und unter dem Bild viel zu große Abstände. Mit Hilfe der View Hierarchie-Perspektive der Android-Tools für Eclipse konnte ich feststellen, dass das Drawable mit dem Bild eine Breite von 50 Pixeln und eine Höhe von 120 Pixeln hatte. Das erklärte den Abstand. Aber woher genau kommt er? Sehen wir uns doch mal den Code für das Bild an:

<imageview android:id="@+id/item_image" android:layout_width="50dp" android:layout_height="wrap_content"></imageview>

Dieser Code legt die Breite auf 50 Pixel fest, allerdings nicht die Höhe. Es gibt zwei Lösungen für das Problem.

  • Entweder man setzt die Höhe fest auf 50 Pixel. Das funktioniert allerdings nur bei quadratischen Bildern.

  • Oder man fügt ein android:adjustViewBounds="true" in den ImageView-Code ein. Damit werden die Bilder korrekt auf max. 50 Pixel Breite unter Einhaltung der Aspektrate skaliert.

19.12.2011 - mod_jk vs SELinux

Tomcat cluster hinter einem Apache HTTPd

Um einen oder mehrere Apache Tomcats hinter einen Apache HTTPd zu betreiben, gibt es verschiedene Protokolle. Ein häufig genutztes Protokoll ist das AJP/1.3-Protokoll (Apache JServ Protocol), da es Load-Balancing unterstützt. Da die SSL-Terminierung bereits im Webserver durchgeführt wird, sollte dieses Betriebsszenario nur verwendet werden, wenn der Kommunikationskanal zwischen HTTPd und Tomcat sicher ist.

Clustered tomcat setup

mod_jk

Das AJP/1.3-Protokoll unterstützt Tomcat von hause aus, für HTTPd wird es von mod_jk implementiert. Dieses Setup ist relativ einfach und wird von vielen Firmen so betrieben. Soweit die Theorie. In der Praxis wollte dies auf einer Distribution mit SELinux nicht funktionieren und ich fand folgenden Logeintrag:

connecting to backend failed. Tomcat is probably not started or is listening on the wrong port (errno=13)

Die Debug-Ausgaben von mod_jk ergaben, dass eine Verbindung zu 127.0.0.1:8009 fehlschlug. Zuerst hatte ich IPv6 in Verdacht. Also habe ich es erstmal deaktiviert:

echo 1 > /proc/sys/net/ipv6/conf/all/disable_ipv6

Dies brachte keine Besserung. Der Service lief jetzt zwar unter IPv4, telnet klappte, aber der Apache HTTPd wollte sich trotzdem nicht verbinden. Dann fand ich folgenden Logeintrag

[error] init_jk::mod_jk.c (3235): Initializing shm:/var/log/httpd/jk-runtime-status.16551 errno=13. Load balancing workers will not function properly.

Eine kurze Recherche ergabe, dass SELinux dazwischen funkt. Ich weiß nicht, warum SELinux bei manchen Distribution per Default aktiviert ist. Es zwar für die Sicherheit gut, aber bisher war die Toolunterstützung nicht leicht eingängig. Für einen Einsteiger ist es sehr schwierig, ohne einfache Übersicht (egal ob GUI oder Log-Datei) den Fehler zu finden und einzugrenzen. Meine Lösung ist es in der Datei ‚/etc/selinux/config‘ folgende Zeile einzufügen.

SELINUX=disabled

Anschließend funktioniert alles. Hinweis: Damit wird SELinux vollständig abgeschaltet. Für ein Entwicklungssystem im sicheren Netz ist dies vertretbar, diese Lösung sollte auf keinen Fall auf einem produktiv genutzen Server genutzt werden.

23.11.2011 - MyPaint Berg

Kürzlich habe ich mal wieder Lust dazu bekommen, mein Grafiktablett auszuprobieren. Daher habe ich diese kleine Szene gemalt:

Es ist das erste Mal, dass ich mit dem Tablet tatsächlich ein ansehnliches Ergebnis produziert habe. Das hat mit selbst etwas überrascht und ich bin dem etwas nachgegangen. Bisher habe ich das dem Table beiliegende Corel Essential 2 oder Gimp verwendet. Beide sind zwar nette Spielereien für Tablets, aber kommen darüber nicht hinweg. Da ich durch Zufall von MyPaint gehört hatte, wollte ich das mal ausprobieren. Ich muss sagen: Ich bin sehr zufrieden, denn die guten mitgelieferten Brushes sind der Grund, warum ich dieses Mal mehr als ein „Hallo, dies ist ein Test“ gemalt habe. Und natürlich, dass ich vor Kurzem in die Bob Ross DVD rein gesehen habe ;-).

22.09.2011 - Nachverfolgung eines Upstream-Projekts mit git

Bei der Softwareentwicklung sollte man möglichst nie das Rad neu erfinden. Dies gibt beispielsweise schon das DRY-Prinzip vor. Als Erweiterung des Prinzips sollte man sich nicht nur seine eigene Arbeit nicht wiederholen, sondern auch nicht die Arbeit von anderen. Daher werden in allen Softwareprojekten andere Softwareprojekte als Abhängigkeiten verwendet. Es kommt bei externen Abhängigkeiten manchmal zu dem Effekt, dass diese minimale Anpassungen benötigen.

Anpassungen an externen Projekten

Wir nehmen ein beliebiges Open Source Projekt, dass man zuerst anpassen muss, bevor man es benutzen kann. (Hinweis: Bitte vor der Anpassung die Lizenz des Projekts prüfen!). Wir nehmen einen Softwarestand des entsprechenden Projektes, passen den Stand an und verwenden die angepasste Abhängigkeit. Das Problem dabei: Wie übernimmt man seine Änderungen in neue Versionen?

Die Lösung dazu bietet sich im Versionskontrollsystem git. Die Idee ist sehr einfach, erleichtert das Vorgehen aber massiv. Zuerst importiert man den initialen Stand der Software (im unteren Beispiel „Release 1.0“). Diesen Stand brancht man in 2 Richtungen ab:

  1. Der Zweig mit dem offiziellen Stand der Software (upstream genannt)
  2. Der Zweig mit lokalen Änderungen (master)

Jetzt können im „master“ Branch wie gewohnt die notwendigen Anpassungen vorgenommen werden. Sobald eine neue Version der Software erscheint wechselt man in den „upstream“ Branch und importiert die neue Version. Sobald man mit git den Branch „upstream“ wieder in den „master“ merged, erhält man eine automatisch gepatchte Version mit den vorigen Änderungen. Eine meist enorme Zeitersparnis.

Hinweis: Natürlich ist es möglich (sofern das externe Softwareprojekt git als Versionskontrollsystem verwendet), den händische Import zu vermeiden. Der Arbeitsablauf selbst ändert sich dadurch aber nicht.

Unsauberer Start

Aber was macht man, wenn man erst zu spät feststellt, dass man dieses Vorgehen mit git so einfach ist? Nehmen wir an, wir haben einen Stand des Upstream-Projekts importiert und im gleichen Branch unsere Änderungen gemacht:

Ganz einfach: Man erstellt den Branch „upstream“ indem man ihn vom „master“ abspaltet. Jetzt wechselt man in diesen Branch, löscht den gesamten Inhalt und importiert den offiziellen Stand der Software (der zu dem Stand im „master“ Branch passt, d.h. wenn master eine angepasst Version von 1.0 ist, würde man die offizielle Version 1.0 importieren). Jetzt würde bei einem Merge natürlich das schlimmste Chaos entstehen. Daher muss man git ein wenig helfen. Wir behaupten einfach, dass alles, was derzeit im „upstream“ Branch steckt, bereits zurück in den „master“ gemerged wurde:

git checkout master
git merge -s ours upstream

Damit kann man dann genauso wie oben beschrieben arbeiten, also in „upstream“ immer den aktuellen Stand importieren und in den master mergen.

Dieser kleine Trick reduziert die Dauer von mehreren Stunden des händischen Vergleich der Änderungen auf wenige Minuten durch diese Automatisierung. Hinweis: Ein anschließendes Testen des angepassten Softwarestand ist allerdings trotzdem notwendig!

Änderungen an das externe Projekt zurückgeben

Grundsätzlich ist dieses Vorgehen einfach, aber aufwendig (je nach dem wie häufig das Einspielen einer neues Upstream-Version vorkommt). Ich versuche immer, die Änderungen an das externe Projekt zurückzugeben, selbst wenn die Lizenz dies nicht erfordert. Dies reduziert den lokalen Aufwand, stellt die (vermutlich hilfreiche) Anpassung allen anderen Nutzern zur Verfügung und motiviert die Betreuer des externen Projekts.

25.08.2011 - ArrayIndexOutOfBoundsException im maven-project-info-reports-plugin

Maven stellt verschiedene Werkzeuge im Umfeld von Java-Projekten zur Verfügung. Eines der Features ist die automatische Seitengenerierung mittels dem Maven-Goal site.

Ich hatte heute ein Problem mit der Seitengenerierung, bei der ich unter Anderem das maven-project-info-reports-plugin verwende. Dieses Plugin erzeugte bei jeden Aufruf eine ArrayIndexOutOfBoundsException im maven-project-info-reports-plugin, die nicht direkt zu deuten war:

java.lang.ArrayIndexOutOfBoundsException: 1
    at org.apache.maven.doxia.module.xhtml.XhtmlSink.tableCell(XhtmlSink.java:791)
    ....

Nach kurzer Recherche stellte sich heraus, dass die Version des maven-site-plugins zu alt war. Um eine neuere Version in einem Projekt zu verwenden, kann folgendes in die pom.xml des Projekts eingetragen werden:

<build>
 <plugins>
  <plugin>
   <groupId>org.apache.maven.plugins</groupId>
   <artifactId>maven-site-plugin</artifactId>
   <!-- Version 2.3 oder neuer wird für das maven-project-info-reports-plugin benötigt -->
   <version>2.3</version>
  </plugin>
 </plugins>
</build>

26.07.2011 - Brother DCP-585CW scanner on Linux

Nachdem mein alter Druckern leider kaputt gegangen ist, wurde er durch einen Netzwerkdrucker ersetzt. Damit ist es möglich, von jedem Rechner im lokalen Netzwerk zu drucken. Meine Wahl fiel auf Grund des guten Preis-Leistungs-Verhältnis auf einen Brother DCP-585CW. Dieser verfügt neben einem WLAN-Anbindung und einem Scanner auch noch Linux-Treiber.

Daher habe ich versucht den Scanner des Brother unter Linux zu benutzen. Brother stellt direkt offizielle Treiber für Linux zur Verfügung und beschreibt im Detail, wie man den Treiber installiert. Leider klappte die Verbindung zum Scanner nicht auf Anhieb. Die Anleitung von Ubuntuusers brachte keine Besserung, aber die Lösung fand ich im Gentoo Forum:

In der /etc/sane.d/dll.conf fehlte bei mir die folgende Zeile:

brother3

Danach funktionierte der Scanner endlich. Allerdings musste ich dann herausfinden, dass die Optionen von „scanimage“ wohl proprietär sind. Der alte Scanner kannte ‚–mode=Lineart‘, der neue Scanner verwendet ‚–mode=“Black & White“‚.

28.05.2011 - Dovecot und fetchmail ohne procmail

Ich habe vor kurzem ein IMAP-Mailserver auf Basis von Dovecot installiert. Dieser dient als Ersatz für mein vorheriges Setup auf Basis von Courier-IMAPd + Procmail. Der Hauptbewegrund war Sieve, eine modernes Mail-Sortier-und-Filter-System.

Bisher funktionierte mein Server so: fetchmail ruft die E-Mails ab, übergibt sie an den SMTP-Server postfix, der übergibt sie an procmail (der sie mit Hilfe der .procmailrc sortiert) und sie können dann über courier-imapd abgerufen werden. Das klingt nicht nur kompliziert, sondern ist es auch.

Jetzt funktioniert es einfacher: fetchmail ruft die E-Mails weiterhin ab, übergibt sie aber an dovecot (an den deliver LDA um genau zu sein) und wir sind fertig. Kürzer. Weniger fehleranfällig. Konfigurierbar über die managesieve-Erweiterung für Thunderbird (was der Hauptbeweggrund war, um von .procmailrc weg zu kommen).

Eigentlich sind dafür relativ wenig Konfigurationsoptionen notwendig:

  1. In der dovecot.conf im protocol lda as Sieve-Plugin aktivieren.

  2. In die /etc/fetchmailrc mda "HOME=/home/%T /usr/bin/sudo -u %T /usr/lib/dovecot/deliver" eintragen

  3. Mittels visudo folgenden Filter eingeben: fetchmail ALL=(ALL) NOPASSWD:/usr/lib/dovecot/deliver

Der einentliche Trick dabei ist es, dass fetchmail bei mir als globaler Service ausgeführt wird, und zwar als eigener Benutzer ‚fetchmail‘. Ein direkter Aufruf von deliver allerdings hat zur Folge, dass die E-Mails im Ordner des Fetchmail-Benutzers landen und nicht dem in der fetchmailrc konfigurierten(!). Diese kleine Information ist extrem entscheidend für das erfolgreiche Abrufen von E-Mails und hat mich ein paar Stunden des Grübelns gekostet. Jetzt funktioniert alles und ich kann endlich wieder E-Mails abrufen… und vor allem sortieren 🙂

30.09.2010 - Ogreopcode und Ogre 1.7

Ich bin derzeit mal wieder dabei an Opengate rumzuexperimentieren. Dazu benötige ich ogreopcode, einen Wrapper der Ogre (eine 3D Engine) mit Opcode (einer Bibliothek zur Kollisionserkennung). Allerdings war dieser nicht mit der neuesten Ogre Version (1.7.1) kompatibel. Daher habe ich folgende Ändernungen gemacht:

===================================================================
--- src/IOgreCollisionShape.cpp (revision 417)
+++ src/IOgreCollisionShape.cpp (working copy)
@@ -264,7 +264,7 @@
                if(!mHasCostumTransform)
                {
                        getParentSceneNode()->_update(true, true);
-                       getParentSceneNode()->getWorldTransforms(&mFullTransform);
+                       mFullTransform = getParentSceneNode()->_getFullTransform();
                }
                return mFullTransform;
        }
Index: src/OgreBoxCollisionShape.cpp
===================================================================
--- src/OgreBoxCollisionShape.cpp       (revision 417)
+++ src/OgreBoxCollisionShape.cpp       (working copy)
@@ -204,7 +204,7 @@

                calculateSize();

-               mParentNode->getWorldTransforms(&mFullTransform);
+               mFullTransform = mParentNode->_getFullTransform();
                //mFullTransform = mParentNode->_getFullTransform();

                return true;
Index: src/OgreMeshCollisionShape.cpp
===================================================================
--- src/OgreMeshCollisionShape.cpp      (revision 417)
+++ src/OgreMeshCollisionShape.cpp      (working copy)
@@ -287,8 +287,7 @@
                }

                mParentNode = mDummyNode;
-               //mFullTransform = mEntity->getParentSceneNode()->_getFullTransform();
-               mParentNode->getWorldTransforms(&mFullTransform);
+               mFullTransform = mParentNode->_getFullTransform();
                return rebuild();
        }

Das ist einer der großen Vorteile von Open Source: Wenn es nicht funktioniert, hat man die Chance herauszufinden warum nicht.

01.03.2010 - Nerdy-Lines Icons

Nerdy-Lines sind Icons für den Linux Desktop, die einen zeichnerischen Stil verwenden.

Ich habe eben gesehen, dass meine Nerdy-Lines Icons mittlerweile mehr als 100.000 Mal heruntergeladen wurden. Ich hatte sie eigentlich nur für mich erstellt und dachte nicht, dass das Interesse so groß ist. Daher freue ich mich um so mehr, dass die Icons eine sinnvolle Verwendung haben.

Nerdy-Lines

Nachtrag: Leider ist die Seite art.gnome.org nicht mehr verfügbar. Für alle Interessierten gibt es die Nerdy-Lines allerdings weiterhin zum Download.

05.07.2009 - Verwendung meiner Cliparts

Es freut mich immer wieder zu sehen, dass meine Arbeit nicht vollkommen ungenutzt bleibt. So habe ich heute abend folgendes bei Spiegel TV entdeckt.

Clipart Haus von Christoph Brill erstellt

Wie dort zu sehen ist, wurde ein Haus, dass ich für Lincity-NG entworfen habe, dort verwendet.

« Zurück 1 2 3 Weiter »
Copyright © christophbrill.de, 2002-2018.