2016-08-10 7 views
0

Ich bin viel Speicherlecks in einer Anwendung bekomme ich erstellt. Ich habe eine sehr einfache App erstellt, um das Problem zu reproduzieren. Diese Anwendung verweist nur auf die FirebaseDatabase und richtet einen ChildEventListener ein. Wenn der Benutzer auf die Schaltfläche klickt, fügt er der Datenbank einen Datensatz hinzu und startet eine neue Aktivität, die System.gc() ausführt.Ist das mein Code oder Code Firebase verursacht dieses Leck?

die mehrmals Taste wird Leak Canary verursachen einen Dump zu erzeugen.

MainActivity.java:

public class MainActivity extends AppCompatActivity { 

private FirebaseDatabase firebaseDatabase; 
private DatabaseReference dbRef; 

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_main); 


    firebaseDatabase = FirebaseDatabase.getInstance(); 
    dbRef = firebaseDatabase.getReference("leak"); 
    dbRef.addChildEventListener(new ChildEventListener() { 
     @Override 
     public void onChildAdded(DataSnapshot dataSnapshot, String previousChildName) { 
     } 

     @Override 
     public void onChildChanged(DataSnapshot dataSnapshot, String previousChildName) { 
     } 

     @Override 
     public void onChildRemoved(DataSnapshot dataSnapshot) { 

     } 

     @Override 
     public void onChildMoved(DataSnapshot dataSnapshot, String previousChildName) { 
     } 

     @Override 
     public void onCancelled(DatabaseError databaseError) { 
     } 
    }); 

    findViewById(R.id.btn_leak).setOnClickListener(new View.OnClickListener() { 
     @Override 
     public void onClick(View view) { 
      dbRef.child(UUID.randomUUID().toString()).setValue("Yes"); 
      Intent leakIntent = new Intent(getApplicationContext(), LeakActivity.class); 
      startActivity(leakIntent); 
     } 
    }); 

} 

}

LeakActivity.java:

public class LeakActivity extends AppCompatActivity { 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.leak); 

     System.gc(); 
    } 
} 

Aufgrund der Post zu begrenzen, das Leck Kanarienvogel Protokoll wird here.

Bin ich tun stimmt etwas in meinem Code nicht oder hängt das mit Firebase zusammen?

EDIT: @ qbix Antwort schien zu arbeiten. Für andere, hier ist die Arbeitsversion von MainActivity.java:

public class MainActivity extends AppCompatActivity { 

private FirebaseDatabase firebaseDatabase; 
private DatabaseReference dbRef; 
private ChildEventListener dbListener; 

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_main); 


    firebaseDatabase = FirebaseDatabase.getInstance(); 
    dbRef = firebaseDatabase.getReference("leak"); 
    dbListener = getDbListener(); 
    dbRef.addChildEventListener(dbListener); 

    findViewById(R.id.btn_leak).setOnClickListener(new View.OnClickListener() { 
     @Override 
     public void onClick(View view) { 
      dbRef.child(UUID.randomUUID().toString()).setValue("Yes"); 
      Intent leakIntent = new Intent(getApplicationContext(), LeakActivity.class); 
      startActivity(leakIntent); 
     } 
    }); 
} 

@Override 
protected void onStop() { 
    dbRef.removeEventListener(dbListener); 
    super.onStop(); 
} 

private ChildEventListener getDbListener(){ 
    return new ChildEventListener() { 
     @Override 
     public void onChildAdded(DataSnapshot dataSnapshot, String s) { 

     } 

     @Override 
     public void onChildChanged(DataSnapshot dataSnapshot, String s) { 

     } 

     @Override 
     public void onChildRemoved(DataSnapshot dataSnapshot) { 

     } 

     @Override 
     public void onChildMoved(DataSnapshot dataSnapshot, String s) { 

     } 

     @Override 
     public void onCancelled(DatabaseError databaseError) { 

     } 
    }; 
} 

}

Antwort

1

Ich habe LeakCanary nicht verwendet wird, so ist dies nur eine Vermutung.

ChildEventListeners Notwendigkeit unregistered sein, wenn sie nicht mehr benötigt werden. Oft werden die Zuhörer hinzugefügt und in der Aktivität Lifecycle Methoden, wie onCreate() und onDestroy() entfernt. Statt einen anonymen Zuhörer zu schaffen, ein Objekt dieser Art zu erstellen und Query.removeEventListener() mit entfernen, wenn nicht mehr benötigt werden, um zu sehen, ob das dem Leck Bericht beseitigt.

0

Ich denke, das ist besser, Listener innerhalb der onStart()/onStop() - oder onCreate()/onDestroy() - Rückrufe jeweils hinzufügen/entfernen.

Wenn ein Listener in onCreate() hinzugefügt und in onStop() entfernt wurde, kann eine Situation auftreten, in der eine Aktivität ohne Aufruf von onCreate() wiederhergestellt wird, aber Aufruf von onStart() und Listener nicht gesetzt werden .

https://developer.android.com/images/activity_lifecycle.png