Autore Topic: Live Wallpaper Preview OOM  (Letto 2164 volte)

Offline RiP

  • Nuovo arrivato
  • *
  • Post: 25
  • Respect: 0
    • Mostra profilo
  • Dispositivo Android:
    Motorola Atrix, SE Xperia Play, Asus eee Pad Transformer
  • Play Store ID:
    Riccardo Piva, RiP
  • Sistema operativo:
    Windows 7, Ubuntu
Live Wallpaper Preview OOM
« il: 10 Luglio 2012, 10:35:48 CEST »
0
Buondì a tutti,
Sono nuovo nel forum e innanzitutto mi presento: sono un neolaureato 24enne di Ferrara che in assenza di immediate opportunità lavorative si è buttato nella programmazione su Android da qualche mese.
Dopo un pò di studio (parecchio) ho cominciato a completare le mie prime applicazioni e a inserirle sul Play Store. Da un pò mi sono concentrato nello sviluppo di Live Wallpapers che reputo un buon inizio per cominciare a mettere le mani sulle tecniche per il game developing e un buon modo per guadagnare qualche soldino in attesa di un lavoro. Ho pubblicato un live wallpaper su market che mi ha creato non pochi problemi con il noto OutOfMemory Error. Per il momento ho bypassato il problema con qualche trucchetto (che a volte funziona e a volte no!! ) ma con la prossima pubblicazione di altri live wallpaper che ho quasi terminato di sviluppare volevo risolverlo definitivamente!
Il punto è che questo problema mi viene generato quando ho i passaggi dalla preview (dove l'utente sceglie il lwp e lo imposta) alla scermata del launcher. Ora ottimizzazione di immagini etc. sono daccordo che siano una buona soluzione ma quando si vuole realizzare qualcosa possibilmente in alta definizione non sempre è possibile. In ogni caso la mia domanda è questa:
posso far caricare la preview in un service a parte. La mia idea era quella di creare 2 engine, uno di preview e uno definitivo. Poi quando l'utente apre la preview faccio aprire l'engine della preview in cui dovendo caricare tutto in una pagina senza effetti di scrolling etc carico immagini fatta adHoc. Poi quando l'utente setta il livewallpaper si carica invece l'altro engine.
Altra ipotesi è quella di interrompere il thread sul quale gira la preview quando l'utente passa al menu di settings e quando poi setta il livewallpaper ma richiamare un super.onDestroy(); sul service sappiamo che non funziona! Ho tentato di creare un intent al quale passo il mio package e poi utilizzo un getApplicationContext().startService(intent); per aprire il nuovo service sul context corrente ma non c'è dubbio che faccia quello che voglio io!!!  :D

Qualche soluzione o consiglio?! Grazie mille in anticipo!

Offline eagledeveloper

  • Translate Team
  • Utente senior
  • ****
  • Post: 516
  • Respect: +37
    • Google+
    • 347516210
    • dark_pinz
    • @WandDStudios
    • Mostra profilo
    • W&D Studios
  • Dispositivo Android:
    HTC One X e HTC One
  • Play Store ID:
    W%26D+Studios
  • Sistema operativo:
    Ubuntu / Windows 7
Re:Live Wallpaper Preview OOM
« Risposta #1 il: 10 Luglio 2012, 11:39:41 CEST »
0
Riutilizzo delle variabili potrebbe essere un buon consiglio ma magari lo fai già.
I numeri contano molto di più del seme.

Offline RiP

  • Nuovo arrivato
  • *
  • Post: 25
  • Respect: 0
    • Mostra profilo
  • Dispositivo Android:
    Motorola Atrix, SE Xperia Play, Asus eee Pad Transformer
  • Play Store ID:
    Riccardo Piva, RiP
  • Sistema operativo:
    Windows 7, Ubuntu
Re:Live Wallpaper Preview OOM
« Risposta #2 il: 10 Luglio 2012, 11:43:06 CEST »
0
Quando possibile uso il recycle() sulle Bitmap, ma non sempre riesco a farlo perchè spesso rischio di incappare in dei NullPointerException. Per riutilizzo delle variabili intendevi questo? Il punto è che pare che quando il lw è in versione preview se ne freghi altamente del fatto che tutte le mie variabili sono già inizializzate e ne crei di nuove. Probabilmente ometto qualcosa.

Offline eagledeveloper

  • Translate Team
  • Utente senior
  • ****
  • Post: 516
  • Respect: +37
    • Google+
    • 347516210
    • dark_pinz
    • @WandDStudios
    • Mostra profilo
    • W&D Studios
  • Dispositivo Android:
    HTC One X e HTC One
  • Play Store ID:
    W%26D+Studios
  • Sistema operativo:
    Ubuntu / Windows 7
Re:Live Wallpaper Preview OOM
« Risposta #3 il: 10 Luglio 2012, 11:55:19 CEST »
0
Le Bitmap sono cazzute, il recycle() serve a poco se non ad incappare in null pointer.

Android fa fatica ad usare le immagini, io avevo delle grandi immagini che mettevo come sfondo e continuavo ad avere errori di out of memory.

Io riutilizzo sempre la stessa Bitmap perche' con due mi crashava sempre.
I numeri contano molto di più del seme.

Offline RiP

  • Nuovo arrivato
  • *
  • Post: 25
  • Respect: 0
    • Mostra profilo
  • Dispositivo Android:
    Motorola Atrix, SE Xperia Play, Asus eee Pad Transformer
  • Play Store ID:
    Riccardo Piva, RiP
  • Sistema operativo:
    Windows 7, Ubuntu
Re:Live Wallpaper Preview OOM
« Risposta #4 il: 10 Luglio 2012, 12:06:28 CEST »
0
Quindi anche tu hai "risolto" bypassando il problema, o meglio adattandoti tu!! Il problema è che un immagine in meno su un live wallpaper è un casino perchè compromette di non poco il risultato grafico che è fondamentale. è mai possibile che oltre ad uno schifosissimo metodo isPreview() non ci sia nient'altro che permette di gestire separatamente la preview dal risultato finale!! Mah!! Mi pare strano...

Offline eagledeveloper

  • Translate Team
  • Utente senior
  • ****
  • Post: 516
  • Respect: +37
    • Google+
    • 347516210
    • dark_pinz
    • @WandDStudios
    • Mostra profilo
    • W&D Studios
  • Dispositivo Android:
    HTC One X e HTC One
  • Play Store ID:
    W%26D+Studios
  • Sistema operativo:
    Ubuntu / Windows 7
Re:Live Wallpaper Preview OOM
« Risposta #5 il: 10 Luglio 2012, 12:58:02 CEST »
0
Se trovi qualcosa fammi sapere.
I numeri contano molto di più del seme.

Offline RiP

  • Nuovo arrivato
  • *
  • Post: 25
  • Respect: 0
    • Mostra profilo
  • Dispositivo Android:
    Motorola Atrix, SE Xperia Play, Asus eee Pad Transformer
  • Play Store ID:
    Riccardo Piva, RiP
  • Sistema operativo:
    Windows 7, Ubuntu
Re:Live Wallpaper Preview OOM
« Risposta #6 il: 10 Luglio 2012, 13:16:55 CEST »
0
Certamente! Spero anche che nelle prossime ore qualche altro utente del forum si faccia vivo!

Offline eagledeveloper

  • Translate Team
  • Utente senior
  • ****
  • Post: 516
  • Respect: +37
    • Google+
    • 347516210
    • dark_pinz
    • @WandDStudios
    • Mostra profilo
    • W&D Studios
  • Dispositivo Android:
    HTC One X e HTC One
  • Play Store ID:
    W%26D+Studios
  • Sistema operativo:
    Ubuntu / Windows 7
Re:Live Wallpaper Preview OOM
« Risposta #7 il: 10 Luglio 2012, 13:24:58 CEST »
0
Semmai mette qualche riga di codice dove ti crasha.
I numeri contano molto di più del seme.

Offline undead

  • Utente senior
  • ****
  • Post: 666
  • Respect: +113
    • Mostra profilo
  • Dispositivo Android:
    Samsung Galaxy S6
  • Play Store ID:
    DrKappa
  • Sistema operativo:
    Windows 10 64-bit, Windows 8.1 64-bit
Re:Live Wallpaper Preview OOM
« Risposta #8 il: 10 Luglio 2012, 13:38:53 CEST »
0
Ma sono l'unico a pensare che recycle non serva a niente?

Offline eagledeveloper

  • Translate Team
  • Utente senior
  • ****
  • Post: 516
  • Respect: +37
    • Google+
    • 347516210
    • dark_pinz
    • @WandDStudios
    • Mostra profilo
    • W&D Studios
  • Dispositivo Android:
    HTC One X e HTC One
  • Play Store ID:
    W%26D+Studios
  • Sistema operativo:
    Ubuntu / Windows 7
Re:Live Wallpaper Preview OOM
« Risposta #9 il: 10 Luglio 2012, 14:18:41 CEST »
0
Ma sono l'unico a pensare che recycle non serva a niente?
No anche io :)
I numeri contano molto di più del seme.

