zurück zum Artikel

App-Entwicklung für bada – ein Beispiel

Tam Hanna

Ein früherer Artikel führte in die Grundlagen der Entwicklung und den Vertrieb von Anwendungen für Samsungs Betriebssystem bada ein. Nun heißt es, tiefer in die Materie einzutauchen.

App-Entwicklung für bada – ein Beispiel

Ein früherer Artikel führte in die Grundlagen der Entwicklung und den Vertrieb von Anwendungen für Samsungs Betriebssystem bada ein. Nun heißt es, tiefer in die Materie einzutauchen.

Gegen Ende des letzten Jahres hat das koreanische Unternehmen Samsung weitere Informationen zum neuen Linux-System TiZen herausgegeben. Böse Zungen bezeichnen TiZen als Meego aus Korea – das ist nicht ganz falsch. Der wesentliche Unterschied besteht darin, dass die erste Version von TiZen keine eigene native API für Entwickler mitbringt. Stattdessen programmiert man à la WebOS in JavaScript, was nicht sonderlich befriedigend ist.

Der Exkurs des letzten Artikels [1] verdeutlichte, dass die sogenannte Open Service Platform (also bada) nicht allein als Betriebssystem anzusehen ist. Vielmehr sieht Samsung bada als API für C++, die ganz nach der Art von Qt vom zugrunde liegenden Kernel unabhängig ist. Das lässt diese Programmierumgebung geradezu prädestiniert erscheinen, als Basis für die native API von TiZen zu dienen. Samsung-Manager bestätigten diese (an sich logische) Überlegung auf mehreren Events. Die zum Zeitpunkt der Drucklegung aktuellste Meldung stammt aus dem Oktober 2012 und bestätigt die Intention der "Zusammenführung".

Im ersten Artikel hat sich der Autor darauf beschränkt, das Projektskelett zu besprechen. Das GUI-Framework der Open Service Platform enthält einige Module, deren Verwendung für Uneingeweihte alles andere als logisch ist. Listen sind besonders haarig, wie im Beispiel HeiseBada1 zu sehen ist.

Mehr Infos

Quellcode

Den Beispielcode zum Artikel finden Leser hier [2].

Der Inhalt des folgenden Lehrbeispiels ist das Verwalten einer Liste von Items, die der Benutzer je nach Wunsch ergänzen oder reduzieren kann. HeiseBada1 ist eine normale Anwendung vom Typ "bada Form Based Application", die aus zwei Formularen besteht. Im ersten Schritt öffnet der Entwickler IDF_FORM1.xml und entfernt den dort von Haus aus befindlichen Button. Stattdessen zieht er eine List View aus dem rechts eingeblendeten Tool-Dialog und legt sie in die Mitte des Formulars.

Obwohl man theoretisch auch auf "klassische" Buttons zurückgreifen könnte, sei hier aus Gründen der Eleganz eine Footer-Toolbar verwendet. Diese Information benötigt der Ressourceneditor – die Eigenschaft "Show Footer" findet sich in den Properties des Formulars (weder die Liste noch den Header markieren). Nachdem diese auf "True" gesetzt wurde, blendet der Editor sofort eine graue Fußzeile ein. Wenn der Entwickler die Eigenschaft wider Erwarten nicht findet, sollte er das selektierte Element in der Outline prüfen. Wenn IDF_FORM1 nicht markiert ist, ist das falsche Steuerelement aktiv.

Im nächsten Schritt ist der Footer zu parametrisieren, sodass er statt Tabs Knöpfe enthält. Dazu markiert man ihn und passt danach die Eigenschaft Footer Style an, sodass FOOTER_STYLE_BUTTON_TEXT selektiert ist. Die IDE zeigt daraufhin eine Warnmeldung an: Sie erscheint bei jeder Änderung des Footer Style, ist meist ohne Konsequenzen und wird durch Klick auf Yes quittiert. Damit ist der Footer zur Aufnahme von Elementen bereit. Danach zieht man drei Footer Items aus der Toolbar in den Footer. Das erste der drei wird als blauer, die zwei weiteren als graue Knopfsilhouetten dargestellt.

