在显示其他类的吐司时出现内存泄漏

时间:2019-07-17 18:48:44

标签: android firebase-realtime-database memory-leaks leakcanary

我正在使用泄漏金丝雀来检测内存泄漏。从我的活动中,我正在调用其他类的方法来更新 firebase实时数据库中的数据,在addOnCompleteListener()上我展示了成功的祝酒词,在addOnFailureListener()上展示了成功的祝酒词。显示错误的吐司。由于Toast需要上下文,所以我已经扩展Application来获取应用程序上下文,因为我没有从活动中传递上下文,因为阅读了一些文章后,我知道传递上下文会导致内存不足泄漏。这是我要在数据库中更新的课程。

public class FirebaseUpdaterr extends Application {

    private Context context;
    private DatabaseReference ref=FirebaseDatabase.getInstance().getReference();
    private FirebaseUser user= FirebaseAuth.getInstance().getCurrentUser();
    public FirebaseUpdaterr(){
        this.context=getApplicationContext();
    }
    public void retriveBook(String bookId, final BookInfo bookInfo){

        final Book[] book = new Book[1];
        ref.child("Books").child(bookId).addListenerForSingleValueEvent(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                book[0] =dataSnapshot.getValue(Book.class);
                bookInfo.onCallback(book[0]);
            }

            @Override
            public void onCancelled(@NonNull DatabaseError databaseError) {

            }
        });
    }

    public void accept(final BookRequestData bookRequestData){

        retriveBook(bookRequestData.getReqBookId(), new BookInfo() {
            @Override
            public void onCallback(Book book) {


                Map<String, Object> childUpdates = new HashMap<>();

                childUpdates.put("/Books/"+bookRequestData.getReqBookId(),book);
                childUpdates.put("/Requests/"+bookRequestData.getReqId()+"/status",StaticValues.REQUESTE_ACCEPTED);
                ref.updateChildren(childUpdates)
                        .addOnCompleteListener(new OnCompleteListener<Void>() {
                            @Override
                            public void onComplete(@NonNull Task<Void> task) {
                                if(task.isSuccessful()){
                                    Toasty.success( context, bookRequestData.getReqUserName()+"'s request accepted", Toast.LENGTH_SHORT, true).show();

                                }
                            }
                        })
                        .addOnFailureListener(new OnFailureListener() {
                            @Override
                            public void onFailure(@NonNull Exception e) {
                                Toasty.error(context, bookRequestData.getReqUserName()+"'s request is not accepted", Toast.LENGTH_SHORT, true).show();
                            }
                        });

            }
        });

    }
}

我的BookInfoActivity大。我仅添加了Memory leaks的可能原因。

public class BookInfoActivity extends AppCompatActivity {

   @Override
    public void onCreate(Bundle savedInstanceState) {
      BookViewModelFactory modelFactory=new BookViewModelFactory(bookLight.getBookId());
      BookViewModel viewModel = ViewModelProviders.of(this,modelFactory).get(BookViewModel.class);

      LiveData<Book> liveData = viewModel.getBookLiveData();
       liveData.observe(this, new Observer<Book>() {
            @Override
            public void onChanged(Book bookLive) {
               //other stuffs
           }

       checkSameReq(new FirebaseCallBack() {
            @Override
            public void onCallback(final BookRequestData reqData) {
                requestBtn.setOnClickListener(new View.OnClickListener() 
                {
                  if(requested){
                      FirebaseUpdaterr fireUpdate=new FirebaseUpdaterr();
                      fireUpdater.accept(bookRequest);
                    }
                   }
                });
              }
        });

    }



  private void checkSameReq( final FirebaseCallBack firebaseCallBack) {
        ref = mdatabase.getReference();
        sameReqCheck=ref.child("Users").child(book.getOwnerID()).child("pendingRequest").orderByChild("reqUserId").equalTo(user.getUid());
        sameReqCheckValEventListener=new ValueEventListener() {

            @Override
            public void onDataChange(DataSnapshot dataSnapshot) {
                boolean sameReqCheck=false;
                final BookRequestData[] requestData = {null};
                Log.e("shanto2", String.valueOf(dataSnapshot.getChildrenCount()));
                for (DataSnapshot reqSnapshot: dataSnapshot.getChildren()) {

                    BookRequestData bookRequestData=reqSnapshot.getValue(BookRequestData.class);
                    if(bookRequestData.getReqBookId().equals(book.getBookId())){

                        sameReqCheck=true;
                        requestData[0] =bookRequestData;
                        break;

                    }

                }

                if(!sameReqCheck){
                    requestBooks.setText(REQUEST_BOOK);
                }else{

                    requestBooks.setText(CANCEL_REQUEST);

                }
                bookStatusSetter(book);

                if(book.getAcceptedReqId().length()>0){
                     requestRef=ref.child("Requests").child(book.getAcceptedReqId());
                    reqEventListener=new ValueEventListener() {
                        @Override
                        public void onDataChange(@NonNull DataSnapshot dataSnapshot) {

                            BookRequestData bookRequestData=dataSnapshot.getValue(BookRequestData.class);


                            if(book.getCurrentOwnerId().equals(user.getUid()) && bookRequestData.getStatus()==StaticValues.REQUESTE_ACCEPTED){
                                requestBooks.setText(GOT_IT);
                                requestData[0] =bookRequestData;
                            }
                            firebaseCallBack.onCallback(requestData[0]);


                        }

                        @Override
                        public void onCancelled(@NonNull DatabaseError databaseError) {

                        }
                    };
                    requestRef.addValueEventListener(reqEventListener);
                }else {
                    firebaseCallBack.onCallback(requestData[0]);
                }

            }

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

        sameReqCheck.addListenerForSingleValueEvent(sameReqCheckValEventListener);

    }

}

leakcanary 检查后,我发现以下日志,错误在哪里?

Logs of leak canary

3 个答案:

答案 0 :(得分:0)

我认为造成内存泄漏的原因是因为您保留了一个实例 private Context context;,并且永远不要保留上下文实例。尝试重做此操作,以便从调用代码的实际活动/视图/应用程序中获取上下文,而不是将其保存到局部变量中,因为此实例将永远不会被破坏

将名为accept的方法更改为也直接接受一个上下文并通过调用它的活动,而不使用保存在应用程序变量中的上下文。

public void accept(final BookRequestData bookRequestData, Context context)

,然后只需从其他任何活动调用fireUpdater.accept(bookRequest, this);。将上下文实例保留为局部变量绝不是一个好主意。

答案 1 :(得分:0)

存储应用程序上下文这不是一个好习惯,但它不会导致内存泄漏,因为您只有1个应用程序实例。很难看到发生了什么,但是应该避免内联侦听器和回调。我建议将侦听器和回调存储在prívate属性中。在活动开始时初始化它们,然后在活动停止时将它们设置为空。

答案 2 :(得分:0)

提供的泄漏跟踪没有显示您的代码,这很可能是Android泄漏。这可能是AOSP中的错误,也可能是制造商实施中的错误。您可以将此信息提供给LeakCanary(Android SDK /支持库中的https://github.com/square/leakcanary/issues/new/choose => Leak),并提供Android API版本和制造商,以便在将来的版本中将其标记为“库泄漏”。