2015-02-01 9 views
10

Kiedy używam GlobalLayoutListener, aby zobaczyć, czy SoftKeyboard jest otwarty, czy nie, fragment nie jest już zbuforowany po zniszczeniu.view.getViewTreeObserver(). AddOnGlobalLayoutListener wycieki Fragment

Co robię:

  • usunąć Listener w onDestroy() mojego Fragment
  • ustawić słuchacza null w onDestroy()
  • ustawić na stanowisku, że jest obserwowany na null w onDestroy()

Nadal wycieka fragment.

Czy ktoś miał podobny problem i zna poprawkę?

My onDestroy:

@Override 
public void onDestroy(){ 
    Log.d(TAG , "onDestroy"); 

    if(Build.VERSION.SDK_INT < 16){ 
     view.getViewTreeObserver().removeGlobalOnLayoutListener(gLayoutListener); 
    }else{ 
     view.getViewTreeObserver().removeOnGlobalLayoutListener(gLayoutListener); 
    } 

    view = null; 
    gLayoutListener = null; 



    super.onDestroy(); 
    } 
+0

Czy mógłbyś pokazać swoją metodę 'onDestroy'? –

+0

@marcel, wysłałem możliwe rozwiązanie dla ciebie. –

Odpowiedz

0

Zamiast tego, można spróbować stworzyć niestandardowy układ i umieścić to jako widoku głównego w swojej xml.

class CustomLayout extends LinearLayout{ 
     public CustomLayout(Context context, AttributeSet attrs) { 
      super(context, attrs);  
     } 

} 

Następnie zastąpić onsizechanged metodę

@Override 
protected void onSizeChanged(int w, int h, int oldw, int oldh) { 
    super.onSizeChanged(w, h, oldw, oldh); 
    if (h < oldh) { 
     // there is a difference, means keyboard is open. 
    } else { 

    } 
} 

Jestem przy założeniu, że aplikacja obsługuje tylko jeden tryb (pionową lub poziomą)

Aktualizacja:

Czy wszystko w

@Override 
public void onDestroyView(){ 
    super.onDestroyView(); 

} 

Ponieważ myślę, że inicjujesz słuchacza w onCreateView(), więc słuchacz powinien zostać usunięty w onDestoryView(). onDestroy() zostanie wywołany tylko wtedy, gdy fragment zostanie zniszczony, a nie podczas zmiany stanu.

Sprawdź Fragment life cycle

0

miałem ten sam problem, ale postanowiłem go usuwając słuchacza w onDestroy(). Zwróć uwagę, że metoda użycia zmieniła się wokół JellyBean.

@Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 
      mView.getViewTreeObserver().addOnGlobalLayoutListener(mGlobalLayoutListener); 
    } 

    @Override 
    public void onDestroy() {  
     if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { 
      mView.getViewTreeObserver().removeGlobalOnLayoutListener(mGlobalLayoutListener); 
     } else { 
      mView.getViewTreeObserver().removeOnGlobalLayoutListener(mGlobalLayoutListener); 
     } 

     super.onDestroy(); 
    } 
+1

Ja to robię. Nadal przecieka fragment ... – marcel12345689

+0

podczas analizy zrzutu sterty, czy odniesienie do twojego fragmentu jest nadal przechowywane w liście obserwatorów drzewa? Jeśli tak jest, może spróbuj zachować odniesienie do obiektu, który pierwotnie otrzymałeś z getViewTreeObserver(). Może jakoś zmieniło się to pomiędzy onCreate i onDestroy? –

+0

@JakeHall Twoja sugestia nie działa dla mnie. –

1

No, może to trochę przesada, ale trudno powiedzieć coś na pewno bez źródeł, więc spróbuj tego. Spraw, aby Twoja gLayoutListener stała się wewnętrzną klasą (aby nie zachować silnego odniesienia do twojego fragmentu).

Jeśli chcesz wykonać pewne operacje z fragmentem lub jego polami wewnątrz detektora, utwórz WeakReference<YourFragment> wewnątrz konstruktora niestandardowej klasy nasłuchiwania i uzyskaj dostęp do fragmentu za pomocą tego odwołania. Nie zapomnij o sprawdzeniu weakref.get() != null.

17

Uważam, że zdecydowanie usunięcie odbiornika, do którego odwołuje się obiekt View, w onDestroy() jest za późno. Ta metoda zastąpienia występuje po onDestroyView(), która ma "... wyczyścić zasoby powiązane z jej widokiem". Zamiast tego możesz użyć tego samego kodu w onStop(). Chociaż nie użyłem tej techniki.

Mogę zasugerować ten kod, którego użyłem bez żadnych problemów z debuggerem.

// Code below is an example. Please change it to code that is more applicable to your app. 
final View myView = rootView.findViewById(R.id.myView); 
myView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { 
    @SuppressLint("NewApi") @SuppressWarnings("deprecation") 
    @Override 
    public void onGlobalLayout() { 

     // Obtain layout data from view... 
     int w = myView.getWidth(); 
     int h = myView.getHeight(); 
     // ...etc. 

     // Once data has been obtained, this listener is no longer needed, so remove it... 
     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { 
      myView.getViewTreeObserver().removeOnGlobalLayoutListener(this); 
     } 
     else { 
      myView.getViewTreeObserver().removeGlobalOnLayoutListener(this); 
     } 
    } 
}); 

Uwagi:

  • Od getViewTreeObserver służy do układów, zazwyczaj trzeba ten słuchacza tylko przez krótki czas. Dlatego słuchacz jest natychmiast usuwany.
  • Drugie połączenie z removeOnGlobalLayoutListener() powinno być przekreślone przez Studio, ponieważ nie jest dostępne przed JELLY_BEAN.
  • Kod Pragma @SuppressWarnings("deprecation") nie jest wymagany, jeśli używasz Androida Studio.
  • Kod myView = rootView.findViewById(R.id.myView); może wymagać zmiany na bardziej odpowiedni kod do aplikacji lub sytuacji.
+1

To wygląda na bardzo czyste rozwiązanie i udało mi się rozwiązać problem wycieku pamięci. Musiałem wprowadzić kilka poprawek/dodatków do kodu (odpowiednio zredagowałem twoją odpowiedź). Czy możesz jednak po prostu potwierdzić, że mam rację używając 'int w = myView.getWidth();' zamiast 'int w = viewTemp.getWidth();'? Czy możesz doradzić, dlaczego w ogóle używasz opcji 'viewTemp' - tzn. Dlaczego nie należy finalnie tworzyć' myView'? –

+0

@ ban-geoengineering, Zgadzam się, że myView może zostać zadeklarowany jako ostateczny w zamieszczonym przykładzie, zmienił go. Jednak w mojej sytuacji nie mogłem zmienić deklaracji bezpośrednio, ponieważ korzystałem z metody nadpisania getView(). –

+1

@ marcel12345689 Powinieneś wybrać tę odpowiedź jako prawidłową (oczywiście, jeśli działa ona dla ciebie). –

0

Też miałem ten problem w niestandardowym widoku. Zarejestrowałem obiekt onPreDrawListener w widoku potomnym w niestandardowym konstruktorze widoków i wyrejestrowałem go w postaci onDetachedFromWindow. Utrzymał się wyciek pamięci. Aby go rozwiązać spróbowałem wszystkiego, ale w końcu musiałem napisać alternatywny mechanizm nie oparty na TreeObserver.

Powiązane problemy