2014-10-28 7 views
7

Dopo aver letto this article, ho iniziato a pensare a perdite di memoria con Volley. Di solito, gli ascoltatori implementati con Volley hanno un riferimento implicito o esplicito alla classe esterna (l'attività). per esempio:In caso di perdite di memoria e utilizzo di WeakReference con Volley in Android

JsonObjectRequest jsonObjReq = new JsonObjectRequest(Request.Method.GET, 
     url, null, 
     new Response.Listener<JSONObject>() { 
      @Override 
      public void onResponse(JSONObject response) { 

       updateLayout(); 
      } 
     } 

in questo caso v'è un riferimento implicito ... o mi può essere utile per creare un costume JsonObjectRequest a interiorizzare la gestione delle risposte, e la necessità di passare un riferimento all'attività di chiamata nel suo costruttore .

Ora diciamo che avvio una richiesta web, ma prima che la risposta ritorni, mi allontano dall'attività che ha avviato la richiesta. Da quello che ho capito, l'oggetto JsonObjectRequest avrebbe mantenuto un riferimento alla mia attività e avrebbe impedito che fosse Garbage Collection.
-Sto che capisco correttamente, è una paura legittima?
- La libreria Volley si occupa automaticamente di questo?
-Se sto creando un oggetto personalizzato JsonObjectRequest e passando un "questo" (riferimento all'attività), devo creare un WeakReference per l'attività?

+1

Dai un'occhiata alla [documentazione del volley] (https://developer.android.com/training/volley/simple.html). Sembra che se ti assicuri di chiamare cancel sulle tue richieste di volley nel metodo 'onStop()' del tuo frammento/attività, il gestore non verrà chiamato. Suppongo che questo significhi anche rimuovere il riferimento al frammento/attività, il che significa che il frammento/attività non è più trapelato. –

+0

@tmalseed grazie, dovresti postare il tuo commento come risposta, e lo accetterò – Siavash

+0

Non sono convinto al 100% che sia la risposta corretta o più appropriata. Ho seguito il mio stesso consiglio e * potrebbe * aver ancora perso l'attività .. –

risposta

5

In base all'osservazione del codice volley, l'annullamento della chiamata non evita realmente la perdita di memoria perché il riferimento non viene mai cancellato e il riferimento non è debole. Calling Cancel evita solo a Volley di fornire la risposta all'ascoltatore.

La mia soluzione al problema dovrebbe essere la clonazione e la modifica della libreria.

  • Una delle soluzioni possono essere fare riferimento di base ErrorListener all'interno di Request.java base per essere riferimento debole. E allo stesso modo può essere fatto allo stesso Listener all'interno di JsonRequest.java.

  • L'altra soluzione può essere quella di cancellare manualmente il riferimento all'annullamento della chiamata. all'interno di cancel(), imposta mErrorListener e mListener su null. Con questa soluzione, però, dovrai rimuovere il modificatore finale dalla dichiarazione del campo altrimenti non ti sarà permesso di impostare il riferimento su null.

Spero che questo aiuti.

+1

Ho implementato l'opzione 2 e finora tutto bene . Ho trovato un'altra perdita dovuta al VolleyLog ma questo è un argomento diverso. – Lancelot

+0

Non c'è bisogno di clonare Volley, davvero. Solo sottoclasse [Richiesta] (https://android.googlesource.com/platform/frameworks/volley/+/2afdd91aba3a7a5396fe96dfe8f930661e56ea9a/src/com/android/volley/Request.java) o [JsonRequest] (https: //android.googlesource .com/piattaforma/framework/volley/+/2afdd91aba3a7a5396fe96dfe8f930661e56ea9a/src/com/android/volley/toolbox/JsonRequest.java) e gestisci tu stesso l'ascoltatore (aggiungendo la parte di cancellazione quando viene chiamato cancel()). – verybadalloc

2

Ho riscontrato perdite di memoria quando uso il volley proprio come il modo in cui scrivi qui. Ogni volta che inizio un nuovo ascoltatore.

Ho usato la fuga di perdite per rilevare perdite.

Quando ho letto del tuo articolo, http://www.androiddesignpatterns.com/2013/01/inner-class-handler-memory-leak.html, e ho utilizzato WeakReference sull'interfaccia di attività e callback (anch'io personalizzato), è stato risolto.

Ho usato il volley come singleton.

public interface VolleyCallback { 
    void onSuccess(JSONObject result); 

    void onFailed(String error); 
} 

private static class SListener implements Response.Listener<JSONObject> { 
    private final WeakReference<Activity> activityWeakReference; 
    private final WeakReference<VolleyCallback> callbackWeakReference; 

    public SListener(Activity activity, VolleyCallback callback) { 
     activityWeakReference = new WeakReference<Activity>(activity); 
     callbackWeakReference = new WeakReference<VolleyCallback>(callback); 
    } 

    @Override 
    public void onResponse(JSONObject jsonObject) { 
     Activity act = activityWeakReference.get(); 
     VolleyCallback vc = callbackWeakReference.get(); 
     if (act != null && vc != null) { 
      LogUtil.d(TAG, act.toString() + " " + jsonObject.toString()); 
      something you need to do; 
      vc.onSuccess(jsonObject); 
     } 
    } 

Ho letto anche questa risposta, How to use WeakReference in Java and Android development?, la seconda risposta dare un esempio, proprio come il vostro articolo provide.It di buono.

1

Sono probabilmente in ritardo per questa festa di un anno, ma ho appena trovato un modo per risolvere questo problema. Eccolo:

public interface VolleyCallback { 
    void onSuccess(JSONObject result); 

    void onFailed(String error); 
} 

private static class SListener implements VolleyCallback { 
    private final WeakReference<MainActivity> activityWeakReference; 

    public SListener(MainActivity activity, VolleyCallback callback) { 
     activityWeakReference = new WeakReference<>(activity); 
    } 
@Override 
    void onSuccess(JSONObject result){ 
} 
@Override 
    void onFailed(String error){ 
    } 
    } 

qui è possibile utilizzare activityWeakReference.get() per accedere anche a tutti gli elementi dell'interfaccia di MainActivity. Trovato questo da http://www.androiddesignpatterns.com/2013/01/inner-class-handler-memory-leak.html. In questo modo non è necessario annullare alcuna richiesta in onStop(). Ricordarsi di usare activityWeakReference.get().isFinishing & & activityWeakReference.get()!=null per evitare arresti anomali quando l'attività non esiste.

+0

Ciao, sto riscontrando lo stesso problema e ho trovato la tua risposta, ti dispiacerebbe condividere dove mettere il codice sopra, come come implementarlo. Ecco il mio esempio di implementazione di Volley nella mia app. https://gist.github.com/arvi/587b2f4cb582ad96c98645212e7b2baf Grazie mille. – Woppi

+0

È necessario creare una nuova classe interna statica e implementare il nuovo Response.Listener e passare un riferimento debole. –

Problemi correlati