java - 这是我的代码还是 Firebase 代码导致了这次泄漏?

标签 java android memory-leaks firebase leakcanary

我创建的应用程序中出现大量内存泄漏。我创建了一个非常简单的应用程序来重现该问题。此应用程序仅引用 FirebaseDatabase 并设置一个 ChildEventListener。当用户单击该按钮时,它会向数据库中添加一条记录,并启动一个执行 System.gc() 的新 Activity 。

多次按下按钮将导致 Leak Canary 生成转储。

主要 Activity .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();
    }
}

由于帖子限制,泄漏金丝雀日志为here.

我的代码是不是做错了什么,或者这与 Firebase 有关?

编辑: @qbix 的回答似乎有效。对于其他人,这是 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) {

        }
    };
}

最佳答案

我没有使用过 LeakCanary,所以这只是一个有根据的猜测。

ChildEventListeners 需要为 unregistered当不再需要它们时。通常在 Activity 生命周期方法中添加和删除监听器,例如 onCreate()onDestroy()。不要创建匿名监听器,而是创建该类型的对象并使用 Query.removeEventListener() 将其删除当不再需要查看是否消除泄漏报告时。

关于java - 这是我的代码还是 Firebase 代码导致了这次泄漏?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38882460/

相关文章:

java - 将 Android Studio Java 应用程序上传到 GitHub

java - 如何在android中设置按钮监听器

android - 如何在 Kotlin 中获取 Android 设备 token 以用于 Firebase 云消息传递

java - 约束布局自定义页脚

android - Android 上的 OutOfMemory 异常

memory-management - 内存调试 : How to get locked pages information in user space/kernel space in linux

java - 如何验证文件是否正确上传?

java - permgen 是否包含在 -Xmx 中?

Android:解析具有大属性且内存使用率低的 JSON 文件

iphone - 仪器(泄漏)和 NSDateFormatter