Mrz 202014
 

Um Ubuntu zu installieren muss man sich zunächst ein Image von Ubuntu herunterladen. Das findet man unter

http://www.ubuntu.com/download/desktop

Nun kann man das Image auf eine CD Brennen und den Rechner damit starten. Besser (und vor allem schneller) ist es das Image auf einen USB-Stick zu speichern.
Damit der Computer auch das Ubuntu von diesem Stick starten kann, muss dieser Bootfähig gemacht werden. Unter Windows gibt es das Tool UNETBOOTIN, dass diese Aufgaben für einen erledigt. Eine Anleitung findet ihr hier:

http://www.lidux.de/linux-tutorials/5-ubuntu-usb-stick-installieren-unetbootin.html

Nun könnt ihr Ubuntu als Livesystem vom Stick starten. Wenn ihr das System gestartet habt, könnt ihr es auch auf eurer Festplatte speichern.
Ist schon ein Betriebssystem drauf, kann man Ubuntu neben dem Betriebssystem installieren. Dazu gibt es noch einen Link und noch eine Anleitung:

http://linuxwelt.blogspot.de/2013/11/ubuntu-neben-windows-installieren.html

Viel Spass damit

Und für die ganz neuen ein kleiner Einsteiger-Artikel:
http://wiki.ubuntuusers.de/Einsteiger

Sep 062013
 

Neulich kam jemand mit einem Stück Code auf mich zu, der folgendem ähnlich war:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3.  
  4. void vergroessern(int* ptr, int size);
  5.  
  6. int main(void) {
  7.  
  8. int *p = malloc(2);
  9.  
  10. vergroessern(p, 5);
  11.  
  12. free(p);
  13.  
  14. return 0;
  15. }
  16.  
  17. void vergroessern(int* ptr, int size) {
  18.  
  19. ptr = malloc(size);
  20.  
  21. }

Er hat sich gewundert, warum er für den Zeiger p auf int nicht an der Funktion ‘vergroessern’ Speicher reservieren kann. Die Antwort da drauf ist simpel und kompliziert zugleich. Zeiger werden in C mittels Call-by-Referenz übergeben. Es wird also die Speicheradresse, auf die der Zeiger zeigt übergeben, nicht aber die Adresse, an der sich der Zeiger befindet. Der Zeiger *ptr in der Funktion ist folglich nicht der gleiche wie der Zeiger p in der main-Funktion. Allokiert man nun in der Funktion vergroessern neuen Speicherplatz für den Zeiger *ptr, hat das keinen Einfluß auf *p im main.

Um den Zusammenhang zu verdeutlichen, habe ich folgendes Programm erstellt:

  1. int main(void) {
  2.  
  3. int *p = (int[]) {1,3,4};
  4.  
  5. printf("---MAIN---\n" );
  6. printf("Inhalt von p: %d\n", *p);
  7. printf("p zeigt auf: %p\n", p);
  8. printf("Adresse von p: %p\n\n", &p);
  9.  
  10. vergroessern(p, 5);
  11.  
  12. free(p);
  13. return 0;
  14. }
  15.  
  16. void vergroessern(int* ptr, int size) {
  17.  
  18. printf("---vergroessern---\n" );
  19. printf("Inhalt von ptr: %d\n", *ptr);
  20. printf("ptr zeigt auf: %p\n", ptr);
  21. printf("Adresse von ptr: %p\n\n", &ptr);
  22.  
  23. }

Das Bild Illustriert nun das Problem. Der Pointer int* p zeigt zwar auf die gleiche Speicherstelle, jedoch ist per Call-by-Reference in der aufgerufenen Funktion, ein anderer Zeiger int *ptr angelegt worden, der auf die gleiche Speicherstelle zeigt. Änderungen, die man nun an dem Wert macht, auf den die Zeiger *p und *ptr zeigen bleiben auch nach verlassen der Funktion ‘vergroessern’ bestehen. Das ist aber auch alles. Den Zeiger *p kann man in der Funktion ‘vergroessern’ nicht manipulieren.

Visualisierung call_by_reference mit Zeigern

Call_by_reference mit Zeigern

Kann man trotzdem irgendwie auf die Adresse von int *p zugreifen

Nicht ohne Trick. Und der heißt Zeiger auf Zeiger.

  1. int main(void) {
  2.  
  3. int *p = (int[]) {1,3,4};
  4. int **ptr_ptr = &p;
  5.  
  6. printf("---MAIN---\n" );
  7. printf("Inhalt von p: %d\n", *p);
  8. printf("p zeigt auf: %p\n", p);
  9. printf("Adresse von p: %p\n\n", &p);
  10.  
  11. vergroessern(p, 5);
  12.  
  13. vergroessern_pointer_pointer(ptr_ptr, 5);
  14.  
  15. free(ptr_ptr);
  16. free(p);
  17. return 0;
  18. }
  19.  
  20. void vergroessern(int* ptr, int size) {
  21.  
  22. printf("---vergroessern---\n" );
  23. printf("Inhalt von ptr: %d\n", *ptr);
  24. printf("ptr zeigt auf: %p\n", ptr);
  25. printf("Adresse von ptr: %p\n\n", &ptr);
  26.  
  27. }
  28.  
  29. void vergroessern_pointer_pointer(int** ptr_ptr, int size) {
  30.  
  31. printf("---vergroessern_pointer_pointer---\n" );
  32. printf("Inhalt von **ptr_ptr: %d\n", **ptr_ptr);
  33. printf("*ptr_ptr zeigt auf: %p\n", *ptr_ptr);
  34. printf("ptr_ptr zeigt auf: %p\n", ptr_ptr);
  35. printf("Adresse von ptr_ptr: %p\n\n", &ptr_ptr);
  36.  
  37. }

