Beiträge von Marco Feltmann

    Dafür mache ich jetzt aber keinen neuen Thread auf...


    Also meine DownloadAsyncTask().execute(URL... params); erwartet offenbar eine Liste von mehreren URL.
    Jetzt baue ich mir diese mehreren URL an Hand eines Keys aus einem Set zusammen.


    Wie bekomme ich dann jetzt diese mehreren URL als Parameterliste übergeben?


    Sagen wir der Einfachheit halber:

    Soweit ich da informiert bin benötigt Gingerbread mindestens 1GHz CPU und 512MB RAM.
    Mein Neo Freerunner dürfte eine ähnliche Leistung besitzen wie diese Uhr und da bekommt man standardmäßig ebenfalls ein 1.6


    Es gibt zwar ein Froyo (2.2.1) dafür, welches angeblich auf 400MHz bei 128MB RAM läuft - aber frag nicht nach Sonnenschein wie arschlahm das ist.
    Da die I'm Watch maximal 484MHz bei 128MB RAM hat, wirst du auch dort sicherlich nicht über 2.2.1 hinaus kommen.


    Alles in Allem ist das ein Heidenaufwand.
    Siehe http://gitorious.org/android-on-freerunner


    Fragen bezüglich der Umsetzung kannst du ja vielleicht auf der Google Group Seite loswerden:
    https://groups.google.com/foru…rum/android-on-freerunner


    Nur: wenn sich die Uhren nicht flashen lassen, dann kannst du es gleich vergessen. Und du kannst damit natürlich auch eine Menge kaputt machen.


    Aber mal am Rande: eine Standby Zeit von 48 Stunden ist doch wohl ein schlechter Witz, oder?

    [killphil]
    Danke für den Tipp mit den Views.
    Ich werde vermutlich dort mit dem ViewHolder arbeiten, da teste ich sowieso immer vorher, ob die Views noch existieren.
    Erschwerend hinzu kommt, dass diese Activity während des Downloads nicht verlassen werden kann. ;)


    Stimmt ich habe das Buch auch hier, der redet nur von Threads und den Rest lässt er unter den Tisch fallen. :(
    sehr unerfreulich.


    Insgesamt habe ich das Gefühl, dass der Herr Künneth für Android so ähnlich ist wie der Herr Hinzberger für iOS. Hilfreiche Dinge auslassen, mit Implementierungsdetails verwirren und schlimmstenfalls noch Falsches einbauen. +sigh+


    ich denke der asynctask ist hier in dem fall auch die beste wahl, meiner meinung nach auch nicht so "anspruchsvoll" wie die ios variante ^^


    Der Vorteil bei der iOS Variante unter iOS ist einfach, dass du stumpf alles komplett getrennt hältst.
    Jetzt habe ich noch locker zwei zusätzliche private Klassen in meiner .java rumfliegen, so dass die Activity selbst unübersichtlicher wird.
    Von den gefühlt 30 Imports reden wir gar nicht erst. ;)


    Insgesamt finde ich die strukturelle Trennung in Java recht ungünstig gelöst. Das ViewHolder Pattern gibt es in iOS Beispielsweise gar nicht, weil der Controller (ein Objekt) Referenzen zur Speicheradresse aller wichtigen Views aus der View-Hierarchie (ein Objektgraph) hat.
    Man könnte stilistisch behaupten, mein findViewById() würde entweder direkt zur Compilezeit fehlschlagen oder niemals. Das ist ja bei Activities nicht so gegeben... ;)


    Insofern ist das Delegating dort State-of-the-Art. Die Dereferenzierung des Delegateobjektes und anschließend der einzelnen Views passiert nahezu in notime.
    Der Hauptgrund, warum ich es erst versuche (ist ein bekanntes Anwendungsmuster) und dann immer auf die Nase falle. (auf Grund der gegensätzlichen Implementierung von Android läuft das hier nicht.)


    [Nur ein bissl blabla, falls mal wer auf die Idee kommt für iOS entwickeln zu wollen. Genauso, wie mir mein iOS Wissen hier nix bringt wird das mit dem Android-Wissen dort sein.]

    Warum nutzt du keinen AsyncTask ??? Dafür sind die doch gebaut worden.


    Weil ich just in diesem Moment von deren Existenz erfahre. ;)
    Mein Büchlein[1] schweigt sich darüber aus.


    Dann bastel ich mal, danke für den Tipp. :)


    (Erst mal soll es funktional sein, Code Cleaning kommt dann im Anschluss, wenn ich mich mit dem Thema einigermaßen auskenne.
    Und ich finde, dass ich in den letzten zwei Monaten doch ausreichend gelernt habe, um jetzt damit anfangen zu können.)


    --
    [1] Thomas Künneth: Android 3 Apps entwickeln mit dem Android SDK, Galileo Computing, 1. Auflage 2011

    Hallo,


    ich mal wieder. ;)


    Ich möchte gern im Hintergrund Daten herunterladen (genau genommen muss ich das tun... +knurr+).
    Während des Herunterladens der Daten soll ein AlertView schön den Fortschritt des Downloads anzeigen.
    (Das können 20 oder mehr MB sein, weshalb so ein Fortschrittsbalken definitiv eine gute Idee ist.)


    Ich habe es aktuell so gelöst, dass ich mir eine eigene Klasse DownloadManager gebastelt habe.
    Dieser bekommt eine Instanz des Interfaces DownloadManagerDelegate mit und an den kritischen Punkten sendet er seinem Delegate ein paar Informationen.
    Die kritischen Punkte wären die Folgenden im Interface definierten Punkte:

    Java
    public interface DownloadManagerDelegate {
        public void managerDidBeginDownload(DownloadManager downloader, long expectedBytes);
        public void managerDidReceiveData(DownloadManager downloader, byte[] data, long downloadedBytes, long expectedBytes);
        public void managerDidFinishDownload(DownloadManager downloader, long downloadedBytes);
        public void managerDidFailWithError(DownloadManager downloader, Error downloadError);
    }


    Nun ja, aus irgendwelchen Gründen befindet sich meine als Delegate übergebene Activity nicht im UI-Thread, so dass ich beispielsweise in der Implementierung der managerDidReceiveData(DownloadManager downloader, byte[] data, long downloadedBytes, long expectedBytes); in etwa wie folgt arbeite:


    Wo ich das so einfüge sehe ich, dass ich vielleicht mit dem HolderPattern noch etwas Performance rausholen kann.
    Wie dem auch sei, mir ist das alles zu langsam. Der Fortschrittbalken bleibt signifikant lange bei einem Wert, sagen wir '16%' stehen und hüpft dann quasi zu '53%'. Das sieht doof aus, zumal die Delegate-Methode alle 1024 Byte aufgerufen wird. Irgendwo hakt bei mir also die Performance.


    Wie ist das unter Android übliche Vorgehen, das UI gemäß Daten aus einem anderen Thread anzupassen?
    Mein von iOS bekannter Ansatz des 'Delegating' läuft hier offenbar träge bis gar nicht.
    (Das 'Delegating' unter Mac OS / iOS bedient mindestens das Command Muster.)

    naja die anzeige das traffic entsteh bzw wievielt kann man auch anders lösen.
    und was soll der user tun das die app abschmiert nur weil im hintergrund daten geladen werden?


    wenn iein gui element daten braucht die noch nicht vorhanden sind, wartet das gui element und es wird nen listener geschrieben der das gui element setzt sobald diese vorhanden sind.


    Eben. Und jetzt gehen wir einmal davon aus, dass die Daten initial geladen werden. Mein Element wartet also auf die Daten und ich habe beispielsweise 15 leere Listenfelder, die signalisieren, dass Daten geladen werden. Zu dieser Zeit kann auch niemand diese 15 leeren Listenfelder auswählen, da noch keine Inhalte da sind. Das UI ist zu diesem Zeitpunkt schlicht unbrauchbar. Idealerweise (ich gehe gern vom WCS aus) werden auch noch die untersten 10 Elemente zuerst geladen und bereit gestellt, so dass dem User sehr lange die sichtbaren 5 Listenfelder leer angezeigt werden. Der User starrte also gut 5 Sekunden auf nicht auswählbare leere Listenelemente und konnte das UI nicht benutzen.


    Meiner Meinung nach ist der Unterschied zu diesem Szenario und 'der User starrt 6 Sekunden auf einen Downloadhinweis und kann das UI nicht bedienen' offensichtlich: im letzten Fall weiß der User, dass er während das Updates die App nicht vernünftig bedienen kann. Im ersten Fall hingegen lässt sich seine App sporadisch für einige Sekunden einfach nicht bedienen, obwohl es so aussieht als ginge dies.


    Ich bekomme auch jedes Mal bei der Twitter App wieder die Krise, weil ich nicht weiß, ob sie mal wieder nen Fehler hat weil sie mir einen Gesprächsverlauf nicht anzeigt oder ob sie einfach nur noch mit Runterladen beschäftigt ist.

    Bei meinen Apps soll im Allgemeinfall das UI blockieren, wenn Daten geladen werden.
    Zum einen, damit der User weiß, dass da gerade Traffic auf seinem Gerät verursacht wird. Zum Anderen um auszuschließen, dass der User irgendwelche Dinge tun kann, die ein Fehlverhalten der App auslösen könnten.


    Ich finde es eine Frechheit, dass ich gezwungen werde, die Netzwerkaktivität in einem anderen Thread auszuführen wenn ich das überhaupt nicht will. ;)

    Nun, der Code bezüglich des Auslesens steht ja im zweiten Beitrag.
    Dort habe ich mir einfach im Log child.getNodeValue() ausgeben lassen und festgestellt, dass dort die ü schon fehlten.


    Dass die ü ein genereller Fehler sind, habe ich bereits festgestellt. Es ist ja quasi als Test drin, ob die Parser mit Fehlern gleich umgehen.


    Ich bekomme keinerlei Log-Ausgaben bezüglich des XML-Parsens, die ich nicht selbst abgegeben habe, außer:

    Zitat

    11-30 15:06:50.693: VERBOSE/BaseXMLParser#parse(787): done parsing xml


    Hast du den SAX oder den DOM Parser genutzt?
    Bei mir wird wie gesagt einfach alles inklusive des ersten Umlauts abgeschnitten...


    Der gesamte Parser sieht so aus:

    Hab noch ein bisschen weiter am XML gespielt und eine vernünftige DTD eingetragen sowie die UTF-8 als auch die HTML Entities verwendet.
    Die spannenden Ergebnisse hängen an.


    Das XML dazu sieht aus wie folgt:


    Also nicht großartig anders, nur dass ich den ursprünglichen Bodytext in eine Kurzbeschreibung umgebaut habe. Die Titel haben HTML-Entities, die Kurzbeschreibungen haben (wenn überhaupt) die UTF-8 codierten Entities.


    Man beachte beim ersten Bild (2.3) dass da kaum was stimmt und beim zweiten Bild (4.0), dass zwar die Umlaute in den UTF-8 Encodings sowie die XML-eigenen Entities dargestellt werden, die Umlaute in HTML-Entities hingegen nicht.


    An meiner Ursprungsfrage ändert das jedoch nichts:
    warum kann 4.0 die UTF-8 kodierten Zeichen als String ausgeben, während 2.3 an der Stelle abbricht?


    Da mir das Ganze nach einem gewaltigen Systembug in 2.3 und kleiner riecht, es aber noch immer zu weit verbreitet ist als dass man es wegfallen lassen könnte (was ich echt liebend gern täte... +seufz+): welche Stelle ist die Richtige, um ein erstelltes Testprojekt zur Darstellung dieses Bugs abzuliefern?


    [killphil75]
    Nein, den WebChromeClient habe ich nicht ausprobiert.
    Ja, das Encoding steht explizit auf UTF-8.
    Ja, ich nutze loadDataWithBaseURL(), weil ich mit loadData() nur Probleme hatte.


    Danke für den Tipp mit dem WebChromeClient. :)

    Die Umlaute als solche sind sichtbar, wenn ich sie im Klartext im XML eintipper.
    Aus Kompatibilitätsgründen mit einigen WebViews sind sie Umlaute in der XML halt UTF-8 HTML Encoded.
    Das beschriebene Encoding ist UTF-8, das Dateiencoding ist UTF-8 und Android 4.0 stellt die HTML-Encoded UTF-8 Chars vernünftig dar, nur Android 2.3 nicht.


    Fun fact: drehe ich den Spieß um und nehme statt UTF-8 kodierter HTML-Werte das normale HTML-Encoding (in diesem Fall beispielsweise ü), dann werden die derart formatierten Zeichen unter 2.3 einfach nur ausgelassen:


    Zitat

    Frhling
    Der Sandmann


    Im Übrigen ist das auch gar nicht mein XML.
    Mein XML hat immer entweder eine Inline-DTD oder eine importierte DTD, woher soll der Parser sonst wissen, was er damit alles tun kann?


    Ich werde also bei Zeiten mal mit dem Ersteller der XML verhandeln, ob man die Zeichen nicht einfach in Klartext in das Dokument bekommt.


    Nichts desto trotz wundert mich, dass dieselbe Implementierung bei derselben Datei auf unterschiedlichen OS-Versionen so eine unterschiedliche Darstellung zur Folge hat. Was wird mir noch alles begegnen? 8|

    WoW! Super Erklärung, könnten sich n paar ne Scheibe davon abschneiden :P


    Danke. :)


    Dennoch finde ich es eigentlich übertrieben, dass man diese Variablen zwingend als final deklarieren muss... man könnte ja immerhin mit try - catch arbeiten um das Problem zu umgehen.


    Welches Problem?
    Das Ändern von Listen ist ein Feature. Wenn die Liste also geändert wird, ist dies doch kein Problem sondern die ganz normale Benutzungsweise.
    Davon abgesehen würde dir schlimmstenfalls permanent eine ListDidChangeException um die Ohren fliegen - damit hättest du dann auch nichts gewonnen.
    Und wie würdest du darauf reagieren wollen? Einfach von vorn anfangen? Im schlimmsten Fall feuert dein Turm dann schlicht niemals.


    Ich persönlich bin übrigens überhaupt kein Freund dieser unsäglichen Threading-Geschichte.
    Android besteht beispielsweise darauf, dass Netzwerkaktivität im Hintergrundthread ausgeführt wird. Warum?
    Wenn _ich_ zeitintensive Netzwerkaktivität habe, dann, weil sie zum Gebrauch des Programms essentiell notwendig ist. Sprich: bevor das nicht durch ist, kann die Anwendung nicht bedient werden.
    Doch dank Androids Vorgaben muss ich im Hintergrund die aktualisierten Daten laden während ich meinen UI-Thread blockieren muss, damit der User nichts kaputtspielt.


    Nicht sehr klug gelöst, wenn man mich fragt. ;)


    Threads sollen Arbeiten übernehmen, die das UI auf Grund ihrer hohen Ausführungszeit blockieren würden.
    Mein UI soll blockieren, also brauche ich den Thread nicht.


    Ein Spiele-UI ist von vorn herein blockiert, zumindest aus Sicht des Betriebssystems. Ob es jetzt künstlich blockiert ist oder manuell blockiert wurde macht da doch keinen Unterschied.


    Im Prinzip läuft auch so ein TowerDefense eher rundenbasiert ab:
    1 Jedes Viech bewegt sich (entsprechend seiner Eigenschaften)
    2 Jeder Turm prüft ob er schießen kann (entsprechend seiner Geschwindigkeit)
    2.1 Turm schießt (entsprechend seiner Eigenschaften)
    2.2 getroffenes Viech prüft, ob es tot ist (entsprechend seiner Gesundheit und des Projektils)
    2.2.1 Beute wird dem Spieler zugeschrieben (entsprechend der Beuteeigenschaftes des Viechs und ggf. Boni des Turms)
    Fahre fort bei Schritt 1.0


    Das heißt, bevor deine Türme schießen können sollten sich die Viecher schon bewegt haben.
    (Meinetwegen auch anders herum: du schießt erst und sie bewegen sich dann.)
    Dann passiert nichts weiter, die Runde endet erst, wenn alle Türme prüften ob sie schießen konnten.
    Das kannst du in die Runnable des Turmes auslagern, solltest du aber nicht tun.


    Genau genommen baust du dir gerade gewaltige Code Smells ein.
    Du verletzt nicht nur das Paradigma der Kapselung, sondern verdrahtest auch Codeteile miteinander, die nichts miteinander zu tun haben.


    Beispiel: dein fünfter Turm KANN gemäß seiner Eigenschaften nur ein einziges Viech angreifen. Wieso sollte er von der Existenz anderer Viecher wissen?
    Wenn du dein Spielfeld mit Quadraten aufteilst (Gamefield Array), dann kennst du ja schon den Umkreis des Bereiches, den dein Turm überblicken kann.
    Warum gibst du ihm dann nicht einfach eine neue Liste mit allen Viechern in diesem Umkreis mit? Wenn er nur die Eigenschaft 'attackiere schwächstes Wesen' hat, dann gib ihm einfach an Stelle ALLER nur das Viech in seinem Umkreis mit der geringsten Energie mit.


    Du kannst schon bei der Erstellung der Listen so viel optimieren, dass du das Auslagern in einen anderen Thread überhaupt nicht benötigst.
    Schneller wird es dadurch eh nicht, da der Mainthread auf die Ergebnisse wartet. (a.k.a. wenn du geschossen hast, muss der UI-Thread das Zeichnen und Bewegen des Projektils übernehmen.)


    Auf Threading würde ich wirlkich nur dann zurückgreifen, wenn es Performanceengpässe gibt.

    Danke für den Tipp Kogoro.


    Ich fürchte nur, dass das eben dieser Bug ist. ;)


    Tausche ich im XML das 'Fr&#xFChling' gegen ein 'Frühling', dann passt es wieder.
    Auch werden mir nicht die Uppercase Umlaute abgeschnitten, sondern das Sonderzeichen mitsamt Rest gar nicht erst angezeigt.
    Außer, das Sonderzeichen ist an erster Stelle, dann wird nur der Rest nicht angezeigt.


    Anbei zwei Screenshots mit Testdaten.
    Die XML dazu sieht simpel und wie folgt aus:


    Moin,


    ich muss das noch mal ansprechen. ^^


    Das Problem scheint in dem Zusammenspiel der XML und den XMLParser Bibliotheken zu liegen.


    Die Umlaute im XML sind websafe als UTF-8 kodiert, also ü = ü und so weiter.


    Dieselbe Klasse mit dem javax.xml.parsers.DocumentBuilder liefert unter 2.3 allerdings nicht die Umlaute, die es unter 4.0 liefert.
    Stattdessen bricht es einfach ab.


    Wenn ich mir die Werte ausgeben lasse, fehlen die Umlaute bereits beim Abholen aus dem XML.
    Betreffende Zeilen Code:


    Der XML String "Frühling" bringt mir dann bei 4.0 das Ergebnis 'Frühling' und bei 2.3 das Ergebnis 'Fr'.
    Angeblich sei die Methode getNodeValue() bereits seit API 1 eingepflegt, so dass es natürlich schwer ist festzustellen, was sich da in deren Implementierung geändert hat.


    Hat jemand einen Tipp für mich, wie ich dieses Problem behoben bekomme?
    (Da Inhalte aus der XML aus einer Webquelle stammen und die Darstellung der Zeichen unter 4.0 ja keinerlei Probleme verursacht, würde ich ungern das XML auf 'irgend ein anderes Symbol als die UTF-8 Darstellung' umbauen müssen.)

    Also klappt das mit dem final? Sehr schön. :)


    Nun, final ist ein Schlüsselwort, das besagt: dies hier ändert sich nicht mehr.
    Wenn du etwas als final definierst und anschließend ändern willst, dann meckert jemand rum, dass das so nicht ginge.

    Java
    final int eins = 1;
    public void changeEinsToZwei()
    {
      eins = 2; // Cannot assign a value to final variable 'eins'
    }


    Threads greifen ja auf Objekte zu, so von außerhalb. Und Objekte lassen sich in Java ja generell verändern.
    Nicht nur, dass du aus eins 2 machen kannst, du kannst aus der ArrayList auch eine eigene List machen. Oder du kannst der ArrayList Objekte hinzufügen. Oder welche herauslöschen.


    Nun nehmen wir mal ein kreatives Beispiel:


    Sekunde 127 deines Spiels, deine Runnable prüft gerade, ob in der Liste der Viecher deines fünften Turms ein Viech dabei ist, dass er erreichen könnte.
    Dein Runnable ist an Position 6 der Liste, zwei kommen noch - als just in dem Moment drei der 8 Gegner von den Türmen 1, 2 und 4 zerfetzt werden.


    JETZT ist deine Liste plötzlich nur noch 5 Gegner groß, deine Turm-Runnable will aber gerade das sechste Viech aus dieser Liste holen - deine Anwendung stürzt gnadenlos ab.
    Andere Änderungen wären weniger gravierend: die Liste wird zu lang und die letzten drei Viecher, die gerade dazu kamen, werden nicht mitgezählt. Ist nur blöd, wenn der Turm direkt am Einstiegsbereich der Kreaturen steht.
    Oder zwei Kreaturen wurden zerfetzt, zwei kamen hinzu und du arbeitest einfach mit falschen Werten, indem du das Projektil in die Pampa feuerst.


    Das final sorgt dafür, dass dies nicht passieren kann. Die Liste hat beim Eintritt in die Runnable genau DEN Zustand, den sie zu dem Zeitpunkt hat.


    Problem: dein Turm bekommt nun überhaupt nicht mehr mit, dass die Viecher 1,2 und 4 zerfetzt wurden, die 0 es gerade so zum Ende geschafft hat und von hinten 18,19 und 20 angerückt kommen. Er ist immer noch auf dem Stand vom Eintritt in den Thread - und der muss nun wirklich nicht aktuell sein.


    Wenn du den ganzen Kram über die GameLoop abwickelst, dann kannst du sehr wohl einen turmspezifischen Run haben: das Ding wird 'rechtzeitig' ausgeführt und schaut einfach bei jedem Turm, ob er schon dran wäre. So kann Turm 1 dann die Liste mit 1,2 und 4 abarbeiten, während bei Turm 5 1,2 und 4 gar nicht mehr vorkommen, dafür aber 18,19 und 20 hinzu gekommen sind.

    Moin!
    Zunächst mal kenne ich mich mit der Spieleentwicklung so gar nicht aus, wenn also irgendwelche Konzepte da anders sind als im Normalfall bitte ich diese Fehlinformation zu entschuldigen.


    Ich weiß nicht, ob Listen im Speziellen und Collections im Allgemeinen überhaupt threadfähig sind.
    Da sie ja veränderbar sind gehe ich einmal davon aus das nicht.


    Warum möchtest du das in eine Runnable des Turmes packen?
    Für mich klingt es gerade sinnvoller, dem Turm eine Methode 'attackEnemy(Object theEnemy)' zu verpasse, in der RunLoop des Spiels das Array durchzuhangeln und dann die entsprechende Methode aufzurufen.


    Da dein Spiel in einer Endlosschleife laufen dürfte und du das System eh davon abhalten musst, dein Spiel als 'abgeschmiert' anzusehen, kannst du ja mit der Auslagerung der Aktionen warten bis die Performance wirklich nicht mehr stimmt.


    Andererseits fällt mir spontan ein:

    Java
    final List<Enemies> theEnemies = EinheitenListe;
    Runnable attackEnemy = new Runnable()
    {
      @Override
      public void run()
      {
        attackEnemiesInList(theEnemies);
      }
    };


    Die final definiert deine Liste ja als unveränderlich und damit sollte das klappen.

    Hier wäre Code hilfreich.


    Es klingt so, als würdest du mit dem ViewHolder Pattern arbeiten und bei der Darstellung der Children die Gravity ändern.
    Wenn du jetzt hoch scrollst wird das geänderte View übergeben und dementsprechend auch die falsche Gravity übernommen.
    Ich würde einfach versuchen, mich nicht auf das Layout zu verlassen sondern beim Bereitstellen des Views eben sein Gravity entsprechend deiner Anforderungen explizit zu setzen.