Offline undead

  • Utente senior
  • ****
  • Post: 666
  • Respect: +113
    • Mostra profilo
  • Dispositivo Android:
    Samsung Galaxy S6
  • Play Store ID:
    DrKappa
  • Sistema operativo:
    Windows 10 64-bit, Windows 8.1 64-bit
Re:Live Wallpaper Preview OOM
« Risposta #10 il: 10 Luglio 2012, 14:40:26 CEST »
0
@eagle: appunto, per me recycle non solo non serve assolutamente a niente, è addirittura dannosa!!!!

Quello che fa recycle è marcare come DEAD una bitmap in modo che il GC possa liberare memoria.

Il primo problema è che il metodo Recycle non può da solo dare luogo ad errori perchè ogni variabile in Java è implicitamente un puntatore, quindi se io ho:

Codice (Java): [Seleziona]
Bitmap miabitmap = caricalamiabitmapnumero1();
miabitmap.Recycle();
miabitmap = caricalamiabitmapnumero2();

L'ultima chiamata "sostituisce" l'oggetto puntato, non opera sulla vecchia bitmap. Non esiste che venga lanciata una eccezione a meno che Recycle non operi in modo talmente oscuro e fuori da ogni logica del linguaggio (e questo suggerirebbe di starne ancora di più alla larga)!

