我正在使用泄漏金丝雀来检测内存泄漏。从我的活动中,我正在调用其他类的方法来更新 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 检查后,我发现以下日志,错误在哪里?
答案 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版本和制造商,以便在将来的版本中将其标记为“库泄漏”。