Beiträge von Marco Feltmann

    Ich glaube, ihr würfelt gerade 'layout' und 'contentView' durcheinander.
    Ein via XML definiertes Layout muss die Activity nicht haben. Wohl braucht sie aber einen ContentView.
    Dieses getLayoutInflater.inflate() sorgt ja nur dafür, dass aus dem via XML definierten Layout irgendwie die Root View extrahiert wird.
    Im nächsten Schritt würde diese dann via setContentView() gesetzt.


    Im Link wäre es dann ungefähr so:

    Java
    GestureOverlayView gestureOverlayView = new GestureOverlayView(this);
    gestureOverlayView.addOnGesturePerformedListener(this);
    setContentView(gestureOverlayView);


    Das GestureOverlayView hat jetzt natürlich kein unterliegendes View, sollte aber dennoch zumindest die Gesten abfangen.
    Falls nicht (beispielsweise, weil es ein View braucht um seine Grenzen zu sehen, bis wo hin es die Gesten auffangen soll), musst du programmatisch ein View mit den gewünschten Dimensionen erstellen und einhängen.
    Also einfach das, was dort mit layoutInflater.inflate() gemacht wird händisch nachbauen.

    Meine einzige Sorge dabei ist: in diesen(und vielen anderen) Tutorials werden Funktionen von Android benutzt, die laut Android schon veraltet und als "nicht mehr zu benutzen" markiert sind.... funktioniert ja trotzdem alles. Frage mich aber ob das gut ist eine neue App mit alten Funktionen zu schreiben.(?)


    Unter Android funktioniert das, auf der veräppelnden Seite der Macht führt das (aus gutem Grund) zu einer Ablehnung in den Stores.
    Du solltest derart markierte Funktionen also lieber sein lassen.


    Im Allgemeinen findest du aber zu allen deprecated Funktionen Hinweise darauf, wie du es besser machen kannst.
    Beispiel:

    Zitat

    SimpleCursorAdapter(Context context, int layout, Cursor c, String[] from, int[] to)


    This constructor was deprecated in API level 11. This option is discouraged, as it results in Cursor queries being performed on the application's UI thread and thus can cause poor responsiveness or even Application Not Responding errors. As an alternative, use LoaderManager with a CursorLoader.


    Für die Abwärtskompatibilität (sofern notwendig) muss dann halt die SupportLibrary herhalten. ;)

    Joah, ohne Client-Server-Architektur wird das vermutlich wirklich nix.


    Ich habe so etwas auch bereits gemacht, allerdings von einer iPhone Anwendung auf einen Windows-PC. (die Variante für den Mac war bereits fertig.)
    Solltest du den Server für Windows auf C# aufsetzen wollen, sei dir folgende Library ans Herz gelegt:
    WindowsInputSimulator


    Im Gegensatz zu den herkömmlichen Windowsfunktionen läuft das auch wunderbar via RDP und Citrix Session, wenn man da eine Kleinigkeit an der Library anpasst.
    (Man glaubt gar nicht, wie viele das wollen... MediaServer via RDP angesprochen oder sowas. +schüttel+)


    Eventuell kannst du da auch mit VNC was werden, das wäre dann Cross-Platform.
    Allerdings bekommen der durchschnittliche Mac- und Windowsnutzer das erfahrungsgemäß nicht ohne mehrere Stunden Support zum Fliegen.

    Ich persönlich würde eher davon absehen, die Kopien von Kontakten in eine eigene Datenbank zu werfen.
    Frauen heiraten, Familien ziehen um, man trägt Geburtstage nach oder ändert Kontaktbilder...
    Alles in Allem bin ich ein totaler Freund davon, Daten zentral abzulegen und darauf zuzugreifen.


    Statt der Kontakte würde ich lieber die Kontakt-ID in die Datenbank schreiben und dann an Hand dieser die Kontakte zur App-Laufzeit ermitteln.

    Sieht so aus als lieferte convertView.findViewById() nix, also ein null zurück - und zwar nur beim zu schnellen Scrollen.


    Mit dem ViewHolder pattern sollst du ja zu viel Rumgesuche via findViewById() vermeiden, hier machst du es aber permanent. Das halte ich für keine gute Lösung und offenbar bekommst du dadurch auch die Crashes.


    Leg dir diese Views lieber als Instanzvariable an oder pack sie dir mit als View in den ViewHolder.
    Dann musst du halt nur beim Zuweisen der Tags erst einmal prüfen, ob die Views auch ja nicht null sind.


    Ich würde übrigens auch das iconview deines ViewHolders beim Zuweisen des Separators nullen - die ConvertViews werden gern wiederverwertet und es kann durchaus passieren, dass dein Separator dann noch das vorherige Icon hat. Muss nicht zu Problemen führen, kann aber. Zumindest bei der Darstellung.

    1) Ja, das ist leider richtig. Java hat diese Unart, genannt 'Garbage Collection'. Das Ding ist auch 'Garbage', collected sich aber leider nicht selbst. ;)
    --
    Zur Erläuterung, damit das nicht als Meckern und Trollen aufgefasst wird:
    Gemäß diversen Prüfungen von Matthew Hertz und Emery D. Berger aus dem Jahre 2005 ist Garbage Collection im Vergleich zu manueller Speicherverwaltung ein Ressourcenfresser, dessen Aufwand in keinem Verhältnis zum Nutzen steht.
    (OOPSLA’05, October 16–20, 2005, San Diego, California, USA. Copyright 2005 ACM 1-59593-031-0/05/0010)


    Ich bin mir ziemlich sicher, dass die Jungs das völlig objektiv bewerten und einschätzen können.
    Falls jemanden diese Ausarbeitung interessiert:
    http://ebookbrowse.com/gcmalloc-oopsla-2005-pdf-d359475443


    Und zusammengekürzt für die tl;dr Fraktion der meiner Meinung nach wichtige Punkt aus dem Fazit:

    Zitat

    Comparing runtime, space consumption, and virtual memory footprints over a range of benchmarks, we show that the runtime performance of the best-performing garbage collector is competitive with explicit memory management when given enough memory. In particular, when garbage collection has five times as much memory as required, its runtime performance matches or slightly exceeds that of explicit memory management. However, garbage collection’s performance degrades substantially when it must use smaller heaps. With three times as much memory, it runs 17% slower on average, and with twice as much memory, it runs 70% slower.


    2) Also ich finde deine Artikulation passend. :)
    Das Problem ist nur, dass dein Vorhaben so vermutlich nicht laufen wird.
    Ich sehe leider nicht, was genau dein FrameLayout jetzt genau ist, befürchte aber, dass der seine eigene Vorstellung davon hat wie Views platziert werden.
    Die Doku sagt dazu:

    Zitat

    FrameLayout is designed to block out an area on the screen to display a single item. Generally, FrameLayout should be used to hold a single child view, because it can be difficult to organize child views in a way that's scalable to different screen sizes without the children overlapping each other. You can, however, add multiple children to a FrameLayout and control their position within the FrameLayout by assigning gravity to each child, using the android:layout_gravity attribute.
    http://developer.android.com/r…d/widget/FrameLayout.html


    Eventuell macht ja ein GridLayout eher was du möchtest,

    Zitat

    A layout that places its children in a rectangular grid.


    was ich mir bei 5 Bildern aber nur schwerlich vorstellen kann (es sei denn, es soll ein Jigsaw-Puzzle werden: in dem Fall halte dich an kilphil75s oder ChampS' Tipps.)

    was genau soll denn da falsch sein?


    NPE bedeutet NullPointerException, eine Eigenheit von Java, die ich überhaupt nicht mag. ;)


    Das bedeutet, dass du an irgend ein Objekt eine Nachricht schickst, dieses Objekt jedoch nicht gesetzt, also null ist.
    Da dein Code angeblich nicht mit dem Log übereinstimmt, kann ich dir auch nicht sagen, welches Objekt das ist.
    Das musst du in deinem eigenen Code vergleichen.

    normalerweise nennt man den primärschlüssel tabellenname_id


    Normalerweise spricht man die Tabelle direkt an und gibt das Feld dahinter an.
    Also: Artikel._id.


    Wie sieht denn da ein Primärschlüssel artikel_id aus?
    Artikel.artikel_id?


    Redundante Informationen sind redundant und Redundanz stört sowohl den Lesefluss als auch die Übersichtlichkeit.


    Wenn ich mir eine Klasse 'Artikel' erstelle, dann sind die Felder dafür ja auch 'nummer', 'name', 'lieferant' und nicht 'artikelnummer', 'artikelname' und 'artikellieferant'. Denn das geht ja schon aus der Klasse hervor: Artikel.nummer, Artikel.name, Artikel.lieferant ist lesbarer als Artikel.artikelnummer, Artikel.artikelname, Artikel.artikellieferant.


    Davon abgesehen: _id ist immer eine ID, egal welche Tabelle. Hast du also eine Hilfsfunktion, die alle IDs aus deiner Tabelle liest, dann kannst du sie abstrakt halten: ein Feld für den Tabellennamen und ein konstruiertes "SELECT _id FROM "+tableName;


    Ebenso kann ich in dem oben genannten Beispiel auch noch eine Klasse Bestellung haben, mit Bestellung.nummer, Bestellung.datum und Bestellung.artikelliste.
    Eine eventuelle Hilfsfunktion kann für eine Übersicht alle Nummern herausholen:

    Java
    public Set<?> holeAlleNummern(List<InterfaceNummerierteObjekte> objektListe)
    {
      Set<?> resultSet = new HashSet();
      for(InterfaceNummerierteObjekte objekt: objektListe)
      {
        resultSet.add(objekt.nummer);
      }
      return resultSet;
    }


    Tausche ich meine Objekte der objektListe aus, läuft weiterhin alles.
    Hießen die Nummern aber Artikelnummer, Bestellnummer, Kundennummer, Lieferantennummer etc.pp. müsste ich jedes mal den Keypath angegeben.
    Generell ist alles weniger fehleranfällig, was weniger Anpassungsaufwand erfordert.


    Der CursorAdapter funktioniert auf jeder Tabelle, selbst wenn ich sie von Artikel auf Bestellung setze. Weil er sich auf _id als Primärschlüssel verlassen kann.
    Also warum um Himmels Willen dazwischen funken wollen?


    Viel spannender finde ich das Ursprungsproblem:

    Nun hatte ich damit zwei identische Feldnamen, _id, die ich durch die Punktschreibweise, also tabellenname._id unterschieden hatte.
    Leider hat das nicht funktioniert, das System hat mir die falschen Werte( id der falschen Tabelle) geliefert.


    Magst du mal zusammengekürzt auf die id die Haupt- und die Subquery posten?
    Das darf nämlich schlicht nicht passieren und deshalb vermute ich da einen Fehler im Ablauf - allerdings nicht von Seiten des CursorAdapters.

    Entschuldigt bitte, wenn ich mich da einmische, aber was soll denn 'sprechender Primärschlüssel' genau bedeuten?
    Sprechender als Tabelle._id geht es doch kaum.
    Ihr meint doch hoffentlich nicht so einen unglaublich unverständlichen und redundanten Kram wie Artikel.artikelPS?

    Moin.
    Da geht offenbar eine ganze Menge schief. ^^


    Zunächst einmal:

    Zitat

    01-04 16:59:01.426: E/BitmapFactory(22584): Unable to decode stream: java.io.FileNotFoundException: /content:/media/external/images/media/26: open failed: ENOENT (No such file or directory)


    Das bedeutet, dass der Pfad nicht stimmt bzw. das Bild dort nicht existiert. (FileNotFoundException)
    Es ist generell eine gute Idee, Exceptions im Vorfelde zu fangen und entsprechend zu reagieren.
    Der Doppelpunkt könnte das Problem sein. Ein /content hat mein Gerät auch nicht, aber das muss ja nix heißen. Und offenbar hat das gewählte Bild auch keine Endung - keine Ahnung ob das was bedeutet.


    Weiterhin:

    Zitat

    01-04 16:59:01.450: E/AndroidRuntime(22584): java.lang.RuntimeException: Unable to start activity ComponentInfo{eu.freemoser.lazarusnote/eu.freemoser.lazarusnote.listListActivity}: android.view.InflateException: Binary XML file line #2: Error inflating class fragment


    Da scheint wohl noch irgendwas beim Inflate schief gegangen zu sein.


    Zu guter Letzt:

    Zitat

    01-04 16:59:01.450: E/AndroidRuntime(22584): Caused by: java.lang.IllegalStateException: Content view not yet created


    Ein notwendiges ContentView wurde nicht gesetzt, was vermutlich dafür sorgt, dass etwas später der Inflate schief geht.

    Ich ahnte schon, dass ich bezüglich der sexistischen Kackscheiße noch einen Kommentar ernten werde. ;)


    Vermutlich funktioniert dein Puzzle wie folgt: du hast bereits x Bilder im Bundle oder auf dem Dateisystem. Während deine App läuft, lädt sie die Bilder im Hintergrund herunter und packt sie dann ins Dateisystem. Solange die Bilder nicht da sind, werden sie deinem Spiel auch nicht als neues Bild angeboten und es sieht auch niemand einen "Bild <Vorschau> steht jetzt zum Puzzlen bereit!" Dialog.


    In meinem Fall ist das ein bisschen anders. Würde ich die heruntergeladenen Daten sequenziell ablegen, würde der Speicherplatz explodieren.


    Man könnte sagen, die Anwendung soll diverse RSS-Feeds von diversen Servern ziehen - inklusive Bilder, Videos, Musik und was da noch alles dran hängt.
    Diese Daten können an Aktualität verlieren, weshalb ich alte Informationen löschen und nur die neuen Informationen ablegen möchte.


    Um das alles möglichst ressourcenschonend zu gestalten, habe ich mir folgende Abläufe überlegt:
    - der Download der RSS/XML wird nur ein einziges mal gestartet, nämlich in der OnCreate der Launch-Activity (eine Art SplashScreen)
    - dann wird eine ID mit der gespeicherten letzten ID verglichen
    - sind die IDs unterschiedlich, werden die Inhalte dieser XML zum Aktualisieren vorgemerkt
    (Das Ganze passiert aktuell 1 bis 12 mal für 1 bis 12 Dateien auf 1 bis 12 Servern mit je 1 bis 12 MB Dateigesamtgröße)
    - dem User werden die zum Aktualisieren vorgemerkten Informationen gezeigt und er wählt via Checkbox einzelne Aktualisierungen an und ab
    - anhand dieser Auswahl werden die vorhandenen Detailinformationen vom Dateisystem gelöscht
    - anschließend werden die Detailinformationen gemäß der Auswahl heruntergeladen und in das Dateisystem gepackt (Pre-Rendered HTML, Bilder, Sounds, Videos...)


    Im ersten Schritt darf das UI nicht blockieren, da hier viel schief gehen kann. Doch die Anzeige der Informationen soll am Ende aller Downloads erfolgen, unabhängig der Activity.
    Ab diesem Punkt können mir viel zu viele Unbekannte passieren:
    - das ListView wird aus einer SQLite Datenbank generiert (da XML parsen arschlahm sein kann), welche mitten drin gelöscht und neu bespielt worden sein kann
    - die Detailansicht verzweigt auf die Daten im Dateisystem, welche gerade gelöscht, verändert oder sonstwie manipuliert worden sein können


    Das alles und noch viel mehr kann zu unvorhersehbarem Verhalten der Anwendung führen.
    Deshalb möchte ich, dass sobald die ersten Informationen heruntergeladen wurden, ein AlertDialog zunächst den Download der vielen größeren Dateien visualisiert (natürlich abbrechbar) und anschließend sämtliche Änderungen an der Datenbank und dem Dateisystem mittels Kreisel darstellt.
    Der User sieht also, dass er diese App gerade nicht benutzen kann (anstatt sie zu benutzen und feststellen zu müssen, dass gerade irgendwas schief ging).


    ---


    Mit dem Blockieren der UI meinte ich, dass meine SplashScreen Activity gezeigt wird solange die RSS/XML Datei heruntergeladen wird. Im Allgemeinen ist das wurscht, da die Files echt winzig sind. Im Speziellen (Server nicht erreichbar) zeigte sich dieser Splashscreen allerdings 10 Minuten. Das soll so nicht sein.


    Also eigentlich suche ich nach wie vor nur nach einer Möglichkeit, nach erfolgreichem Download aller RSS/XML Dateien im Hintergrund einen Dialog anzuzeigen - unabhängig der aktuellen Activity. +sigh+


    Nun, vielleicht bleibt die aufrufende Activity aber auch so lange im Speicher, dass ich dort einfach den UIThread als Instanzvariable mitgeben kann und dem Ding dann die gewünschten Methoden zuposte. Mal herumprobieren.

    Herzlichen Dank für Eure Hilfe, Ihr beiden. :)


    [matthias]
    Die Sache mit den Services sieht spannend aus. Das werde ich mir mal näher zu Gemüte führen. Eventuell kann ich davon was gebrauchen, auf für zukünftige Dinge.


    [antifish]
    Danke für den Code!
    Nach wie vor habe ich dann aber schlimmstenfalls pro Activity die Listener implementiert.
    Irgendwie halte ich ein eigenes Fragment für oversized, da in diesem speziellen Fall der Download nur einmal beim Start (onCreate) angestoßen und dann bei blockiertem UI weiterrattern soll.
    Mal sehen, wie ich das noch in den Griff bekomme. :)


    Zunächst habe ich das 'Blockieren'-Problem mit einem extrem kleinen Timeout-Wert für die URL Connection umgangen.
    Verdammte persönlich gesetzte Deadlines. ^^

    Moin,


    irgendwie treiben mich Androids Activities nach wie vor in den Wahnsinn.
    Deshalb frage ich hier mal nach. :)


    Ich möchte gern Dinge aus dem Internet herunterladen, was an und für sich kein Problem ist.
    Aktuell wird das über den Splash Screen geregelt und ein aufpoppender AlertDialog teilt auch unmissverständlich mit, dass gerade gewartet werden muss.
    Ungeilerweise können ja beim Download durchaus Probleme auftreten, aktuell: der Server antwortet nicht. In diesen Fällen dauert eine Reaktion ewig, weshalb eine blockierende Activity, wie ich sie jetzt habe, nicht in Frage kommt.
    (3x eine Datei von je einem Server laden = 3*3 Minuten Timeout)


    Nun würde ich das Ganze gern auslagern. Meinetwegen in ein Objekt packen und dann an einen Thread übergeben. Nur müsste dieser Thread mitten drin mal ein paar UI Elemente (Dialogfelder) anzeigen. Was er ja nun mal designbedingt nicht kann.
    Erschwerend hinzu kommt, dass ich nicht abschätzen kann, auf welcher Activity sich meine App gerade befindet.
    Die Methoden für AsyncTask einbauen wird also mutmaßlich auch nicht allzu viel helfen, da die Activities ja lustig wechseln können.


    Am Liebsten wäre mir, ich könnte dem Objekt sagen: "Wenn du damit fertig bist, dann starte Activity XYZ auf dem UI Thread und gib ihr die Extras ABC mit."
    Nur: wie geht das?


    --


    Ach ja, ich frage absichtlich nicht nach Möglichkeiten, wie ich die Erreichbarkeit des Servers testen kann.
    Wenn ich keine Daten habe, dann habe ich keine Daten und es interessiert mich nicht, warum ich keine Daten habe.
    Frage ich beispielsweise ab, ob der Server auf einen Ping reagiert, aber bei HTTP kommt kein Response, bin ich genauso weit wie jetzt - nur mit noch mehr Code. Da ich nicht alles berücksichtigen kann (Ping und HTTP geht, aber ich bekomme ne 503 als HTML Seite ausgeliefert...) und dementsprechend auch nicht will möchte ich lieber abstrakt und minimalisiert da ran gehen: entweder ich bekomme gültige Daten oder nicht.
    Wie dabei das 'oder nicht' aussieht interessiert mich erst einmal nicht.

    Okay, das sieht so aus, als läge das Problem nicht bei den von dir gezeigten Codezeilen.


    Er steigt aus beim sinngemäßen Aufruf von

    Java
    gameThread.start();


    Da dein GameThread bereits $irgendwo existiert und läuft, kannst du ihm kein .start() senden.
    Das geht nur, wenn sein ThreadState auf 'NEW' steht. Selbst beim Pausieren steht er gemäß StackOverflow auf 'RUNNABLE' oder 'WAITING'.


    Seit einem geringen API Level (1!) gibt es die Möglichkeiten zum Anhalten und Fortführen eines Threads nicht mehr, war wohl zu unsicher.


    Leider habe ich keine Ahnung von Spieleentwicklung (und mag Threads auch nicht besonders), so dass ich dir hier leider nicht weiterhelfen kann. -.-

    Da du Java-Code formatierst, solltest du auch

    Java
    [code=java]

    nehmen. ;)
    Zumindest klappt da erfahrungsgemäß die Sache mit dem Einrücken.


    Was sagt denn das Log bezüglich deines Absturzes?
    Ich habe die Erfahrung gemacht, dass eine Activity sich ungern aus einem anderen als dem MainThread starten lässt.

    Du kannst sie dir auch vom Gerät ziehen.


    Mit der ddms-Ansicht deiner IDE kannst du zum Speicherort der Datenbank navigieren, sie irgendwo auf deinen Rechner ziehen und anschauen.
    Das Ding sollte in


    /data/data/package_name/databases


    liegen.


    Geht sowohl via Gerät mit aktiviertem USB-Debugging als auch über den Emulator. :)


    (Natürlich musst du dann mit sqlite3 oder einen graphischen Client arbeiten, um in der Datenbank agieren zu können.)

    Hallo ihr lieben hilfreichen Seelen,


    ich habe da mal ein paar Fragen zur Entwicklung mit Java.
    Da ich so gefühlt langsam das Larvenstadium verlasse und mich mittlerweile so richtig einniste, möchte ich Dinge natürlich auch richtig machen. ;)


    Dazu wäre ich über Tipps und Tricks zu folgenden Problemstellungen sehr dankbar. :)


    1) Codestrukturierung
    Meine IDE bietet ja mit der 'Structure'-Übersicht ein paar nette Hilfsmittel an. Gerne würde ich diese Strukturübersicht noch übersichtlicher gestalten.
    In Objective-C kann ich mit #pragma mark Label ein Label setzen, beispielsweise um logisch zusammenhängende Codeblöcke (Overrides, Getter+Setter, Delegates...) sichtbar zu unterteilen.
    In C# gibt es mit den Tags #region und #endRegion die Möglichkeit, logisch zusammenhängende Codeblöcke sichtbar zu gruppieren.
    Welches Equivalent bietet Java hier von Hause aus an?


    2) Testing
    Ich mag ja Unit Tests. Sowohl unter C# als auch unter Objective-C mache ich nichts ohne. Hier unter Java/Android allerdings schon, weil es sich mir nicht erschließt. Naja, ich werde damit jetzt anfangen.


    Nur finde ich absolut nichts zum Thema Integration Tests. Hat da jemand Tipps oder Hinweise?


    3) Code Coverage
    Wir kennen das ja... Es dümpelt Code herum den man niemals nicht braucht und der bläht die eh schon viel zu langen .java Files auch noch unnötig auf.
    Als IDE nutze ich IntelliJ, weil ich weder Eclipse noch NetBeans wirklich ausstehen kann. Leider kann die freie Edition keine CodeCoverage abgreifen.
    Emma Code Coverage kann offenbar (nach eigenen Angaben) nicht mit Android umgehen.


    Kennt jemand ein Tool, mit dem ich die CodeCoverage von Android überprüfen kann?