Die Funktion ‘vergroessern_pointer_pointer’ erwartet einen Zeiger auf Zeiger. Damit kann man einen Zeiger übergeben, der auf die Speicherstelle in der sich der Zeiger int* p aus dem main befindet, zeigt. Nun kann man auch den Zeiger *p manipulieren. Den Rest überlasse ich der Fantasie und dem Forschungsdrang der Leser dieses Artikels.

Noch ein Bildchen zur Illustration:

Call_by_reference mit Zeigern auf Zeiger

Call_by_reference mit Zeigern auf Zeiger


 

Okt 242012
 

Der ein oder andere wird schon festgestellt haben, dass das debugen eines Programms das mit fork() mehrere Prozesse erzeugt,  unter Eclipse so ohne weiteres nicht geht. Meistens liegt es an den Einstellungen in den Debug-Configurations.

Diese passt man wie folgt an:

Man klickt mit der rechten Maustaste auf das Projekt, und wählt Debug as –> Debug Configurations

 

Dann wechselt man in den Reiter ‘Debugger’ und klickt die folgenden Optionen an. Was die machen findet man auf den Hilfeseiten des Eclipse CDT-Plugins.

 

 

Okt 202012
 

 

Strukturen, auch Records genannt, dienen dazu Variablen mit verschiedenen Datentypen in einem Verbund zusammenzufassen.

Strukturen definieren

Erstmal allgemein:

struct typbezeichner {
	typ komponente1 ;
	typ komponente2 ;
	typ komponente3 ;
	...
	...
        typ komponenteN ;
 };

Beispiel Struktur definieren (ohne zuweisen einer Variablen) :

  1. struct fahrzeug {
  2. char hersteller[20];
  3. char model[20];
  4. int kw;
  5. ...
  6. ...
  7. };

 

Beispiel Struktur für mehrere Variablen deklarieren.

  1. struct fahrzeug {
  2. char hersteller[20];
  3. char model[20];
  4. int kw;
  5. } kfz, lkw, motorrad;

Das gleiche erreicht man auch mit folgendem Code:

  1. struct fahrzeug {
  2. char hersteller[20];
  3. char model[20];
  4. int kw;
  5. };
  6.  
  7. int main(void) {
  8. /*deklaration von kfz, lkw, motorrad*/
  9. struct fahrzeug kfz, lkw, motorrad;
  10. ...
  11. ...
  12.  
  13. return 0;
  14. }

Man kann auch “anonyme” Strukturen deklarieren.

  1. struct {
  2. char hersteller[20];
  3. char model[20];
  4. int kw;
  5. } kfz, lkw, motorrad;

Strukturen initialisieren

oder: Wie kriege ich da jetzt Daten rein?

  1. struct fahrzeug {
  2. char hersteller[20];
  3. char model[20];
  4. int kw;
  5. };
  6.  
  7. int main(void) {
  8. /*deklaration von kfz*/
  9. struct fahrzeug kfz;
  10.  
  11. /*Chars in die Komponenten hersteller und model kopieren.*/
  12. /*** strcpy ist boese!!! besser strncpy benutzen!!! Dann gibts auch keine
  13.   Pufferueberlaeufe ***/
  14. strcpy(kfz.hersteller, "Citroen");
  15. strcpy(kfz.model, "DS4-THP200");
  16. kfz.kw = 200;
  17. ...
  18.  
  19. return 0;
  20. }

oder

  1. struct fahrzeug {
  2. char hersteller[20];
  3. char model[20];
  4. int kw;
  5. } kfz = {"Citroen", "DS4-THP200", 200};

oder auch Deklarieren und initialisieren in einer Funktion

  1. struct fahrzeug kfz = {"Citroen", "DS4-THP200", 200};

Strukturen selektiv initialisieren (seit C99 Standard)

Beispiel:

  1. struct fahrzeug {
  2. char hersteller[20];
  3. char model[20];
  4. int kw;
  5. };
  6.  
  7. int main(void) {
  8. /*initialisierung von kfz*/
  9. struct fahrzeug kfz {
  10. .hersteller = "Citroen", /*initialisiert hersteller*/
  11. "DS4-THP200" /*initialisiert automatisch model anhand der Reihenfolge in der Struktur*/
  12. /*kw wird nicht initialisiert. Wird automatisch auf 0 gesetzt.*/
  13. };
  14.  ...
  15.  
  16. return 0;
  17. }

 

  1. struct fahrzeug {
  2. char hersteller[20];
  3. char model[20];
  4. int kw;
  5. };
  6.  
  7. int main(void) {
  8. /*initialiserung von kfz*/
  9. struct fahrzeug kfz {
  10. "Citroen", /*initialisiert hersteller*/
  11. .kw = 200 /*hier ist der Bezeichner .kw notwendig, da vorher noch model kommt*/
  12. };
  13.  ...
  14.  
  15. return 0;
  16. }

Werte aus Strukturen lesen

Werte liest man mittels Punkt-Operator wieder aus. (Außer bei Zeigern auf Strukturen)

