Kdo si J2ME, nezlobí – texty
Spolu s menu nám v předchozím článku přibylo několik textů a jejich náhodné roztroušení po zdrojovém kódu začíná být poněkud nepřehledné. Navíc, chceme-li aplikaci mít ve více než jednom jazyku, je načase se s texty vypořádat trochu jinak.
Více jazyků najednou?
Na tuto otázku odpovím rovnou záporně. Texty mohou zabrat přibližně 2 až 8 kB, což je u některých telefonů a aplikací příliš mnoho na to, abychom tuto velikost zabírali dvakrát nebo dokonce i vícekrát. Také je velmi málo pravděpodobné, že by na jednom telefonu bylo potřeba mít zároveň k dispozici více jazyků, a je tedy zvykem, mít při stahování aplikace na výběr z jednotlivých jazykových verzí.
Kam s texty?
Při nakládání s texty máme zhruba tyto možnosti umístění:
- přímo v kódu
- ve speciální třídě s textovými konstantami
- v deskriptoru aplikace
- ve speciálním souboru jako text
- ve speciálním souboru jako binární data
Každá z nich má své výhody a nevýhody, takže si je dále rozebereme trochu podrobněji. Podíváme se, jak je u jednotlivých přístupů lehké či komplikované změnit nějaký text nebo převést aplikaci do jiného jazyka.
Přímo v kódu
Tento způsob práce s texty jsme používali dosud, protože je nejjednodušší a tedy se při psaní programu přímo sám nabízí. U aplikací, které mají podporovat více jazyků nebo jsou rozsáhlejší, však tato metoda není vůbec vhodná.
Abychom převedli aplikaci do jiného jazyka, museli bychom najít všechny textové řetězce roztroušené všude ve zdrojovém kódu, nahradit je jejich překladem a aplikaci znovu přeložit. I kvůli změně jednoho řetězce bychom museli prohledat zdrojové kódy, už jen proto, abychom tento řetězec našli, a překladu aplikace se také nevyhneme. Zde je vidět, že je obecně lepší mít všechny textové konstanty na jednom místě.
Ve speciální třídě s textovými konstantami
public class Texts {
public static final String BACK = „Zpět“;
public static final String HELP = „Nápověda“;
public static final String HELP_CONTENT = „Šipkami jezděte …“;
public static final String PLAY = „Hrát“;
public static final String EXIT = „Konec“;
}
Toto je vylepšené předchozí řešení, kdy máme texty stále ve zdrojovém kódu, ale jsou umístěny všechny v jedné třídě, která slouží pouze jako skladiště textových konstant.
Nyní můžeme třídu obsahující konstanty vyrobit v několika verzích – co jazyk, to verze. Jazyk aplikace tak bude určen tím, která verze bude do aplikace zabalena.
Nevýhodou zůstává, že ke změně textu je potřeba znovu přeložit a sestavit aplikaci, takže tuto činnost musí dělat někdo, kdo „ví, co dělá“.
V deskriptoru aplikace
Jednoznačnou výhodou ukládání textů do deskriptoru aplikace je, že mechanismus na jejich načítání už J2ME obsahuje a nemusíme jej tedy programovat. Dále však následují i nevýhody:
- Různé telefony mají různě velikou maximální povolenou velikost deskriptoru aplikace.
- Délka jednotlivých řádků je omezená a některé telefony se neumí vypořádat se zalamovanými řádky deskriptoru aplikace.
- České znaky je potřeba ukládat v kódování UTF-8.
- I přes aplikaci předchozího bodu na některých telefonech některé české znaky nefungují.
Rozhodnete-li se přesto ukládat texty do deskriptoru, doporučuji udělat si předem průzkum, jak se k nim budou chovat cílové telefony.
Změnu textu nebo překlad aplikace do jiného jazyka může s texty umístěnými v deskriptoru provádět prakticky kdokoli, což zjednodušuje práci a umožňuje její dělbu.
Ve speciálním souboru jako text
Přenesením textů aplikace do speciálního souboru, který bude uložen uvnitř JAR souboru spolu s aplikací, se zbavíme většiny problémů, které jsou spojeny s ukládáním textů do deskriptoru aplikace, zůstane pouze poslední bod předchozího výčtu. Navíc ale budeme muset sami vyřešit načtení textů.
Pro jednoduchost a přehlednost zvolíme stejný způsob ukládání textů, jako má deskriptor aplikace. Každý řádek bude obsahovat dvojici klíč: hodnota
dělenou dvojtečkou. Načtení takto strukturovaného souboru do java.util.Hashtable
předvádí následující ukázka:
Hashtable texts = new Hashtable();
InputStream is = null;
InputStreamReader isr = null;
try {
// otevření zdrojového souboru
is = this.getClass().getResourceAsStream(„/texts.txt“);
// vytvoření instance InputStreamReader se zadaným kódováním UTF-8
isr = new InputStreamReader(is, „UTF-8“);
int i = isr.read();
StringBuffer buf = new StringBuffer();
String key = null;
while (i != -1) {
// zpracování dat, dokud nenastane konec souboru
char ch = (char) i;
if (ch != ‚\n‘ && (ch != ‚:‘ || key != null)) {
// načítání klíče nebo jeho hodnoty
buf.append(ch);
} else if (ch == ‚:‘ && key == null) {
// zpracování dvojtečky oddělující klíč
// od jeho hodnoty
key = buf.toString();
buf.delete(0, buf.length());
} else if (ch == ‚\n‘) {
// zpracování konce řádku
if (key != null) {
texts.put(key, buf.toString());
key = null;
}
buf.delete(0, buf.length());
}
// načtení dalšího znaku
i = isr.read();
}
// není-li poslední řádek ukončen znakem nového řádku
// je potřeba uložit poslední text zde
if(key!=null){
texts.put(key, buf.toString());
}
} catch (Exception e) {
} finally {
if(isr!=null){
// zavření instance InputStreamReader
try{
isr.close();
} catch(Exception e){
}
}
if(is!=null){
// zavření instance InputStream
try{
is.close();
} catch(Exception e){
}
}
}
V aplikaci pak uložíme všechny klíče jako konstanty do třídy GameMIDlet
a této třídě také přidáme metodu getText(String klíč)
, která vrátí hodnotu přiřazenou danému klíči.
Ve speciálním souboru jako binární data
Při tomto způsobu uložení dat jsem na žádné problémy s češtinou zatím nenarazila. To ovšem neznamená, že takto můžete použít libovolné znaky. Třeba jednoduchá uvozovka na Nokii 7650 neměla šanci.
Drobnou komplikací je, že lidsky čitelný soubor s texty je potřeba zkonvertovat do binárního formátu, ale jak jste si už asi všimli, ruční ošetřování všech odlišností pro jednotlivá zařízení a jazykové verze by bylo při tvorbě více aplikací příliš úmorné a poskytovalo by mnoho možností vzniku chyby. Proto se v budoucnu nějaké automatizaci chtě nechtě nevyhneme.
Ke konverzi textového souboru do binárního nám bude sloužit pomocná třída TextsToBin
. Načtení textového souboru pro jednoduchost uděláme stejně jako u předchozího příkladu. Uložení textů v binární podobě vypadá takto:
FileOutputStream fos = null;
DataOutputStream dos = null;
try{
// vytvoření výstupního proudu do souboru
fos = new FileOutputStream(outName);
// vytvoření datového výstupního proudu,
// který data posílá dál do
// souborového výstupního proudu
dos = new DataOutputStream(fos);
Enumeration enum = texts.keys();
// zapsání počtu textů
dos.writeInt(texts.size());
while(enum.hasMoreElements()){
// uložení klíče a pak hodnoty textu
String key = (String)enum.nextElement();
dos.writeUTF(key);
dos.writeUTF((String)texts.get(key));
}
} catch(Exception e){
e.printStackTrace();
} finally {
if(dos!=null){
// zavření datového výstupního proudu
try{
dos.close();
} catch(Exception e){
}
}
if(fos!=null){
// zavření souborového výstupního proudu
try{
fos.close();
} catch(Exception e){
}
}
}
Načtení textů v midletu je obdobné, jen se místo výstupních proudů používají vstupní proudy a místo zapisování texty čteme.
Hashtable texts = new Hashtable();
InputStream is = null;
DataInputStream dis = null;
try {
// vytvoření vstupního proudu ze souboru
is = this.getClass().getResourceAsStream(„/texts.bin“);
// vytvoření datového vstupního proudu, který
// čte data z výše vytvořeného vstupního proudu
dis = new DataInputStream(is);
// načtení počtu textů
int i = dis.readInt();
while(i>0){
// načtení textu
texts.put(dis.readUTF(), dis.readUTF());
i–;
}
} catch (Exception e) {
} finally {
if(dis!=null){
// zavření datového vstupního proudu
try{
dis.close();
} catch(Exception e){
}
}
if(is!=null){
// zavření vstupního proudu
try{
is.close();
} catch(Exception e){
}
}
}
Co zvolit?
Odpověď na tuto otázku závisí na tom, kolik aplikací budete vyrábět, kolik a jaká zařízení chcete podporovat a zda plánujete podporu více jazyků nebo nikoli. Pokud si píšete jednu aplikaci pro radost, po které chcete, aby běhala jen na vašem telefonu, klidně si pište texty někam do kódu a netrapte se obsahem tohoto článku. Máte-li větší ambice, budete muset zvolit některý z komplikovanějších přístupů. A třeba vymyslíte nějaké vlastní geniální řešení, na které jsem ještě nepřišla.
Ke stažení
Veškeré zde uvedené zdrojové kódy, obrázky ke hře a hotovou aplikaci si můžete stáhnout a použít pro vlastní potřebu.
Starší komentáře ke článku
Pokud máte zájem o starší komentáře k tomuto článku, naleznete je zde.
Mohlo by vás také zajímat
-
Monitory OLED: klíčové pojmy a funkce
13. května 2024 -
Co je to VRAM a jak ji navýšit bez drahého upgradu?
20. srpna 2024 -
Gaming na HDR monitoru: Stojí to za to?
12. srpna 2024
Nejnovější
-
Jak rozšířit úložiště Macu za pětinovou cenu?
16. prosince 2024 -
Nové trendy v doménách pro osobní projekty – DIY, LIVING a LIFESTYLE
9. prosince 2024 -
Jak chránit webové stránky před Web/AI Scrapingem
27. listopadu 2024 -
Jaký monitor je nejlepší k novému Macu Mini?
25. listopadu 2024