Autore Topic: Application class  (Letto 342 volte)

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
Application class
« il: 20 Maggio 2014, 18:30:24 CEST »
0
Ho la activity A e la application A1.
Faccio partire la activity A che mi inizializza nella onCreate un membro della application A1.
Faccio quindi partire un'altra activity, la B, faccio quello che devo fare e torno all'activity A.

Domanda: è possibile che la activity A non venga distrutta ma il sistema nel frattempo distrugga la application A1????

Perchè quello che vedo si spiega solo se, non si sa in base a quale principio che non riesco a riprodurre, il membro della application A1 mi diventa null (quindi la application viene distruttra e ricreata) mentre la activity A gira tranquillamente.

E nel caso sia possibile... quale è il senso di questo comportamento????

Offline bradipao

  • Moderatore globale
  • Utente storico
  • *****
  • Post: 4043
  • keep it simple
  • Respect: +567
    • Github
    • Google+
    • bradipao
    • Mostra profilo
  • Dispositivo Android:
    Nexus 5
  • Play Store ID:
    Bradipao
  • Sistema operativo:
    W7
Re:Application class
« Risposta #1 il: 20 Maggio 2014, 18:39:49 CEST »
0
Domanda per capire se ho capito  :-P : L'activity A fa parte dell'applicazione di cui ha esteso l'oggetto Application A1?
NON rispondo a domande nei messaggi privati
Bradipao @ Play Store

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:Application class
« Risposta #2 il: 20 Maggio 2014, 18:54:31 CEST »
0
Domanda per capire se ho capito  :-P : L'activity A fa parte dell'applicazione di cui ha esteso l'oggetto Application A1?
Esattamente.  :-)

Ora, non per linkare a siti esterni, ma io ho trovato questo: activity - Android Application Class Lifecycle - Stack Overflow

