2010-10-21 6 views
7

Tutti,NDK Android: come pulire il codice nativo dopo aver riavviato l'attività?

Sono consapevole del fatto che per impostazione predefinita un'attività viene interrotta e riavviata quando l'orientamento dello schermo cambia, o una tastiera viene inserita o estratta. (Vedi Activity restart on rotation Android). La mia domanda è, qual è il modo corretto per gestire questo da una prospettiva di codice nativo? per esempio. se ho un blocco statico che carica una libreria nativa e la mia app viene riavviata, come faccio a garantire che qualsiasi memoria nella terra natia sia gestita in modo appropriato? Il problema è

Quando ruotiamo il dispositivo, sembra come un pool di thread viene creata e quelli vecchi non vengono mai rimossi. Questo significa che ogni volta che qualcuno trasforma il dispositivo, abbiamo una tonnellata più discussioni le mani in mano e prendendo memoria

Come faccio a garantire che ciò non accada? Vedo dalle JNIExample page alcune note in fondo:

[*] Questioni irrisolte e bug Anche se l'esempio è completamente funzionali, ci sono un paio questioni irrisolte residuo che mi non ero in grado di capire fino ad ora. I problemi appaiono quando si avvia l'attività , quindi si preme il pulsante Indietro per nasconderlo, quindi lo si riavvia. In base alla mia esperienza, le chiamate alle funzioni native in tale attività riavviata avranno esito negativo in modo spettacolare. callVoid() si blocca semplicemente con un errore di segmentazione , mentre le chiamate verso getNewData() e getDataString() causa JVM per interrompere con un errore, perché non è più contento della cache globalmente oggetto riferimento. Sembra che il riavvio di attività invalida in qualche modo i nostri cache riferimenti agli oggetti, anche se sono protette con NewGlobalRef(), e l'attività è in esecuzione all'interno del JVM originale (riavvio attività non non significa che JVM stessa è rinnovate) . Non ho una buona spiegazione del sul motivo per cui ciò accade, quindi se avete idee, per favore, datemi il numero .

È stato risolto?

risposta

6

Il riavvio in Android NDK è fastidioso. Qualsiasi dato statico in cui ci si muove, perché riutilizza il processo, quindi è necessario reimpostare manualmente tutto ciò che non sarà valido in una nuova esecuzione (come qualsiasi oggetto OpenGL o buffer di vertice).Ti offre un nuovo thread Java e una nuova applicazione Java e altri oggetti, quindi è necessario cancellare anche tutti i riferimenti globali memorizzati nella cache agli oggetti che sarebbero nuovi in ​​una nuova istanza della tua app.

Quindi la strategia che uso è duplice: ridurre al minimo riavvia e riavvia tutto.

Si minimizzano i riavvii gestendo le configChanges in-app, come si dice nella risposta alla domanda collegata. Quindi l'apertura di una tastiera o la rotazione non provocano il riavvio di un'app, che è come dovrebbe essere per qualsiasi app con tempi di avvio non banali.

E quando ho rilevato che è stata avviata una nuova istanza della mia app, rilascio tutto ciò che è critico dalla vecchia istanza in quel punto, incluso il rilascio di qualsiasi oggetto Java trattenuto tramite NewGlobalRef. Ho provato a ridurre al minimo i dati statici, ma i pochi punti inevitabili in cui mi tengo attorno agli oggetti statici li cancello quando rilevo la nuova istanza all'avvio.

I vecchi thread dovrebbero andare via una volta che non ci sono più riferimenti eccezionali a loro (vale a dire, una volta che hai rilasciato tutti gli oggetti NewGlobalRef).

2

Se la macchina virtuale viene riavviata, si inizia da capo. Altrimenti, lo stato è giusto dove l'hai lasciato. Non esiste alcuna invalidazione dei riferimenti agli oggetti memorizzati nella cache che rimuove le cose da NewGlobalRef. Ho scritto alcune altre note sull'articolo on the NDK mailing list di wooyd.

Se si dispone di dati che devono essere inizializzati al riavvio dell'attività, è necessario aggiungere una chiamata di inizializzazione esplicita alla propria attività (in onCreate, penso). Assicurati di scartare correttamente qualsiasi materiale che hai conservato nel round precedente - DeleteLocalRef quindi archivia NULL, non solo memset() a zero.