Die Footer Items sind im Prinzip nichts anderes als Buttons. Deshalb sind sie nun zu parametrisieren. Dafür sind die Text-Eigenschaften so anzupassen, dass drei Buttons mit den Texten "Add", "Edit" und "Remove" entstehen. Die IDs dienen der Korrelation der Klicks in den Event-Handlern. Es ist deshalb sinnvoll, jedem Element eine in diesem Formular einzigartige ID zuzuweisen. Außerdem ist darauf zu achten, dass die eigenen IDs nicht kleiner sind als 1001. Eine denkbare Zuordnung wäre "Add = 1001", "Edit = 1002", "Remove = 1003".

Im nächsten Schritt ist mit der Verdrahtung der Steuerelemente zu beginnen. Dazu öffnet man Form1.h und ergänzt die Klassendeklaration um drei Konstanten mit den zu verwendenden IDs:

protected:
static const int ID_FOOTER_ADD = 1001;
static const int ID_FOOTER_EDIT = 1002;
static const int ID_FOOTER_REMOVE = 1003;

Damit ist man in der Lage, die Events zuzuordnen. Leider hilft einem das nicht, da sie nirgendwo ankommen – der Footer hat noch keinen Event-Handler erhalten. Das holt man in der Methode OnInitializing nach, die während des Formularaufbaus aufgerufen wird:

result
Form1::OnInitializing(void)
{
result r = E_SUCCESS;

GetFooter()->AddActionEventListener(*this);

return r;
}

An der Stelle sieht der Leser ein fundamentales Pattern in bada: Von Haus aus hat kein Widget einen verdrahteten Event-Handler. Es ist immer die Aufgabe des Entwicklers, das Routing der Ereignisse vorzunehmen. Damit bleibt nur noch das Abfangen der Events. Da das Formular das Interface IActionEventListener schon implementiert hat, ist noch OnActionPerformed anzupassen:

void
Form1::OnActionPerformed(const Osp::Ui::Control& source, int actionId)
{
switch(actionId)
{
case ID_FOOTER_ADD:
{
AppLog("Add clicked \n");
}
break;
case ID_FOOTER_EDIT:
{
AppLog("Edit clicked \n");
}
break;
case ID_FOOTER_REMOVE:
{
AppLog("Remove clicked \n");
}
break;
default:
break;
}
}

In der Codepassage identifiziert der Leser den aktivierten Button und gibt seinen Namen in der Debugger-Konsole aus.

Der einfachste (und in Summe auch schnellste) Weg zum Testen einer bada-Applikation ist der im 2.0.x-SDK enthaltene Emulator. Dabei handelt es sich um eine virtuelle Maschine samt Hardwareemulation – der in den 1.x-Builds mitgelieferte Simulator (bada APIs für Win32) wird nicht mehr unterstützt.

Da die bada IDE auf Eclipse aufsetzt, bekommt der Anwender es auch hier mit dem Konzept der Debugger-Konfigurationen zu tun. Dabei handelt es sich um Einstellungen, die das Verhalten des Debuggers und des Compilers steuern. Das Erstellen der ersten Debugger-Konfiguration ist einfach. Durch Klicken auf den grünen Käfer öffnet der Entwickler den "Debug As"-Dialog. Dort wählt er bada Emulator Application und klickt auf Ok. Wenn ein Fehler vom Typ "Binary not found" erscheint, sind die Rekompilierung durch Klick auf das Hammer-Icon anzustoßen und der Prozess danach zu wiederholen.

Der Emulator schläft - er will wie ein echtes Telefon durch Druck auf "Power" aufgeweckt sein (Abb. 1).

Der Emulator schläft - er will wie ein echtes Telefon durch Druck auf "Power" aufgeweckt sein (Abb. 1).

Je nach Systemkonfiguration dauert der Start des Emulators bis zu eine Minute. Er verhält sich wie ein reales Handy, geht also nach einiger Inaktivität, wie in Abbildung 1 gezeigt, "schlafen".

Nach dem ersten Start des Emulators ist es oft notwendig, einen kleinen Einstellungs-Wizard zu erstellen. Danach erscheint die Applikation am Bildschirm. Die Ausgabe von AppLog sieht man im Output-Tab in der Perspektive "bada C++". Nach dem Beenden des Debuggings durch einen Klick auf die Auflegen-Taste des Emulators beendet dieser die Anwendungsausführung, läuft aber weiter. Das spart beim nächsten Start Zeit.

Zu beachten ist, dass insbesondere Haltepunkte alles andere als zuverlässig funktionieren. Mehrfaches Single Stepping ist ein sicheres Rezept für einen Absturz der zugrunde liegenden Debugger-Engine. Zum Fortsetzen des Testens sind dann zumindest die IDE, manchmal sogar der Rechner neu zu starten.