Se hai un errore vuol dire che da qualche parte hai ancora un reference a quell'istanza di bitmap che hai invalidato... e non solo... da qualche parte continui pure ad usarla!

Da questo deriva il secondo problema: avere dei reference ad un oggetto che impediscono al GC di liberare l'oggetto stesso e invece di risolvere il problema cercare di "aggirarlo".

Il fatto che esista una funzione di "comodo" che tagga un oggetto come DEAD anche se hai reference sparsi qua e là si chiama istigazione a delinquere da parte di google.

Recycle spinge lo sviluppatore a supporre che non ci siano problemi... si chiama Recycle fregandosene di avere reference ad un oggetto che dichiariamo morto e speriamo che la GC funzioni o ce lo pulisca "in tempo".

Ma funziona davvero? E qui siamo al terzo problema. Se il comportamento di recycle fa si che la chiamata al garbage collector sia asincrona (e lo è!) non se ne capisce l'utilità. Se il GC è stato invocato e usi la bitmap hai una nullpointerexception, se non è stato invocato hai comunque una eccezione perchè stai usando un oggetto taggato come morto!!!!

Mi domando che soluzione/hack/aggiramento possa essere se nei due casi possibili (uso prima del GC o dopo il GC) ottengo comunque due eccezioni.

La solzione per me è una sola: dimenticarsi che esiste Recycle, assegnare null a qualunque reference e vivere tranquilli.