Beispiel:

  1. struct fahrzeug {
  2. char hersteller[20];
  3. char model[20];
  4. int kw;
  5. };
  6.  
  7. int main(void) {
  8. /*deklaration von kfz*/
  9. struct fahrzeug kfz;
  10.  
  11. /*Chars in die Komponenten hersteller und model kopieren.*/
  12. /*** strcpy ist boese!!! besser strncpy benutzen!!! Dann gibts auch keine
  13.   Pufferueberlaeufe ***/
  14. strcpy(kfz.hersteller, "Citroen");
  15. strcpy(kfz.model, "DS4-THP200");
  16. kfz.kw = 200;
  17.  
  18. printf("Hersteller: %s\n", kfz.hersteller);
  19. printf("Leistung; %d\n", kfz.kw);
  20.  
  21.  return 0;
  22. }

Zeiger auf Strukturen

Definiert man einen Zeiger auf Strukturen, so kommt der Pfeiloperator -> zum Einsatz.

  1. struct fahrzeug {
  2. char hersteller[20];
  3. char model[20];
  4. int kw;
  5. } kfz;
  6.  
  7. int main(void) {
  8. /*Zeiger auf sturktur fahrzeug definieren und kfz zuweisen*/
  9. struct fahrzeug *cit;
  10. cit = &kfz;
  11.  
  12.  /*Chars in die Komponenten hersteller und model kopieren.*/
  13. /*** strcpy ist boese!!! besser strncpy benutzen!!! Dann gibts auch keine
  14.   Pufferueberlaeufe ***/
  15. strcpy(cit->hersteller, "Citroen");
  16. strcpy(cit->model, "DS4-THP200");
  17. cit->.kw = 200;
  18. printf("Hersteller: %s\n", cit->hersteller);
  19. printf("Leistung; %d\n", cit->kw);
  20.  
  21. return 0;
  22. }

Grösse von Strukturen

Man könnte annehmen, Strukturen sind so groß wie die Summe der Größe der einzelnen Komponenten. So ist es aber nicht. Diese Tatsache ist der Organisation des Betriebssystems geschuldet. Meistens werden Strukturen in n-Byte (wobei n abhängig vom Betriebssystem ist) großen Fragmenten gespeichert, egal, wie groß die einzelnen Komponenten der Strukturen sind.

Deshalb muss man immer die sizeof – Operation durchführen, wenn man die tatsächliche Größe einer Struktur wissen muss.

 

Okt 142012
 

Immer wieder benutzen wir Aliase, die mittels Typedef definiert wurden.

Beispiel:

Die Funktion

  1. pid_t getpid();

liefert die PID eines Prozesses. Der Rückgabewert pid_t ist ein Typedef, das in der Headerdatei sys/types.h definiert ist. Untersucht man diesen Typdef näher stellt man fest das pid_t eigentlich vom Typ int ist (kann je nach System und Kernel variieren).

Typedef funktioniert wie folgt:

typedef typname alias

Beispiel:

  1. typedef unsigned int uint

Hier steht uint also stellvertretend für unsigned int.

Warum macht man so etwas?

Zum einen soll es die Lesbarkeit des Codes verbessern. Zum anderen, und das ist der wichtigere Aspekt, benutzt man das Alias als Datentypenvereinbarung. Das Alias ist nun unabhängig vom eigentlichen Datentypen. D.h. im Falle von pid_t müssen wir nicht wissen, welcher Datentyp hinter pid_t steckt. Wir können ganz einfach getpid() aufrufen. Ob es nun auf einem 16 Bit System nur einem short entspricht oder auf einem 32 Bit System einem int muss uns nicht interessieren. Das wurde schon in sys/types.h erledigt.

Okt 062012
 

Vorwort