bada 2.0 kennt keine "primitiven" Listen. Die Logik zum Verwalten der Items muss immer der Entwickler stellen, die Liste kommuniziert mit ihrer Datenquelle über das Interface IListViewItemProvider. Insbesondere bei nicht allzu komplexen Formularen ist es sinnvoll, dieses Interface gleich in der Formularklasse zu implementieren. Dafür muss der Entwickler den Header Form1.h um folgende Passagen erweitern:

class Form1 :
public Osp::Ui::Controls::Form,
public Osp::Ui::IActionEventListener,
public Osp::Ui::Controls::IListViewItemProvider,
public Osp::Ui::Controls::IListViewItemEventListener
{

Aus Gründen der Bequemlichkeit implementiert der Autor hier sowohl den Item Provider als auch das Interface zum Einlesen von Listen-Events. Als Datenspeicher sei ein statisches Array aus maximal acht Elementen verwendet – es ist als Member der Klasse angelegt:

public:
Osp::Base::String item[8];
int itemCount;

Damit lässt sich mit der Implementierung der Listenverwaltungslogik beginnen. Als Erstes realisiert der Entwickler die Methode GetItemCount, die die Listen-Engine darüber informiert, wie viele Elemente im Speicher liegen:

int Form1::GetItemCount(void)
{
return itemCount;
}

Die einzelnen Elemente der Liste sind keine Text-Strings, sondern Steuerelemente. Es ist also durchaus möglich, ein eigenes Item zu realisieren. Erfreulicherweise liefert Samsung einige Templates mit, die die meisten Anwendungsfälle abdecken. CreateItem sieht deshalb so aus:

Osp::Ui::Controls::ListItemBase* Form1::CreateItem(int index, 
int itemWidth)
{
Osp::Ui::Controls::SimpleItem * pItem = new SimpleItem();
pItem->Construct(Osp::Graphics::Dimension(itemWidth, 100),
LIST_ANNEX_STYLE_RADIO);
pItem->SetElement(item[index], null);
return pItem;
}

Nach dem Aufruf erstellt CreateItem eine neue Instanz von SimpleItem. Wie die meisten bada-Systemobjekte verlangt diese Klasse eine zweistufige Initialisierung. Das bedeutet, dass die Anforderung des Speichers und die Parametrisierung in zwei separaten Aufrufen erfolgen.

Der Konstruktoraufruf firmiert unter dem Namen Construct(). Nun übergibt man als Parameter die Größe des Elements sowie den gewünschten Stil und weist danach noch den Text zu. Als Rückgabewert bekommt der Listenmanager den Pointer auf das fertige Objekt, das er nur noch auf den Bildschirm zeichnet.

Das Abtragen der Listenelemente ist kompliziert. Der Grund dafür ist, dass DeleteItem immer dann aufgerufen wird, wenn ein Listenelement-Objekt abgetragen werden soll – das hat nicht unbedingt Einfluss auf den Datenspeicher:

bool Form1::DeleteItem(int index, Osp::Ui::Controls::ListItemBase* 
pItem, int itemWidth)
{
if(myKillFlag==true)
{
myKillFlag=false;
itemCount--;
for(int i=index;(i+1)<9;i++)
{
item[i]=item[i+1];
}
}
return false;
}

Diese Methode aktualisiert den Datenspeicher nur, wenn das Kill-Flag gesetzt ist. Die Rückgabe von false weist das System dazu an, das Listenelement selbst abzutragen. Wenn der Entwickler das zu eliminierende Objekt selbst "erlegt", sollte er stattdessen true zurückgeben.

Nun fehlt noch die Verdrahtung der Liste mit dem Element-Array. Das erledigt man am effektivsten in OnInitializing:

result Form1::OnInitializing(void) { result r =
E_SUCCESS;

GetFooter()->AddActionEventListener(*this);

itemCount=3;
item[0]="Item A";
item[1]="Item B";
item[2]="Item C";

myKillFlag=false;

myList = static_cast<ListView *>(GetControl(L"IDC_LISTVIEW1"));
myList->SetItemProvider(*this);
myList->AddListViewItemEventListener(*this);


return r;
}
Die im Konstruktor erstellten Items erscheinen in der Liste (Abb. 2).

Die im Konstruktor erstellten Items erscheinen in der Liste (Abb. 2).

Dann wird das Listen-Array mit Daten befüllt, die Listeninstanz bekommt einen Item-Provider und einen Event-Listener zugewiesen. Der Aufruf von GetControl fördert das Steuerelement aus der Liste aller Widgets hervor – die ID des Steuerelements ist in der Ressourcendatei festgelegt. Damit ist das Programm einsatzbereit. Im Emulator sieht es wie in Abbildung 2 aus.

Obwohl das Programm nun funktionsfähig ist, hat es einen ärgerlichen Makel. Es ist möglich, mehrere Icons mit einem Haken zu markieren. Das Erzwingen der "Einzel-Selektion" ist Aufgabe des Entwicklers – eine gangbare Lösung sieht so aus:

void Form1::OnListViewItemStateChanged
(Osp::Ui::Controls::ListView &listView,
int index, int elementId,
Osp::Ui::Controls::ListItemStatus status)
{
//Uncheck all others
if(status==LIST_ITEM_STATUS_CHECKED)
{
AppLog("Checked!");
for(int i=0;i<myList->GetItemCount();i++)
{
if(i!=index)
{
myList->SetItemChecked(i,false);

}
}
}

OnListViewItemStateChanged prüft als Erstes, ob der Aufruf durch das Markieren eines Elements erfolgt ist. Ist dem so, deselektiert die for-Schleife alle anderen Items der Liste – auf diese Art ist immer nur ein Element gleichzeitig markiert. Die restlichen Handler sind für das Beispielprogramm uninteressant. Da die Namen der Methoden aussagekräftig gewählt sind, erschließt sich ihr Einsatzzweck aber aus der Logik.

Im nächsten Schritt soll das Löschen der Items in OnActionPerformed angelegt werden. Dazu sei folgendes Codeschnipsel verwendet:

case ID_FOOTER_REMOVE:
{
bool isFormulaFound=false;
for(int i=0;i<myList->GetItemCount();i++)
{
if(myList->IsItemChecked(i)==true)
{
isFormulaFound=true;
myKillFlag=true;
myList->RefreshList(i,LIST_REFRESH_TYPE_ITEM_REMOVE);
break;
}
}
if(isFormulaFound==false)
{
MessageBox msgbox;
msgbox.Construct("Bitte Item selektieren!", "Bitte wähle
ein Item aus!" ,MSGBOX_STYLE_OK, 10000);
int modalResult = 0;
msgbox.ShowAndWait(modalResult);
}
}
break;

Im ersten Schritt ist nach dem markierten Item zu suchen. Da es in bada keine Funktion zum Ermitteln aller selektierten Elemente einer Liste gibt, muss man die ganze Liste durchlaufen. Sobald ein markiertes Element gefunden ist, wird es entfernt. Von Zeit zu Zeit vergessen Anwender das Markieren eines Elements. In diesem Fall zeigt das Programm eine MessageBox an.

Zum Ändern und Hinzufügen von Items benötigt man ein zweites Formular. Erfreulicherweise ist es einfach, eine bada-Applikation in diese Richtung zu erweitern. Dazu muss der Entwickler die Ressourcendatei IDF_FORM1.xml öffnen, um die IDE in den Ressourcen-Editiermodus zu versetzen. Am unteren linken Teil des Bildschirms erscheint ein Ressourcenfenster. Nach dem Klick mit der rechten Maustaste auf den Ordner ScreenSize-Normal und im darauf erscheinenden Pop-up-Menü auf New Form reagiert die IDE darauf mit dem in Abbildung 3 gezeigten Formular-Wizard, der das Erstellen der neuen Ressourcendatei erledigt.

Die bada IDE erstellt Formulare automatisch (Abb. 3).

Die bada IDE erstellt Formulare automatisch (Abb. 3).

Die Bedienung des Dialogs ist einfach. Man markiert ScreenSize-Normal und gibt einen Formularnamen ein. Nach dem Klick auf Finish erscheint im Ressourcenfenster das neue Formular (s. Abb. 4).

Die Erstellung des Formulars ist so gut wie abgeschlossen (Abb. 4).

Die Erstellung des Formulars ist so gut wie abgeschlossen (Abb. 4).

Um das Formular endgültig anzulegen, muss man auf den mit dem Stern markierten Eintrag klicken. Wenn das neue Formular im Ressourceneditor geladen ist, klickt man auf das Speichern-Icon in der Toolbar. Daraufhin legt die IDE eine weitere XML-Datei im Ordner /res/ScreenSize-Normal an.

Zum Erstellen der Formularklassen gibt es einen kleinen Shortcut. Dafür muss man das Formular-Wurzelelement (IDF_FORM_*) in der Outline des Ressourceneditors rechts anklicken und im danach erscheinenden Menü die Option Add Class anwählen. Nach der Bestätigung des Dialogs erstellt die bada-IDE die Klasse samt dazugehörendem Header automatisch.

Im nächsten Schritt ist das Formular mit Steuerelementen zu befüllen. Diesmal sind sie aber nicht von Hand anzuordnen, diese Arbeit wird an die in bada integrierten Layout-Manager ausgelagert. Als Erstes muss der Entwickler dem System mitteilen, dass automatische Layout-Unterstützung benötigt wird. Dazu setzt er die Formulareigenschaft "Layout Style" auf LAYOUT_VERTICAL_BOX, um die Steuerelemente übereinander anzuordnen. Im nächsten Schritt bevölkert er das Formular, indem er nacheinander ein Label, ein EditField und zwei Buttons aus der Toolbar in den Formularkorpus zieht. Der Layoutmanager ordnet die Steuerelemente automatisch untereinander an, es ist nur noch die Breite anzupassen. Am Ende sollte das Formular ungefähr wie in Abbildung 5 aussehen.

Dieses Formular wird vom Layoutsystem verwaltet (Abb. 5).

Dieses Formular wird vom Layoutsystem verwaltet (Abb. 5).

Primitive Anwendungen verwalten ihre Formulare in der Applikationsklasse. Ergänzt sei die Klasse HeiseBada1 deshalb um einen Pointer auf Form_edit und um eine Referenz auf Form1:

class HeiseBada1 :
public Osp::App::Application,
public Osp::System::IScreenEventListener
{
public:
Form1 *pForm1;
Form_edit *pEditForm;

Die automatisch erstellte "temporäre Referenz" in OnAppInitializing wird durch einen Verweis auf die Member-Variable ersetzt. Ebenda wird auch das neue Formular initialisiert:

bool
HeiseBada1::OnAppInitializing(AppRegistry& appRegistry)
{
pForm1 = new Form1();
pForm1->Initialize();
pEditForm=new Form_edit();
pEditForm->Initialize();

Frame *pFrame = GetAppFrame()->GetFrame();
pFrame->AddControl(*pForm1);
pFrame->AddControl(*pEditForm);

pFrame->SetCurrentForm(*pForm1);

pForm1->Draw();
pForm1->Show();

return true;
}

Wichtig ist, dass alle bada-Formulare im Frame der Anwendung leben. Deshalb muss der Entwickler alle Formularinstanzen erstellen und danach ihre Initialize()-Methoden aufrufen, um die Konstruktoren auszuführen. Danach schreibt er die Formulare in den Frame. Zu guter Letzt aktiviert er das erste Formular und gibt es zum Zeichnen frei. Die Aktivierung des Editor-Formulars erfolgt in den Handlern der Add- und Edit-Buttons von Form1:

case ID_FOOTER_ADD:
{//Compiler whines re reuse
HeiseBada1 *anApp;
anApp=static_cast<HeiseBada1*>
(Osp::App::Application::GetInstance());
Frame *pFrame;
pFrame = anApp->GetAppFrame()->GetFrame();
pFrame->SetCurrentForm(*(anApp->pEditForm));
anApp->pEditForm->SetIDAndMode(true,0, this);
anApp->pEditForm->RequestRedraw(true);
}
case ID_FOOTER_EDIT:
{
bool isFormulaFound=false;
int i;
for(i=0;i<myList->GetItemCount();i++)
{
if(myList->IsItemChecked(i))
{
isFormulaFound=true;
break;
}
}
if(isFormulaFound)
{
HeiseBada1 *anApp;
anApp=static_cast<HeiseBada1*>(Osp::App::Application::GetInstance());
Frame *pFrame;
pFrame = anApp->GetAppFrame()->GetFrame();
pFrame->SetCurrentForm(*(anApp->pEditForm));
anApp->pEditForm->SetIDAndMode(false,i, this);
anApp->pEditForm->RequestRedraw(true);
}
}
break;

Auch zum Wechseln des aktiven Formulars benötigt der Entwickler den Frame. Die Referenz auf ihn bekommt er über die Singleton-Mutterklasse der Anwendung. Die erste Aufgabe besteht deshalb darin, einen Zeiger auf das Singleton zu erhalten. Danach setzt man das aktuelle Formular, schreibt die Eigenschaften und ruft RequestRedraw auf, um ein Neuzeichnen der geänderten Steuerelemente zu erzwingen.

Die Edit-Methode unterscheidet sich von Add nur insofern, dass sie statt eines leeren Elements den Index des selektierten Elements an den Editor weiterreicht. Dort wartet die Methode SetIDAndMode, die das Editorformular neu initialisiert:

void Form_edit::SetIDAndMode(bool _createNew, int _id, Form1* context)
{
myCreateFlag=_createNew;
myContext=context;
myID=_id;
EditField* TxtField = static_cast<EditField *>
(GetControl(L"IDC_EDITFIELD1"));
if(myCreateFlag)
{
TxtField->SetText("");

}
else
{
TxtField->SetText(myContext->item[myID]);
}
}

Die übergebenen Parameter werden ins Formular gespeichert, die TextBox bekommt den zutreffenden Text durch Aufruf der Methode SetText zugewiesen. Es muss nur noch der Editor geschlossen werden:

case ID_BUTTON_CANCEL:
{
HeiseBada1 *anApp;
anApp=static_cast<HeiseBada1*>
(Osp::App::Application::GetInstance());
Frame *pFrame;
pFrame = anApp->GetAppFrame()->GetFrame();
pFrame->SetCurrentForm(*(anApp->pForm1));
anApp->pForm1->RequestRedraw(true);
}
break;
case ID_BUTTON_OK:
{
HeiseBada1 *anApp;
anApp=static_cast<HeiseBada1*>
(Osp::App::Application::GetInstance());
Frame *pFrame;
pFrame = anApp->GetAppFrame()->GetFrame();
pFrame->RemoveControl(*(anApp->pForm1));
//Update base stack
if(myCreateFlag==true)
{
EditField* TxtField = static_cast<EditField
*>(GetControl(L"IDC_EDITFIELD1"));
myContext->item[myContext->itemCount]=TxtField->GetText();
myContext->itemCount++;
}
else
{
EditField* TxtField = static_cast<EditField
*>(GetControl(L"IDC_EDITFIELD1"));
myContext->item[myID]=TxtField->GetText();
}

Osp::Base::String item[8];
int itemCount = myContext->itemCount;
for(int i=0;i<8;i++)
item[i]=myContext->item[i];

//Redo form stack
anApp->pForm1=new Form1();
anApp->pForm1->Initialize();

//Restore data
anApp->pForm1->itemCount = itemCount;
for(int i=0;i<8;i++)
anApp->pForm1->item[i]=item[i];

pFrame->AddControl(*(anApp->pForm1));
pFrame->SetCurrentForm(*(anApp->pForm1));



anApp->pForm1->RequestRedraw(true);
}
break;

Sofern der Benutzer auf Cancel klickt, hat das Programm keine Arbeit. Es schickt den Editor wieder in den Hintergrund und zeigt stattdessen Form1 an. Bei einem Klick auf Ok werden Änderungen an der Liste erforderlich, was eine etwas komplexere Vorgehensweise erfordert.

Die von Samsung vorgesehene Methode des Anpassens von Formularen besteht darin, die Liste über die diversen Methoden über das Einpflegen und Ändern von Items zu informieren. In der Praxis ist es oft einfacher, das Formular komplett neu zu erstellen. Im Beispiel nutzt der Autor diesen Shortcut und erstellt eine neue Formularinstanz. Da die Item-Liste im Formular liegt, ist sie zwischenzuspeichern – in der Praxis würde man sie in die Applikations-Mutterklasse oder ein anderes globales Objekt auslagern.

Die Zuweisung der Event-Handler für die Buttons erfolgt in OnInitializing:

result
Form_edit::OnInitializing(void)
{
result r = E_SUCCESS;

// TODO: Add your initialization code here

CmdOk = static_cast<Button *>(GetControl(L"IDC_BUTTONOK"));
if (CmdOk != null)
{
CmdOk->SetActionId(ID_BUTTON_OK);
CmdOk->AddActionEventListener(*this);
}

CmdCancel = static_cast<Button *>(GetControl(L"IDC_BUTTONCANCEL"));
if (CmdCancel != null)
{
CmdCancel->SetActionId(ID_BUTTON_CANCEL);
CmdCancel->AddActionEventListener(*this);
}


return r;
}

Der Unterschied zu den vorher besprochenen Buttons im Footer besteht darin, dass die Buttons die Zuweisung der Event-ID zur Laufzeit erwarten. Bevor sich die Anwendung testen lässt, muss der Entwickler noch die Initialisierung des Arrays in OnInitializing entfernen, danach ist die Liste editierbar.

Zu beachten ist, dass die bada-Runtime nicht mehr als 30 Formulare gleichzeitig verwalten kann. Bei komplexen Programmen ist es deshalb sinnvoll, eine Art Formularmanager zu realisieren und die Formularklassen nach Bedarf zu erstellen und abzutragen – Beispiele dafür finden sich im
Internet.

Auch wenn der Emulator gut arbeitet, ist es manchmal unerlässlich, eine Anwendung auf einem echten Smartphone auszuprobieren. Insbesondere haptische Tests sind mit Maus und Tastatur nicht
machbar, außerdem ist die Performance des Emulators von der Host-Maschine abhängig und erlaubt keine Rückschlüsse auf das echte Telefon.

Der zentrale Schritt zum On-Device-Debugging-Smartphone ist das Installieren des Root-Zertifikats. Es findet sich im Installationsverzeichnis des SDKs unter C:\bada\2.0.5\Tools\sbuild\rootCACert.cer. Diese Datei muss auf das Telefon kopiert und danach im Dateimanager angeklickt werden – das animiert bada zum Installieren des Zertifikats. Von Haus aus verbindet sich das Telefon trotzdem weiter als USB-Speicher oder MTP-Gerät (Media Transfer Protocol). Je nach Netzbetreiber-Branding wird das Aktivieren des USB-Debugging-Modus etwas anders gehandhabt. Meist findet man die Einstellung bei den Optionen für USB.

Zu guter Letzt sei noch ein Blick auf Möglichkeiten zum Vertrieb von bada-Applikationen geworfen. Im Samsung App Seller Office können Softwarehersteller ihre Programme entweder zum kostenlosen Download oder aber zum Kauf anbieten. Die praktische Erfahrung lehrt, dass der Verkauf von Anwendungen unter bada nur höchst schleppend abläuft – die Konversionsraten von Spielen bewegen sich im nicht messbaren Bereich. Das Phänomen tritt selbst auf, wenn das Spiel Tausende von Downloads hat.

Eine durchaus brauchbare Alternative ist der von Samsung angebotene Werbedienst AdHub [3]. Bei der Anmeldung ist darauf zu achten, den richtigen Kontotyp zu wählen. Es ist nach der Erstellung nämlich nicht mehr möglich, zwischen Privatem und Unternehmenskonto umzustellen – in diesem Fall wären auch die in den Applikationen enthaltenen IDs anzupassen. Es ist deshalb sinnvoll, die Aktivierung des Kontos abzuwarten, bevor man mit der Implementierung der Werbefunktionen beginnt.

Wer seine mobile Reichweite optimieren möchte, macht mit einem Investment in diese Plattform nicht allzu viel falsch – wichtig ist nur, dass man bada nicht überbewerten sollte. Die Plattform bringt bei richtiger Anwendung eine überschaubare Anzahl loyaler, aber weitgehend zahlungsunwilliger User. Man kann aber auch über "Migrationseffekte" spekulieren – ein unter bada mit TouchCalc zufriedener User mag das Programm auch auf einem Android-Handy weiterverwenden ...

Tam Hanna
befasst sich seit der Zeit des Palm IIIc mit Programmierung und Anwendung von Handheldcomputern. Er entwickelt Programme für diverse Plattformen, betreibt Onlinenews-Dienste zum Thema und steht für Fragen, Trainings und Vorträge gern zur Verfügung.
(ane [4])


URL dieses Artikels:
https://www.heise.de/-1803837

Links in diesem Artikel:
[1] http://www.heise.de/developer/artikel/Ein-erster-Ausflug-in-die-App-Entwicklung-fuer-bada-1712174.html?artikelseite=4
[2] ftp://ftp.heise.de/pub/ix/developer/hanna_bada.zip
[3] http://www.samsungadhub.com/
[4] mailto:ane@heise.de