La teoria dice che dalvik dovrebbe accorgersi che esiste memoria non utilizzata, dovrebbe reclamarla e buonanotte.

Siccome spesso la pratica e la teoria non coincidono, si chiama esplicitamente il GC prima di caricare un'altra bitmap (dopo aver eliminato tutti i reference), che da quanto ne so (o almeno da specifiche java) è sincrono.

Poi se non hai reference, chiami la GC e continua a non funzionare penso che ci sia poco da fare. Ma attenzione... una volta che hai fatto il possibile e ottieni ancora out of memory devi risolvere il problema alla radice: superare la limitazione di 16/24mb nell'heap space.

La soluzione "migliore" sarebbe quella di farsi un live wallpaper OpenGL ES, ma ho letto in un altro post che l'OP vorrebbe prima esplorare le funzionalità 2D di android (scelta che condivido e che ho fatto anche io).

Potrei sbagliarmi perchè avevo fatto prove a basso livello qualche mese fa e non ho più toccato nulla (come si dice... if it ain't broke, don't fix it! ) ma l'unico modo che hai per usare le funzioni 2D e fregartene delle limitazione sullo heap è scrivere un allocatore/caricatore di bitmap a basso livello con l'NDK e poi disegnare con Java.

 :-(

Offline RiP

  • Nuovo arrivato
  • *
  • Post: 25
  • Respect: 0
    • Mostra profilo
  • Dispositivo Android:
    Motorola Atrix, SE Xperia Play, Asus eee Pad Transformer
  • Play Store ID:
    Riccardo Piva, RiP
  • Sistema operativo:
    Windows 7, Ubuntu
Re:Live Wallpaper Preview OOM
« Risposta #11 il: 10 Luglio 2012, 15:06:08 CEST »
0
Guarda sul recycle() sono d'accordo con te, non ho trovato alcun miglioramento nell'utilizzo o meno di questo metodo in quanto a OOM Error e in fase di programmazione ho trovato più rogne che resto.. penso che (purchè non sia un metodo pensato male fin dal principio dai realizzatori dell'sdk!) abbia una logica adatta ad utilizzi diversi da questo. Magari con un uso intenso di metodi di scaling per creare Bitmap a partire da una bitmap già esistente, ma sinceramente vedo più logica una bella bitmap = null; e bon!
Per quello che riguarda la chiamata diretta al gc la faccio in vari metodi (dall'onCreate all'onDestroy) ma in realtà mi sa che dalvik se ne frega altamente delle mie chiamate anche se fatte sul Runtime.getRuntime().gc().
Il punto è che sto comunque attento (per quanto lo si possa fare) all'utilizzo delle immagini così da non strozzare l'heap ma nelle chiamate ripetute della preview e settando ripetutamente il livewallpaper pare che quella ceffa di una VM non capisca che sul mio package quel cacchio di thread è già aperto e che quelle cacchio di immagini sono già in memoria... Quindi pensa bene di ricreare un nuovo thread e di ricaricare tutte le immagini! Poi dopo qualche secondo il gc() si accorge che il primo thread e sue allocazioni non servono più ad un piffero e lo elimina ma se in quel frangente di secondi io ho smanettato 20 volte sulla preview del live wallpaper strippa e mi sbatte un bel OOM...
@undead dici che lavorando con le openGL eviterei molti di questi problemi di OOM?! L'idea era quella di lavorare con le caratteristiche dell'Application Framework e impararle bene poi creare nel prossimo futuro qualcosa con le openGL e nel caso in cui vedessi sostanziali miglioramenti migrare tutti i lavori in quel senso. Per il codice nativo con l'NDK sinceramente mi sembra uno sbattimento eccessivo per un live wallpaper.. Ho in mente un paio di games che probabilmente mi porteranno in quel senso ma non ora!!
Grazie mille per le risposte.. sapere che è un problema comune e di non facile risoluzione mi fa sentire meno pirla... Ero stanco di vedere developers americani che sapevano rispondere unicamente "use the recycle()"...
Una cosa che ho omesso ma che ho potuto verificare essere utile in molte situazioni è quella di aggiungere alle options del BitmapFactory.decodeResources un bel options.inPreferredConfig = Bitmap.Config.RGB_565; il che mi fa occupare la metà dei byte rispetto alla configurazione normale, che è meglio!!!  :D

Offline undead

  • Utente senior
  • ****
  • Post: 666
  • Respect: +113
    • Mostra profilo
  • Dispositivo Android:
    Samsung Galaxy S6
  • Play Store ID:
    DrKappa
  • Sistema operativo:
    Windows 10 64-bit, Windows 8.1 64-bit
Re:Live Wallpaper Preview OOM
« Risposta #12 il: 10 Luglio 2012, 15:29:37 CEST »
0
Guarda sul recycle() sono d'accordo con te, non ho trovato alcun miglioramento nell'utilizzo o meno di questo metodo in quanto a OOM Error e in fase di programmazione ho trovato più rogne che resto.. penso che (purchè non sia un metodo pensato male fin dal principio dai realizzatori dell'sdk!) abbia una logica adatta ad utilizzi diversi da questo. Magari con un uso intenso di metodi di scaling per creare Bitmap a partire da una bitmap già esistente, ma sinceramente vedo più logica una bella bitmap = null; e bon!
Per quello che riguarda la chiamata diretta al gc la faccio in vari metodi (dall'onCreate all'onDestroy) ma in realtà mi sa che dalvik se ne frega altamente delle mie chiamate anche se fatte sul Runtime.getRuntime().gc().
Ma infatti scindiamo il problema.
Le reference alle bitmap si "nullano", le liste/array si "clearano", si chiama il GC e si incrociano le dita.
Ma gli errori che vengono fuori possono (e devono) essere solo degli out of memory, non dei null pointer. A meno che il null non sia conseguenza dell'out of memory che però non dovrebbe essere  "bypassato".

;-)

Citazione
Il punto è che sto comunque attento (per quanto lo si possa fare) all'utilizzo delle immagini così da non strozzare l'heap ma nelle chiamate ripetute della preview e settando ripetutamente il livewallpaper pare che quella ceffa di una VM non capisca che sul mio package quel cacchio di thread è già aperto e che quelle cacchio di immagini sono già in memoria... Quindi pensa bene di ricreare un nuovo thread e di ricaricare tutte le immagini! Poi dopo qualche secondo il gc() si accorge che il primo thread e sue allocazioni non servono più ad un piffero e lo elimina ma se in quel frangente di secondi io ho smanettato 20 volte sulla preview del live wallpaper strippa e mi sbatte un bel OOM...
Senza avere il codice è difficile dare un giudizio. Ad occhio e croce visto che parli di thread perchè non ti implementi un singleton o un resource manager che sia accessibile dal thread? Intendo qualcosa di staccato dal thread che carica le bitmap e poi il thread ci accede e vede se il resource manager ha caricato tutto o meno?  :-\

Citazione
@undead dici che lavorando con le openGL eviterei molti di questi problemi di OOM?! L'idea era quella di lavorare con le caratteristiche dell'Application Framework e impararle bene poi creare nel prossimo futuro qualcosa con le openGL e nel caso in cui vedessi sostanziali miglioramenti migrare tutti i lavori in quel senso. Per il codice nativo con l'NDK sinceramente mi sembra uno sbattimento eccessivo per un live wallpaper.. Ho in mente un paio di games che probabilmente mi porteranno in quel senso ma non ora!!
OpenGL non ha un limite sullo heap a quanto ne so. Le texture vanno "oltre". Oltre nel senso dell'heap space di Java, se hai 200mb liberi sul telefono quelli sono, salvo che il sistema reclami memoria...

Citazione
Grazie mille per le risposte.. sapere che è un problema comune e di non facile risoluzione mi fa sentire meno pirla... Ero stanco di vedere developers americani che sapevano rispondere unicamente "use the recycle()"...
Potenza di anddev.it  :D

Citazione

Una cosa che ho omesso ma che ho potuto verificare essere utile in molte situazioni è quella di aggiungere alle options del BitmapFactory.decodeResources un bel options.inPreferredConfig = Bitmap.Config.RGB_565; il che mi fa occupare la metà dei byte rispetto alla configurazione normale, che è meglio!!!  :D
Si però la qualità diminuisce.  :-(

Offline RiP

  • Nuovo arrivato
  • *
  • Post: 25
  • Respect: 0
    • Mostra profilo
  • Dispositivo Android:
    Motorola Atrix, SE Xperia Play, Asus eee Pad Transformer
  • Play Store ID:
    Riccardo Piva, RiP
  • Sistema operativo:
    Windows 7, Ubuntu
Re:Live Wallpaper Preview OOM
« Risposta #13 il: 10 Luglio 2012, 15:58:15 CEST »
0
Forse non è corretto il termine thread. Posso anche girarti tutto il codice ma cambia relativamente perchè è poi in fase di test e debug che mi accorgo di questa cosa.
Ora ti faccio un bel riepilogo di un mio debug standard sul live wallpaper e qual'è il punto che vorrei aggiustare:
Piazzo 3 Breakpoint che ti numero di seguito:
1) onCreateEngine() (DELLA CLASSE PRINCIPALE)
2) onCreate(SurfaceHolder sh) (DELL'ENGINE)
3 )onDestroy() (DELL'ENGINE)

Ora a sfondo non caricato faccio installo la mia apk.
Passo alla Preview del mio live wallpaper per settarlo e in ordine ho: 1), 2)
Come è giusto aspettarsi. Quando gli dico di settare il livewallpaper ricevo: 1), 2), 3)
Ora il mio problema è sostanzialmente sul fatto: Ma perchecacchio il 3) cioè l'onDestroy() arriva dopo che mi ha ricreato di nuovo tutto l'ambaradan dell'engine e non prima per poi creare tutto se proprio vuoi.. In teoria in questa maniera dovremmo girare su 2 Thread, uno usato per la preview che quando gli tira (spesso troppo tardi) passa in onDestroy() e l'altro che invece rappresenta lo sfondo vero e proprio sotto la home del launcher. Solo che io non riesco ad individuare l'uno o l'altro thread (o quello che sono) per dirgli di fare prima il punto 3) e poi passare alla creazione. Il problema al contrario poi mi si presenta quando torno alla preview e ancora una volta carica tutto passando da 1), 2) (in questo caso chiaramente il 3) non lo considera. Se poi per qualche motivo sono così ceffo da spingere di nuovo il tasto per settare il livewallaper anche se è già settato di nuovo passiamo prima da 1), 2) poi magari si degna di fare qualche onDestroy() e valutando che il gc() non è sempre li al mio comando nel frattempo ho occupato l'heap per 4 volte di fila con la stessa roba!! Mi sembra assurdo che questi passaggi non possano un minimo essere instradati.. In quel caso eviterei molti ma molti problemi.. spero di essere stato chiaro..

Offline undead

  • Utente senior
  • ****
  • Post: 666
  • Respect: +113
    • Mostra profilo
  • Dispositivo Android:
    Samsung Galaxy S6
  • Play Store ID:
    DrKappa
  • Sistema operativo:
    Windows 10 64-bit, Windows 8.1 64-bit
Re:Live Wallpaper Preview OOM
« Risposta #14 il: 10 Luglio 2012, 17:04:35 CEST »
0
La butto lì... nell'engine hai un metodo onsurfacedestroyed... se passa di lì forse c'è un modo.

setti un flag in inizializzazione a true.

nella onsurfacedestroyed se è false esci e basta.

se è true metti tutto a null, setti il flag a false e chiami stopself, per forzare la ondestroy.. a quel punto nella ondestroy non ci metti nulla.

 :-\ :-\