Diese Sammlung entsteht für euch, ihr “Fork-Bomb-Bastler” ( siehe auch http://de.wikipedia.org/wiki/Forkbomb ). An die die mit dem letzten Satz einfach nichts anzufangen wissen: Seid versichert, ihr seid nicht gemeint.

Klartext: Ich unterrichte unter anderem Systemprogrammierung in C. Nun sitzen die C-Grundlagen nicht immer da, wo sie sein sollten. Nämlich in den Köpfen der Schüler. Darum gibt es diesen Artikel.

Kommandozeilenargumente in C

int main(int argc, char *argv[]) oder auch int main(int argc, char **argv)

Erschreckend aber war: Man kann einem C-Programm Kommandozeilenargumente übergeben. Auch wenn es den GUI-Mauszeiger-Schubsern von heute veraltet vorkommen mag, es ist immer noch die Regel. Vor allem in UNIXOIDEN Umgebungen.

Wie funktioniert das denn?

Startet man ein Programm in der Kommandozeile, kann man ihm Argumente mitgeben, die dann zur Laufzeit des Programms verarbeitet werden können. Kleines Beispiel:

ivan@yugosphere:/etc$ ls -a
In diesem Beispiel ist ls das Programm ( es macht das gleiche wie dir unter Windows, nämlich den Inhalt eines Verzeichnisses auflisten ) und -a ist das Argument.

Wie geht das in C-Programmen? Die main-Funktion ist mit zwei Parametern ausgestattet: int argc und char *argv[] (oder auch char **argv, das ist das gleiche )

  • int argc beinhaltet die Anzahl der Argumente
  • char *argv[] beinhaltet einen Vektor aus Zeigern auf char (ACHTUNG: Da ist je ein Zeiger auf ein char in den Vektorfeldern!) Da sind die übergebenen Argumente in String-darstellung drin!

Im ersten Vektorfeld argv[0] steht meistens der Programmname. Meistens! Das kann auch anders sein. Mittels der Funtion execv kann man den Vector argv direkt übergeben. Und wenn man da an erster Stelle eben nicht den (symbolischen) Programmnamen schreibt…..ätsch. In den Vectorfeldern >0 stehen die Argumente.

Gegeben sei folgender Programmaufruf (meinprogramm ist das Programm):

meinprogramm argumente nichts als argumente

Inhalt von argc: 5

Inhalt von argv: argv[0] –> meinprogramm, argv[1] –> argumente, argv[2] –> nichts, argv[3] –> als, argv[4] –> argumente

Wie gehe ich nun damit in C um?

Beispiel:

  1. /*Description: Dieses Programm erwartet ein Argument aus der Kommandozeile*, und gibt es dann aus.
  2. * Author: Ivan Kersevan */
  3. #define NULL ((void*) 0)
  4. #include <string.h>
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. int main(int argc, const char* argv[]) {
  8. /*Nicht initialisierte Zeiger immer mit NULL belegen, dann kann nichts dummes passieren"*/
  9. char* argument = NULL;
  10. /*Wir gehen davon aus, dass das erste Argument tatsaechlich der Kommandoname ist.*/
  11. /* Falls weniger als zwei Argumente vorhanden sind, fehlt ein Argument */
  12. if(argc<2)
  13. {
  14. printf("Es wurde kein Argument übergeben!");
  15. return 1;
  16. }
  17. /*Die Argumente sind in diesem Fall varaenderbar (const).
  18. *Deshalb müssen wir sie kopieren!*/
  19. /*Länge des übergebenen Strings ermitteln*/
  20. int stringlength = strlen(argv[1]);
  21. /*Platz reservieren*/
  22. argument = (char*) malloc( sizeof(char)*( stringlength+1 )) ;
  23. /*Falls kein Platz mehr frei ist*/
  24. if(argument == NULL){
  25. fprintf(stderr, "Kein Speicherplatz mehr frei");
  26. return 1;
  27. }
  28. /*zu sortierendes String in eine nicht const variable kopieren.*/
  29. strcpy(argument, argv[1]);
  30. printf("Uebergebenes Argument: %s\n",argument);
  31. free(argument);
  32. return 0;
  33. }

Es fällt auf, dass die Argumentenliste argv[] in diesem Beispiel const ist. Das ist eine gute Möglichkeit, um die übergeben Argumente vor Veränderungen zu schützen! Gehört zum guten Ton.

So. Den Rest müsst ihr schon selbst erforschen!

Apr 232012
 

Unter Android ist es relativ einfach ListActivities mit einem eigenen Layout zu kreieren. Dazu benötigt man lediglich einen eigenen ListAdapter, der ListItems in der View mit den gewünschten Daten füttert. Hier kann man aber auch verheerende Fehler machen und die Performance seiner App (oder zumindest der angezeigten Liste) in die Knie zwingen.

Dieses Beispiel zeigt eine App bestehend aus einer Activity, die unsere Liste darstellen soll. Im Menü kann man zwischen der “Guten”, also der Performanten, und der “Schlechten”  Liste umschalten. Die “schlechte” Liste ruckelt.

Adapter zur Darstellung von Daten in Views

Ein Adapter ist relativ schnell geschrieben. Hierzu stellt Android die abstrakte Basisklasse android.widget.BaseAdapter zur Verfügung. In meinem Beispiel habe ich zwei Adapter geschrieben. Der GoodListAdapter entspricht den Programmierregeln die Google vorschlägt. Siehe hier. Der BadListAdapter ist in Negativ-Beispiel das man leider in vielen Projekten findet.

  • GoodListAdapter
  1. package org.kersevanivan.BadListWithGC;
  2.  
  3. import java.util.ArrayList;
  4.  
  5. import android.content.Context;
  6. import android.view.LayoutInflater;
  7. import android.view.View;
  8. import android.view.ViewGroup;
  9. import android.widget.BaseAdapter;
  10. import android.widget.ImageView;
  11. import android.widget.TextView;
  12.  
  13. public class GoodListAdapter extends BaseAdapter {
  14. private ArrayList<SomeListData> _person = new ArrayList<SomeListData>();
  15. private LayoutInflater _layoutInflater;
  16.  
  17. public GoodListAdapter(Context context, ArrayList<SomeListData> person){
  18. _person = person;
  19. _layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
  20. }
  21. @Override
  22. public int getCount() {
  23. return _person.size();
  24. }
  25.  
  26. @Override
  27. public Object getItem(int position) {
  28. return _person.get(position);
  29. }
  30.  
  31. @Override
  32. public long getItemId(int position) {
  33. // TODO Auto-generated method stub
  34. return 0;
  35. }
  36.  
  37. /**
  38. * uses the given convertView, which is recycled.
  39. */
  40. @Override
  41. public View getView(int position, View convertView, ViewGroup parent) {
  42.  
  43. if (convertView == null) {
  44. convertView = _layoutInflater.inflate(R.layout.list_item, null);
  45. }
  46.  
  47. SomeListData p = (SomeListData) getItem(position);
  48. ((TextView) convertView.findViewById(R.id.text)).setText(p.getName());
  49.  
  50. int resource = p.getIcon();
  51.  
  52. ImageView image = (ImageView) convertView.findViewById(R.id.leftImage);
  53. image.setImageResource(resource);
  54.  
  55. return convertView;
  56. }
  57.  
  58. }

 

Entscheidend ist die Funktion  public View getView(int position, View convertView, ViewGroup parent){…}. Diese Funktion wird jedesmal aufgerufen, wenn das ListenElement am Bildschirm dargestellt werden soll. Also auch, wenn das ListenElement sichtbar war, herausgescrollt wurde, und wieder sichtbar wird, weil es hineingescrollt wird. Der Parameter View convertView ist der alte View, der dieses ListenElement hält. Es ist wichtig genau diesen wieder zu verwenden, und nicht, wie es im schlechten Beispiel BadListAdapter passiert, einen neuen View zu instantieren.

  • BadListAdapter
  1. package org.kersevanivan.BadListWithGC;
  2.  
  3. import java.util.ArrayList;
  4.  
  5. import android.content.Context;
  6. import android.view.LayoutInflater;
  7. import android.view.View;
  8. import android.view.ViewGroup;
  9. import android.widget.BaseAdapter;
  10. import android.widget.ImageView;
  11. import android.widget.TextView;
  12.  
  13. public class BadListAdapter extends BaseAdapter {
  14.  
  15. private ArrayList<SomeListData> _person = new ArrayList<SomeListData>();
  16. private LayoutInflater _layoutInflater;
  17.  
  18. public BadListAdapter(Context context, ArrayList<SomeListData> person){
  19. _person = person;
  20. _layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
  21. }
  22. @Override
  23. public int getCount() {
  24. return _person.size();
  25. }
  26.  
  27. @Override
  28. public Object getItem(int position) {
  29. return _person.get(position);
  30. }
  31.  
  32. @Override
  33. public long getItemId(int position) {
  34. // TODO Auto-generated method stub
  35. return 0;
  36. }
  37.  
  38. /**
  39. * Inflates for each list_item shown on the screen an own view.
  40. */
  41. @Override
  42. public View getView(int position, View convertView, ViewGroup parent) {
  43.  
  44. SomeListData p = (SomeListData) getItem(position);
  45. View view = _layoutInflater.inflate(R.layout.list_item, null);
  46. ((TextView) view.findViewById(R.id.text)).setText(p.getName());
  47.  
  48. int resource = p.getIcon();
  49.  
  50. ImageView image = (ImageView) view.findViewById(R.id.leftImage);
  51. image.setImageResource(resource);
  52.  
  53. return view;
  54. }
  55.  
  56. }

Jedes mal, wenn ein ListElement erscheint wird eine neue View-Instanz erzeugt. Das hat zur Folge, dass die View-Instanz, die vorher für die Anzeige der ListElemente zuständig war dem Garbage Collector zum Opfer fällt. Dieser benötigt jedoch viel Zeit, und bremst das System aus. Das kann man gut mit angeschloßenem Handy im LogCat der Entwicklungsumgebung beobachten.

  • Das Beispielprojekt

Das Beispiel Projekt erzeugt eine Liste aus zufälligen Icons und deren Bezeichnern. Man kann zwischen der Performanten und der schlechten Listendarstellung umschalten, in dem man das Menu aufruft.

Das Projekt kann als Eclipse (Version 3.7) Projekt heruntergeladen werden.

Das Projekt: BadListWithGC

  1. package org.kersevanivan.BadListWithGC;
  2.  
  3. import java.util.ArrayList;
  4.  
  5. import android.app.ListActivity;
  6. import android.os.Bundle;
  7. import android.view.Menu;
  8. import android.view.MenuInflater;
  9. import android.view.MenuItem;
  10. /**
  11.  * Demonstrates the difference between bad and good (Recycling Views) ListView techniques.
  12.  * @author Ivan Kersevan
  13.  *
  14.  */
  15. public class BadListWithGCActivity extends ListActivity {
  16.  
  17. private ArrayList<SomeListData> _someListData = new ArrayList<SomeListData>();
  18.  
  19. /** Called when the activity is first created. */
  20. @Override
  21. public void onCreate(Bundle savedInstanceState) {
  22. super.onCreate(savedInstanceState);
  23.  
  24. setContentView( R.layout.big_list );
  25. // generate some Data for our ListView.
  26. for(int i=0; i<100; i++)
  27. _someListData.add(new SomeListData());
  28.  
  29. }
  30.  
  31. @Override
  32. public boolean onCreateOptionsMenu(Menu menu) {
  33. MenuInflater inflater = getMenuInflater();
  34. inflater.inflate(R.menu.menu, menu);
  35. return true;
  36. }
  37.  
  38. @Override
  39. public boolean onOptionsItemSelected(MenuItem item) {
  40.  
  41. switch (item.getItemId()) {
  42. case R.id.bad_list:
  43. showBadList();
  44. return true;
  45. case R.id.good_list:
  46. showGoodList();
  47. return true;
  48. default:
  49. return super.onOptionsItemSelected(item);
  50. }
  51. }
  52.  
  53. private void showGoodList() {
  54.  
  55. GoodListAdapter ownArrayAdapter = new GoodListAdapter(this, _someListData);
  56. setListAdapter(ownArrayAdapter);
  57. }
  58.  
  59. private void showBadList() {
  60.  
  61. BadListAdapter ownArrayAdapter = new BadListAdapter(this, _someListData);
  62. setListAdapter(ownArrayAdapter);
  63.  
  64. }
  65.  
  66. }

 

  1. package org.kersevanivan.BadListWithGC;
  2.  
  3. import java.lang.reflect.Field;
  4.  
  5. import android.R.drawable;
  6.  
  7. /**
  8.  * Returns an random drawable icon and icon-name of the android.R.drawable.class using reflection
  9.  * @author Ivan Kersevan
  10.  *
  11.  */
  12. public class SomeListData {
  13.  
  14. // name of the drawable
  15. private String _name;
  16. // field in the android.R.drawable.class holding the iconResourceId
  17. private Field _field;
  18.  
  19. public SomeListData() {
  20. Class<drawable> drawableIds = android.R.drawable.class;
  21. Field[] fields = drawableIds.getFields();
  22. // Assumes that there are more then 100 members in drawable, and takes a random one.
  23. Double d = (Double) Math.random()*100 ;
  24. _field = fields[d.intValue()];
  25. _name = _field.getName();
  26. }
  27.  
  28. public String getName(){
  29. return _name;
  30. }
  31.  
  32. public int getIcon() {
  33.  
  34. int iconResourceId = 0 ;
  35. try {
  36.  
  37. iconResourceId = _field.getInt(_field);
  38.  
  39. // TODO Auto-generated catch block
  40. e.printStackTrace();
  41. } catch (IllegalAccessException e) {
  42. // TODO Auto-generated catch block
  43. e.printStackTrace();
  44. }
  45.  
  46. return iconResourceId;
  47.  
  48. }
  49. }

 

  1. package org.kersevanivan.BadListWithGC;
  2.  
  3. import java.util.ArrayList;
  4.  
  5. import android.content.Context;
  6. import android.view.LayoutInflater;
  7. import android.view.View;
  8. import android.view.ViewGroup;
  9. import android.widget.BaseAdapter;
  10. import android.widget.ImageView;
  11. import android.widget.TextView;
  12.  
  13. public class BadListAdapter extends BaseAdapter {
  14.  
  15. private ArrayList<SomeListData> _person = new ArrayList<SomeListData>();
  16. private LayoutInflater _layoutInflater;
  17.  
  18. public BadListAdapter(Context context, ArrayList<SomeListData> person){
  19. _person = person;
  20. _layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
  21. }
  22. @Override
  23. public int getCount() {
  24. return _person.size();
  25. }
  26.  
  27. @Override
  28. public Object getItem(int position) {
  29. return _person.get(position);
  30. }
  31.  
  32. @Override
  33. public long getItemId(int position) {
  34. // TODO Auto-generated method stub
  35. return 0;
  36. }
  37.  
  38. /**
  39. * Inflates for each list_item shown on the screen an own view.
  40. */
  41. @Override
  42. public View getView(int position, View convertView, ViewGroup parent) {
  43.  
  44. SomeListData p = (SomeListData) getItem(position);
  45. View view = _layoutInflater.inflate(R.layout.list_item, null);
  46. ((TextView) view.findViewById(R.id.text)).setText(p.getName());
  47.  
  48. int resource = p.getIcon();
  49.  
  50. ImageView image = (ImageView) view.findViewById(R.id.leftImage);
  51. image.setImageResource(resource);
  52.  
  53. return view;
  54. }
  55.  
  56. }

 

  1. package org.kersevanivan.BadListWithGC;
  2.  
  3. import java.util.ArrayList;
  4.  
  5. import android.content.Context;
  6. import android.view.LayoutInflater;
  7. import android.view.View;
  8. import android.view.ViewGroup;
  9. import android.widget.BaseAdapter;
  10. import android.widget.ImageView;
  11. import android.widget.TextView;
  12.  
  13. public class GoodListAdapter extends BaseAdapter {
  14. private ArrayList<SomeListData> _person = new ArrayList<SomeListData>();
  15. private LayoutInflater _layoutInflater;
  16.  
  17. public GoodListAdapter(Context context, ArrayList<SomeListData> person){
  18. _person = person;
  19. _layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
  20. }
  21. @Override
  22. public int getCount() {
  23. return _person.size();
  24. }
  25.  
  26. @Override
  27. public Object getItem(int position) {
  28. return _person.get(position);
  29. }
  30.  
  31. @Override
  32. public long getItemId(int position) {
  33. // TODO Auto-generated method stub
  34. return 0;
  35. }
  36.  
  37. /**
  38. * uses the given convertView, which is recycled.
  39. */
  40. @Override
  41. public View getView(int position, View convertView, ViewGroup parent) {
  42.  
  43. if (convertView == null) {
  44. convertView = _layoutInflater.inflate(R.layout.list_item, null);
  45. }
  46.  
  47. SomeListData p = (SomeListData) getItem(position);
  48. ((TextView) convertView.findViewById(R.id.text)).setText(p.getName());
  49.  
  50. int resource = p.getIcon();
  51.  
  52. ImageView image = (ImageView) convertView.findViewById(R.id.leftImage);
  53. image.setImageResource(resource);
  54.  
  55. return convertView;
  56. }
  57.  
  58. }
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="fill_parent"
  4. android:layout_height="fill_parent"
  5. android:orientation="vertical" >
  6.  
  7. <ListView
  8. android:id="@+android:id/list"
  9. android:layout_width="fill_parent"
  10. android:layout_height="fill_parent" >
  11. </ListView>
  12.  
  13. </LinearLayout>
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. android:orientation="horizontal" >
  6.  
  7. <ImageView
  8. android:id="@+id/leftImage"
  9. android:layout_width="43dp"
  10. android:layout_height="43dp"
  11. android:src="@android:drawable/sym_call_incoming"
  12. />
  13.  
  14. <EditText
  15. android:id="@+id/text"
  16. android:layout_width="match_parent"
  17. android:layout_height="wrap_content" >
  18.  
  19. <requestFocus />
  20. </EditText>
  21.  
  22. </LinearLayout>
menu.xml   
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <menu xmlns:android="http://schemas.android.com/apk/res/android" >
  3. <item android:id="@+id/bad_list"
  4. android:title="@string/bad_list"
  5. />
  6. <item android:id="@+id/good_list"
  7. android:title="@string/good_list" />
  8.  
  9. </menu>
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <resources>
  3.  
  4. <string name="hello">Hello World, BadListWithGCActivity!</string>
  5. <string name="app_name">BadListWithGC</string>
  6. <string name="bad_list">Bad list</string>
  7. <string name="good_list">Good list</string>
  8.  
  9. </resources>
Feb 152012
 

Merge from Branch to Trunk or from Trunk to Branch. Dieser Artikel basiert auf dem svnbook das hier zu finden ist.

Die Versions-Verwaltungssoftware Subversion bietet die Möglichkeit eine Verzweigung, also einen Branch, aus dem Hauptenwicklungsweig(trunk) zu erstellen. Hierbei wird die Kopie einer Revision erzeugt. Das folgende Bild (aus commons.wikimedia) zeigt wie ein solcher Graph aussehen kann. In diesem Artikel wird anhand der Revisionen erklärt, wie man einen Branch wieder in den Trunk merged. Dabei nehme ich die Revisionen 4-12 als Beispiel.
Subversion project visualization

Grundsätzlich muss man verinnerlichen, dass im Falle von Subversion Merging immer die Differenz ALLER Änderungen zwischen den Zweigen zusammen geführt werden muss. Vor diesem Hintergrund wird klar, dass es nicht genügt die Version 11 mit der Version 12 zu mergen, da Änderungen, wie Beispielsweise das Löschen einer Datei in Revision 10 im Branch nie passiert sind. Man muss also die Revisionen 6-11 mit dem Hauptenwicklungszweig mergen.

Merging mittels Kommandozeile

Bedingung für das Merge mittels Kommandozeile, ist das eine Arbeitskopie aus dem Trunk ausgecheckt wurde. Zunächst muss man ermitteln, in welcher Revision der Branch erstellt wurde. Das kann man einfach mittels

svn log –stop-on-copy http://svn.beispiel.org/repos/meinSuperProjekt/branch/meinPrivaterSpezialBranch

erreichen. Dieses Kommando zeigt den Log des SVNs und hört auf, wenn es merkt, dass die Dateien aus einem anderen Zweig kopiert wurden. Im Falles des Beispiels würde die Ausgabe r6 (kopiert von r4) anzeigen. Nun ist klar, dass die Revisionen 6 bis 11 in den Trunk gemerged werden müssen. Hierfür muss man in den Trunk der Arbeitskopie wechseln und erstmal mit

svn update

auf den neusten Stand updaten.

Dannach wird der Merge durchgeführt, in dem man

svn merge -r 6:11 http://svn.beispiel.org/repos/meinSuperProjekt/branch/meinPrivaterSpezialBranch

ausführt. Nun ist die lokale Arbeitskopie des trunks gemerged. Bevor man nun die Arbeitskopie eincheckt, muss man kontrollieren, ob der Merge konfliktfrei funktioniert hat, und, ob das Ergebniss auch den Erwartungen entspricht. Mit

svn status

erhält man die Stati der Dateien, also ob Konflikte entstanden sind, was gemerged ist usw. Wenn alles passt kann man mit

svn commit -m “Commit nach merging”

wieder alles wie gewohnt einchecken.

Merging mit graphischen Tools ( Bsp. Subclipse-Plugin für Eclipse )

Das Prinzip ist dasselbe wie oben beschrieben. Man muss den Bereich Abgeben der gemerged werden muss. Das Merge löst man am besten in der Arbeitskopie aus, in die gemerged werden soll,  Normalerweise sind diese Eingaben mit From: und To: markiert. Das ist NICHT zu verwechseln mit “Von Branch nach Trunk”. Wenn man darüber nachdenkt ist das ja auch Quatsch, da der Mergeimmer in die Arbeitskopie gemacht wird, auf der man gerade arbeitet.

Branch in Trunk mergen

Will man also vom Branch in den Trunk mergen, so muss man auf der Arbeitkopie des Trunks den Merge auslösen und in das Feld From: die Revision eintragen in der der Branch erstellt wurde und in das Feld To die Revision eintragen, aus der der Merge erfolgen soll. Die URL ist in Falle Branch -> Trunk immer die des Branches!

Trunk in Branch mergen

Das geht genau andersherum. Will man vom Trunk in den Branch mergen, so muss man auf der Arbeitkopie des Branches den Merge auslösen und in das Feld From: die Revision eintragen bevor der Branch erstellt wurde und in das Feld To die Revision eintragen, aus der der Merge erfolgen soll. Die URL ist in Falle Trunk -> Branch immer die des Trunks!

 

Feb 102012
 

Das SCP-Task für Ant erleichtert das Kopieren von Daten übers Netzwerk per SSH. Allerdings hängt es von einer Library ab, die man der Task erst geben muss. Hierzu lege ich in meinen Projekten einfach einen Ordner namens lib an, und kopiere in diesen alle Bibilotheken, die benötigt werden. Diese werden in mein Ant-Script mittels:

  1. <path id="classpath">
  2. <fileset dir="${basedir}/lib" includes="**/*.jar" />
  3. </path>

eingebunden.

Benutzt wird der SCP-Task wie im Manual beschrieben. [APACHE-SCP-MANUAL] Zum Beispiel so:

  1. <scp file="irgendeinedatei.endung" todir="user@somehost:/home/benutzer" password="password"/>

Die SCP-Task benötigt JSch Library, um eine SSH Verbindung aufzubauen. Diese kann man hier herunterladen. Benötigt wird mindestens Version 0.1.42. Fehlt diese Bibilothek, meldet die SCP-Task auf den Konsole foldenden Fehler.

  1. Problem: failed to create task or type scp
  2. Cause: the class org.apache.tools.ant.taskdefs.optional.ssh.Scp was not found.
  3. This looks like one of Ant's optional components.
  4. Action: Check that the appropriate optional JAR exists in
  5. -/usr/share/ant/lib
  6. -[Pfad zum Homeverzeichnis]/.ant/lib
  7. -a directory added on the command line with the -lib argument
  8.  
  9. Do not panic, this is a common problem.
  10. The commonest cause is a missing JAR.
Jan 242012
 

Unter Android wird die SeekBar grundsätzlich horizontal dargestellt. Wer eine vertikale Seekbar braucht, erreicht das, in dem er die SeekBar-Klasse beerbt und einfach um 90° dreht. Das geschieht in der onDraw(Canvas c) Methode.

  1. public class VerticalSeekBar extends SeekBar {
  2. private OnSeekBarChangeListener _seekbarListener;
  3.  
  4. public VerticalSeekBar(Context context) {
  5. super(context);
  6. }
  7.  
  8. public VerticalSeekBar(Context context, AttributeSet attrs, int defStyle) {
  9. super(context, attrs, defStyle);
  10. }
  11.  
  12. public VerticalSeekBar(Context context, AttributeSet attrs) {
  13. super(context, attrs);
  14. }
  15.  
  16. protected void onSizeChanged(int w, int h, int oldw, int oldh) {
  17. super.onSizeChanged(h, w, oldh, oldw);
  18. }
  19.  
  20. @Override
  21. protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  22. super.onMeasure(heightMeasureSpec, widthMeasureSpec);
  23. setMeasuredDimension(getMeasuredHeight(), getMeasuredWidth());
  24. }
  25.  
  26. @Override
  27. public void setOnSeekBarChangeListener(OnSeekBarChangeListener mListener){
  28. this._seekbarListener = mListener;
  29. }
  30.  
  31. protected void onDraw(Canvas c) {
  32.  
  33. c.rotate(-90);
  34. c.translate(-getHeight(), 0);
  35.  
  36. super.onDraw(c);
  37. }
  38.  
  39. @Override
  40. public boolean onTouchEvent(MotionEvent event) {
  41.  
  42. if (!isEnabled() || _seekbarListener==null) {
  43. return false;
  44. }
  45.  
  46. switch (event.getAction()) {
  47.  
  48. case MotionEvent.ACTION_DOWN:
  49. if(_seekbarListener!=null)
  50. _seekbarListener.onStartTrackingTouch(this);
  51. break;
  52.  
  53. case MotionEvent.ACTION_MOVE:
  54. int position = getMax() - (int) (getMax() * event.getY() / getHeight());
  55.  
  56. if(position<0)
  57. position=0;
  58. if(position>getMax())
  59. position=getMax();
  60.  
  61. setProgress(position);
  62. onSizeChanged(getWidth(), getHeight(), 0, 0);
  63. if(_seekbarListener!=null)
  64. _seekbarListener.onProgressChanged(this, position, true);
  65. break;
  66.  
  67. case MotionEvent.ACTION_UP:
  68. if(_seekbarListener!=null)
  69. _seekbarListener.onStopTrackingTouch(this);
  70. break;
  71.  
  72. case MotionEvent.ACTION_CANCEL:
  73. break;
  74.  
  75. }
  76.  
  77. return true;
  78.  
  79. }
  80.  
  81. }

Diese SeekBar kann man nun wie gewohnt per XML-Definition ins View einbinden. Die Namensräume in folgendem Listing müssen an die eigenen angepasst werden.

  1. <?xml version="1.0" encoding="utf-8"?>
  2.  
  3. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  4. android:id="@+id/LinearLayout"
  5. android:layout_width="wrap_content"
  6. android:layout_height="wrap_content"
  7. android:gravity="center" >
  8.  
  9. <org.kersevanivan.view.VerticalSeekBar
  10. android:id="@+id/impulse"
  11. android:layout_width="wrap_content"
  12. android:layout_height="fill_parent"
  13. android:max="100"
  14. android:progress="0" />
  15.  
  16. </LinearLayout>

Eigenes Design für die Android SeekBar erstellen

Wie man der SeekBar ein eigenes Design verpasst, findet man hier.