有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

Firebase Android PhoneAuthProvider的java内存泄漏

Firebase->;PhoneAuthProvider->;VerifyPhoneNumber正在泄漏。我相信,这可能是OnVerificationStateChangedCallbacks,我们正在通过电话发送给verifyPhoneNumber

复制步骤:

  1. 启动应用程序
  2. 选择“PhoneAuthActivity”进行基于电话的身份验证
  3. 发送电话号码
  4. 点击后退

单击“上一步”时,会出现泄漏的内存

有人也有同样的问题吗?有解决办法吗

public void FirebasePhoneUser(String phoneNumber) {
            mCallback = new PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
                @Override
                public void onVerificationCompleted(PhoneAuthCredential phoneAuthCredential) {
                    Log.d("Completed","");
                }
                @Override
                public void onVerificationFailed(FirebaseException e) {
                    Log.d("Error","");
                }

                @Override
                public void onCodeSent(String verificationId,
                                  PhoneAuthProvider.ForceResendingToken forceResendingToken) {
                    Log.d("onCodeSent", "");
                }
            };
            phoneAuthProvider = PhoneAuthProvider.getInstance();
            phoneAuthProvider.verifyPhoneNumber(
                    phoneNumber,
                    30,
                    TimeUnit.SECONDS,
                    TaskExecutors.MAIN_THREAD,
                    mCallback
            );
}

共 (1) 个答案

  1. # 1 楼答案

    考虑到API很糟糕,而且没有取消订阅的选项,您有几个选项可以解决这个问题

    1. 代理或装饰。创建另一个OnVerificationStateChangedCallbacks,将方法调用委托给另一个实例:
    // this class must be either top-level or 'static'!
    public /*static*/ final class DelegatingVerificationStateCallbacks
        extends PhoneAuthProvider.OnVerificationStateChangedCallbacks
        implements Closeable {
        @Nullable private PhoneAuthProvider.OnVerificationStateChangedCallbacks delegate;
        public DelegatingVerificationStateCallbacks(
            @NonNull PhoneAuthProvider.OnVerificationStateChangedCallbacks delegate
        ) {
            this.delegate = delegate;
        }
    
        @Override public void onCodeSent(
            @NonNull String verificationId,
            @NonNull PhoneAuthProvider.ForceResendingToken forceResendingToken
        ) {
            if (delegate != null) delegate.onCodeSent(verificationId, forceResendingToken);
        }
        @Override public void onCodeAutoRetrievalTimeOut(@NonNull String s) {
            if (delegate != null) delegate.onCodeAutoRetrievalTimeOut(s);
        }
        @Override public void onVerificationCompleted(@NonNull PhoneAuthCredential phoneAuthCredential) {
            if (delegate != null) delegate.onVerificationCompleted(phoneAuthCredential);
        }
        @Override public void onVerificationFailed(@NonNull FirebaseException e) {
            if (delegate != null) delegate.onVerificationFailed(e);
        }
    
        @Override public void close() {
            delegate = null;
        }
    }
    

    我已经实现了Closeable来进行清理,但您可以实现RxJava的Disposable或其他任何东西

    这里的使用模式是显而易见且众所周知的:

    public final class SomeScreen extends ActivityOrFragmentOrControllerOrWhatever {
        private final ArrayList<Closeable> disposeBag = new ArrayList<>();
        private void performAuth() {
            DelegatingVerificationStateCallbacks callbacks =
                new DelegatingVerificationStateCallbacks(
                    new OnVerificationStateChangedCallbacks() { … }
                );
            disposeBag.add(callbacks);
            phoneAuthProvider.verifyPhoneNumber(…, callbacks);
        }
        @Override protected void onDestroy() {
            for (Closeable c : disposeBag) {
                try { c.close(); }
                catch (IOException ignored) { }
            }
            disposeBag.clear();
        }
    }
    

    结果:Firebase泄漏了一个空的廉价DelegatingVerificationStateCallbacks的引用,而不是活动

    1. 把你自己的引用置零。你可以采用上面介绍的方法来清除自己对活动的引用。这意味着这些引用必须是显式的,即类不能是匿名的,也不能是活动内部的。您必须完全控制类构造函数和字段,顶级类或嵌套的static类非常适合

    2. 弱引用。这不太明确,而且涉及一些间接操作,但仍然有效:实例化顶级或嵌套的static类,将活动传递给构造函数,将其包装在WeakReference中,并分配给字段。仅此而已,一段时间后WeakReference#get将开始返回null

    3. 反思。非常糟糕且不稳定的选择,在其他情况下可能会有所帮助。有时,您的活动可能会被Android SDK或特定于供应商的代码泄露,上述选项不适用。然后你可以自己清空一些私有字段。不要为Firebase这么做