E tra i vari commenti (oltre a quello dell'OP) vedo questo:

Citazione
I've found that my application's global state, which is held in the .Application class, is quite frequently killed even though the Activity stack apparenty remains intact. To solve this, all of my Activities must be able to gracefully cope with the global state no longer being present the next time they come to foreground, and in such case trigger the rebuilding of the global state
....
Furthermore, I can only assume that the cyclic killing and re-instantiating of my app's .Application is the system attempting to improve user experience by getting ready again any processes it had to kill previously due to low RAM. What this has made me realise is that it's a bad idea to start off any lengthy work of rebuilding global state at the point of .Application instantiation.

Questi commenti sembrerebbero avvalorare l'ipotesi che la application class possa essere distrutta a piacimento senza che l'activity venga espressamente ricreata tramite una chiamata a onCreate.

Questo comportamento mi stupisce. Sbaglia chi ha fatto il commento? Sbaglio io? Però effettivamente vedo un crash la cui unica spiegazione è che un membro della classe application sia stato "resettato dal sistema", quindi sia null... mentre nell'activity continuo a usarlo senza problemi.

Boh!

Offline bradipao

  • Moderatore globale
  • Utente storico
  • *****
  • Post: 4043
  • keep it simple
  • Respect: +567
    • Github
    • Google+
    • bradipao
    • Mostra profilo
  • Dispositivo Android:
    Nexus 5
  • Play Store ID:
    Bradipao
  • Sistema operativo:
    W7
Re:Application class
« Risposta #3 il: 20 Maggio 2014, 19:50:06 CEST »
0
Avevo sempre pensato che l'oggetto Application fosse l'ultimo ad essere distrutto, ma dai commenti e dai link pare proprio non sia così. Mi cade una certezza. :-(

EDIT: trovato un blog post sull'argomento Don’t Store Data in the Application Object

A me sembra di capire che il problema risiede nel fatto che il processo viene distrutto (e quindi anche l'oggetto Application), mentre rimane nello stack l'activity che assume la presenza dei dati nell'oggetto Application. Non credo sia possibile distruggere l'Application da sola.

« Ultima modifica: 20 Maggio 2014, 20:01:44 CEST da bradipao »
NON rispondo a domande nei messaggi privati
Bradipao @ Play Store

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:Application class
« Risposta #4 il: 20 Maggio 2014, 20:27:24 CEST »
0
Infatti l'ho postato qua perché il bug che mi segnalano è sulla briscola ma se il caso é quello dell'activity e application é una cosa così particolare da essere di interesse "pubblico".
Anche a me cade una certezza.

Ti dirò di più a me capita (apparentemente) quando vado a chiamare due activity una dietro l'altra.
La prima è quella dell'attivazione bluetooth la seconda é quella del discovery.
Di fatto sono activity ma da sistema appaiono come due stupidissime dialog.
Immagina il mio stupore... arriva la dialog che ti chiede se lo vuoi visibile al ritorno io faccio comunque partire il servizio bluetooth e nel tempo in cui parte mi iniziano a arrivare i device e poi del tutto casualmente BOOOOOOM.

Mi da un nullpointerexception sullo stesso oggetto che sto usando per mostrare i device visibili. Che però funziona nell'activity. Ricontrollando in lungo e in largo in un solo punto passo quell'oggetto alla application: nella oncreate dell'activity. In nessun device, mio o di amici, ho mai potuto verificare questo crash.

Il mio caso è quindi leggermente diverso. Uso la application per condividere un dato con un servizio. La activity funziona perché non richiede la application infatti gli arrivano i device. Nel mentre parte il servizio che si fa dare l'oggetto dalla application che è cambiata (ma != null) e nessuno ha inizializzato.

Pazzesco.

Non si finisce mai di imparare.  :-)

Post unito: 21 Maggio 2014, 13:20:23 CEST
Vorrei fare una ulteriore considerazione su quello che c'è nel link, sono curioso di sapere cosa ne pensi.

C'è un punto che non mi è chiaro e che spero sia definitivamente "chiuso" quando avrò fatto la modifica alla app e potrò vedere se il problema è stato risolto o meno.

Tutto ruota attorno a questa frase:

Citazione
7.Android creates a new MyApplication instance and restores GreetLoudlyActivity
Se io la prendo alla lettera io immagino che venga chiamata la onCreate di MyApplication e la onResume della seconda activity.
Se il comportamento è questo il mio crash è assolutamente logico: la onResume non setta il framework corrente (che rimane valido, infatti mi arrivano i device sull'activity) alla application, che quindi ha un framework null e all'atto di far partire il servizio mi da una nullpointerexception.

Se questo è il caso non c'è bisogno di due activity per riprodurre il problema. Basta che nella onCreate setti il testo nella application e nella onResume lo usi. Infatti secondo quanto dice viene creata una nuova istanza della application ma la oncreate della activity non viene chiamata. Eppure questo problema viene specificatamente segnalato nel caso di due activity, non nel caso di una. Come mai?

Un'idea ce l'ho.

C'è un altro particolare che durante lo sviluppo ho ritenuto di poco conto ma che potrebbe essere determinante in questa situazione.
Io lancio la mia activity, inizio una partita multiplayer con service Bluetooth. Quando premo il tasto home e l'avversario gioca una carta io ricevo una notifica. Cliccando sulla notifica apro la app. Nel launchmode standard viene creata una nuova istanza della app. Procedendo a chiuderla col tasto back torno alla istanza precedente e il gioco si svolge regolarmente. Onde evitare di avere istanze multiple ho deciso di utilizzare il flag "singleTask".

<activity> | Android Developers

Citazione
The system creates the activity at the root of a new task and routes the intent to it. However, if an instance of the activity already exists, the system routes the intent to existing instance through a call to its onNewIntent() method, rather than creating a new one.

L'idea che mi sto facendo, apparentemente bislacca ma forse nemmeno poi tanto.. è che la activity sia creata "separata" rispetto alla application.
Nel caso in cui il sistema ripulisca memoria può succedere che scelga di ripulire la application che viene ricreata ma che essendo slegata dalla activity che è dichiarata come singleTask non ne condivida il ciclo di vita.

Questo potrebbe essere il motivo per cui nella mia app ho quel tipo di crash nonostante abbia una sola activity. In una situazione normale l'application e l'activity numero 1 sono create "unite" e quindi nascono e muoiono assieme. Aprire la activity due crea un task slegato. Nel mio caso application e activity nascono separate perché il sistema crea l'activity "at the root of a NEW task".

Che ne pensi?  o_O
« Ultima modifica: 21 Maggio 2014, 13:20:23 CEST da undead, Reason: Merged DoublePost »

Offline bradipao

  • Moderatore globale
  • Utente storico
  • *****
  • Post: 4043
  • keep it simple
  • Respect: +567
    • Github
    • Google+
    • bradipao
    • Mostra profilo
  • Dispositivo Android:
    Nexus 5
  • Play Store ID:
    Bradipao
  • Sistema operativo:
    W7
Re:Application class
« Risposta #5 il: 21 Maggio 2014, 14:23:33 CEST »
+1
Se questo è il caso non c'è bisogno di due activity per riprodurre il problema. Basta che nella onCreate setti il testo nella application e nella onResume lo usi. Infatti secondo quanto dice viene creata una nuova istanza della application ma la oncreate della activity non viene chiamata. Eppure questo problema viene specificatamente segnalato nel caso di due activity, non nel caso di una. Come mai?

Un'idea ce l'ho.

C'è un altro particolare che durante lo sviluppo ho ritenuto di poco conto ma che potrebbe essere determinante in questa situazione.
Io lancio la mia activity, inizio una partita multiplayer con service Bluetooth. Quando premo il tasto home e l'avversario gioca una carta io ricevo una notifica. Cliccando sulla notifica apro la app. Nel launchmode standard viene creata una nuova istanza della app. Procedendo a chiuderla col tasto back torno alla istanza precedente e il gioco si svolge regolarmente. Onde evitare di avere istanze multiple ho deciso di utilizzare il flag "singleTask".

L'idea che mi sono fatto io, che non dovrebbe essere diversa dalla tua, è basata su una affermazione che ho letto: il problema in questione non vale solo per l'oggetto Application, ma anche per qualsiasi Singleton che vai a creare (e mi torna perchè anche l'oggetto Application è un Singleton).

Credo che funzioni così: quando avvii l'app, viene prima di tutto creato l'oggetto Application se ancora non esiste, quindi viene lanciata l'activity di apertura. Fintanto che l'activity rimane in primo piano, l'oggetto Application non può essere distrutto. Se porti l'activity in background, ecco che l'applicazione diventa "distruggibile" dal sistema e se accade viene distrutto l'oggetto Application. Ma nello stack rimane l'activity, o meglio rimane il riferimento all'ultima activity aperta di quella applicazione.

Siamo quindi nella situazione di Application distrutta, ma activity nello stack. Se clicchi sull'activity e cerchi di aprirla, secondo me il sistema cerca di fare tutto in modo trasparente come se non avesse distrutto niente, cioè ricrea l'oggetto Application da zero e riapre l'activity usando magari quanto si è salvato con OnSaveInstanceState. Chiaramente se l'activity ricostruita faceva affidamento su dati salvati nell'Application originario, ed assenti in quello nuovo, ecco che si presenta il nullpointer.

L'idea che mi sto facendo, apparentemente bislacca ma forse nemmeno poi tanto.. è che la activity sia creata "separata" rispetto alla application. Nel caso in cui il sistema ripulisca memoria può succedere che scelga di ripulire la application che viene ricreata ma che essendo slegata dalla activity che è dichiarata come singleTask non ne condivida il ciclo di vita.

Come vedi da quanto ho scritto sopra, io penso che l'oggetto Application abbia lo stesso ciclo di vita del Processo dell'app, nel quale girano anche tutte le activity. Al momento in cui nel processo non c'è nessuna activity attiva, secondo me può subire la distruzione. Che poi l'activity rimanga nello stack è un'altra cosa, è come se fosse la "history".

Comunque, se nel tuo caso l'application viene distrutta con le activity sempre in foreground e attive, ovviamente cade completamente la mia ipotesi. Ma sarebbe veramente devastante un framework di questo genere.
NON rispondo a domande nei messaggi privati
Bradipao @ Play Store

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:Application class
« Risposta #6 il: 21 Maggio 2014, 14:50:51 CEST »
0
Comunque, se nel tuo caso l'application viene distrutta con le activity sempre in foreground e attive, ovviamente cade completamente la mia ipotesi. Ma sarebbe veramente devastante un framework di questo genere.
No no.. hai ragione tu perché la activity non rimane in foreground.  La activity richiama un intent di sistema con startActvityForResult e poi viene correttamente richiamato onActivityResult. Il fatto che poi l'intent lanci una dialog piuttosto che altro è irrilevante a quanto ne so. Se io chiamo startActivity la mia activity va in background.