gpt4 book ai didi

android - 修复由 Leak Canary 发现的 Activity 内存泄漏

转载 作者:行者123 更新时间:2023-12-05 06:14:32 25 4
gpt4 key购买 nike


Leak Canary 显示我的 Activity 有泄漏,但我不明白泄漏的原因。

我试图从 Activity 中移除零件以检查泄漏的来源,但没有奏效。我还从 Activity 中删除了所有内容,但仍然得到相同的结果。经过这些测试和许多其他测试后,我假设将我发送到 PostDetailActivity 的 Activity 有问题;还是我错了?

我是新手。对 Activity 的实现方式感到抱歉。

这是 Activity

    public class PostDetailActivity extends AppCompatActivity {

//details of user and post
String myUid, myName, myProfilPic, postId, pLikes, pDislike, pTitle, pTime, pImage, pUserPic, pUserName;

private DatabaseReference likesRef;
private DatabaseReference dislikeRef;
boolean mProcessLike = false;
boolean mProcessDislike = false;
Integer position, dislike, like;


//post views
ImageView userPicture, postImage;
TextView userName, postTime, postTitle;
Button likeBtn, dislikeBtn, shareBtn;
LinearLayout profileLayout, emptyRecycler, commentExtraSpace;
public RecyclerView recyclerView;
NestedScrollView scrollView;

public static List<Comment> commentList;
CommentAdapter commentAdapter;

//add comments views;
EditText commentEt;
ImageButton sendCommentBtn;
ImageView userCommentImage;

Comment replyComment;

@Override
protected void onCreate(Bundle savedInstanceState) {

// DARK/LIGHT THEME CODE START
if (DarkThem) {
setTheme(R.style.DarkTheme);

} else {
setTheme(R.style.LightTheme);

}
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_post_detail);

myUid = FirebaseAuth.getInstance().getCurrentUser().getUid();
likesRef = FirebaseDatabase.getInstance().getReference().child("Likes");
dislikeRef = FirebaseDatabase.getInstance().getReference().child("Dislikes");

Toolbar toolbar = findViewById(R.id.toolBar);
setSupportActionBar(toolbar);
getSupportActionBar().setTitle("");
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
PostFragment.relogPost(position);
onBackPressed();

}
});

//getting post info with intent
Intent intent = getIntent();
postId = intent.getStringExtra("postId");
pLikes = intent.getStringExtra("pUp");
pDislike = intent.getStringExtra("pDown");
pTitle = intent.getStringExtra("pTitle");
pTime = intent.getStringExtra("pTime");
pImage = intent.getStringExtra("pImage");
pUserPic = intent.getStringExtra("uDp");
pUserName = intent.getStringExtra("uName");
try {
String positionList = intent.getStringExtra("position");
position = Integer.parseInt(positionList);
} catch (Exception e) {

}
//initializing views post
userPicture = findViewById(R.id.userPic);
postImage = findViewById(R.id.pImage);
userName = findViewById(R.id.userNamePost);
postTime = findViewById(R.id.pTime);
postTitle = findViewById(R.id.pTitle);
likeBtn = findViewById(R.id.upBtn);
dislikeBtn = findViewById(R.id.dwnBtn);
shareBtn = findViewById(R.id.shareBtn);
profileLayout = findViewById(R.id.profileLayout);
recyclerView = findViewById(R.id.recyclerView);
scrollView = findViewById(R.id.scrollView);
emptyRecycler = findViewById(R.id.emptyRecycler);
commentExtraSpace = findViewById(R.id.commentExtraSpace);

//initializing views comment
commentEt = findViewById(R.id.commentEt);
sendCommentBtn = findViewById(R.id.sendComment);
userCommentImage = findViewById(R.id.userCommentImage);

//convert time to dd//mm//yyyy hh:mm am/pm
Calendar calendar = Calendar.getInstance(Locale.getDefault());
calendar.setTimeInMillis(Long.parseLong(pTime));
String pTimeshown = DateFormat.format("dd/MM/yyyy hh:mm aa", calendar).toString();


//set data for PostDetails
userName.setText(pUserName);
postTime.setText(pTimeshown);
postTitle.setText(pTitle);
likeBtn.setText(pLikes);
dislikeBtn.setText(pDislike);


//Set user pic
if (pUserPic.equals("default")) {
userPicture.setImageResource(R.mipmap.ic_launcher_round);
} else {
try {
Glide.with(this).load(pUserPic).into(userPicture);
} catch (Exception e) {

}
}

//Setting postPicture
if (pImage.equals("default")) {
postImage.setImageResource(R.drawable.sunset);
} else {
try {
Glide.with(this).load(pImage).into(postImage);
} catch (Exception e) {

}
}


setLikes(postId);
setDislike(postId);
loadComments();


sendCommentBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
sendComment();
commentList.add(replyComment);
commentAdapter.notifyDataSetChanged();
scrollView.post(new Runnable() {
@Override
public void run() {
scrollView.scrollTo(0, recyclerView.getBottom());
}
});
}
});


dislikeBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
pDislike = dislikeBtn.getText().toString();
pLikes = likeBtn.getText().toString();
mProcessDislike = true;
dislikeRef.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {

if (mProcessDislike) {
if (dataSnapshot.child(postId).hasChild(myUid)) {
//already disliked ,so remove dislike
dislikeRef.child(postId).child(myUid).removeValue();
mProcessDislike = false;
dislikeBtn.setText(MessageFormat.format("{0}", Integer.parseInt(pDislike) - 1));
postList.get(position).setpDown("" + (Integer.parseInt(pDislike) - 1));
dislike = Integer.parseInt(pDislike) - 1;
postList.get(position).setpDown("" + dislike);
dislikeBtn.setCompoundDrawablesRelativeWithIntrinsicBounds(R.drawable.ic_downvote_black, 0, 0, 0);
} else {
//not liked
likesRef.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
//verifying is user has liked the post
if (dataSnapshot.child(postId).hasChild(myUid)) {
likesRef.child(postId).child(myUid).removeValue();
dislikeRef.child(postId).child(myUid).setValue("-1");
likeBtn.setText(MessageFormat.format("{0}", Integer.parseInt(pLikes) - 1));
postList.get(position).setpUp("" + (Integer.parseInt(pLikes) - 1));
dislike = Integer.parseInt(pDislike) + 1;
dislikeBtn.setText(MessageFormat.format("{0}", dislike));
postList.get(position).setpDown("" + dislike);
} else {
dislikeRef.child(postId).child(myUid).setValue("-1");
dislike = Integer.parseInt(pDislike) + 1;
dislikeBtn.setText(MessageFormat.format("{0}", dislike));
postList.get(position).setpDown("" + dislike);
}
mProcessDislike = false;
dislikeBtn.setCompoundDrawablesRelativeWithIntrinsicBounds(R.drawable.ic_disliked, 0, 0, 0);
likeBtn.setCompoundDrawablesRelativeWithIntrinsicBounds(R.drawable.ic_upvote_black, 0, 0, 0);
}

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

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

likeBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
pDislike = dislikeBtn.getText().toString();
pLikes = likeBtn.getText().toString();
mProcessLike = true;
likesRef.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {

if (mProcessLike) {
if (dataSnapshot.child(postId).hasChild(myUid)) {
//already liked ,so remove like
likesRef.child(postId).child(myUid).removeValue();
like = Integer.parseInt(pLikes) - 1;
mProcessLike = false;
likeBtn.setText(MessageFormat.format("{0}", like));
postList.get(position).setpUp("" + like);
likeBtn.setCompoundDrawablesRelativeWithIntrinsicBounds(R.drawable.ic_upvote_black, 0, 0, 0);
} else {
//not liked
dislikeRef.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
//verifying is user has dislkied the post
if (dataSnapshot.child(postId).hasChild(myUid)) {
dislikeRef.child(postId).child(myUid).removeValue();
likesRef.child(postId).child(myUid).setValue("1");
dislikeBtn.setText(MessageFormat.format("{0}", Integer.parseInt(pDislike) - 1));
postList.get(position).setpDown("" + (Integer.parseInt(pDislike) - 1));
like = Integer.parseInt(pLikes) + 1;
likeBtn.setText(MessageFormat.format("{0}", like));
postList.get(position).setpUp("" + like);
dislikeBtn.setCompoundDrawablesRelativeWithIntrinsicBounds(R.drawable.ic_downvote_black, 0, 0, 0);
} else {
likesRef.child(postId).child(myUid).setValue("1");
like = Integer.parseInt(pLikes) + 1;
likeBtn.setText(MessageFormat.format("{0}", like));
postList.get(position).setpUp("" + like);
}
mProcessLike = false;
likeBtn.setCompoundDrawablesRelativeWithIntrinsicBounds(R.drawable.ic_liked, 0, 0, 0);
}

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

}
}

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

scrollView.post(new Runnable() {
@Override
public void run() {
scrollView.scrollTo(0, commentExtraSpace.getBottom());
}
});

DatabaseReference databaseReference = FirebaseDatabase.getInstance().getReference().child("Users").child(myUid);
databaseReference.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
myProfilPic = "" + dataSnapshot.child("imageURL").getValue();
myName = "" + dataSnapshot.child("username").getValue();
}

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

private void sendComment() {
String comment = commentEt.getText().toString().trim();
//checking if empty
if (TextUtils.isEmpty(comment)) {
Toast.makeText(this, getString(R.string.EmptyComment), Toast.LENGTH_SHORT).show();
return;
}
String timeStamp = String.valueOf(System.currentTimeMillis());
DatabaseReference databaseReference = FirebaseDatabase.getInstance().getReference("Comments");
HashMap<String, String> hashMap = new HashMap<>();
//put info in hashmap
hashMap.put("commentId", timeStamp);
hashMap.put("comment", comment);
hashMap.put("timeStamp", timeStamp);
hashMap.put("userId", myUid);
hashMap.put("userPicture", myProfilPic);
hashMap.put("userName", myName);
hashMap.put("like", "0");
hashMap.put("dislike", "0");
hashMap.put("replies", "no");
hashMap.put("liked", "no");
hashMap.put("disliked", "no");
databaseReference.child(postId).child(timeStamp).setValue(hashMap);
replyComment = new Comment(timeStamp, comment, timeStamp, "noid", myProfilPic, myName, "0", "0", "no", "no", "no");
commentEt.setText("");
}


private void loadComments() {
//linear layout for recyclerView
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getApplicationContext());
//set layout to recyclerView
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(linearLayoutManager);
//init comments list
commentList = new ArrayList<>();

//path of the post,to get comments;
DatabaseReference databaseReference = FirebaseDatabase.getInstance().getReference("Comments").child(postId);
databaseReference.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
commentList.clear();

for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
Comment comment = snapshot.getValue(Comment.class);
if (snapshot.child("comments").getChildrenCount() >= 1) {
comment.setReplies("" + snapshot.child("comments").getChildrenCount());

} else {
comment.setReplies("no");
}
if (snapshot.child("likes").hasChild(myUid)) {
comment.setLiked("yes");
} else {
comment.setLiked("no");
}
if (snapshot.child("dislikes").hasChild(myUid)) {
comment.setDisliked("yes");
} else {
comment.setDisliked("no");
}
comment.setLike(String.valueOf(snapshot.child("likes").getChildrenCount()));
comment.setDislike(String.valueOf(snapshot.child("dislikes").getChildrenCount()));
commentList.add(comment);
//setup adapter
}
commentAdapter = new CommentAdapter(PostDetailActivity.this, commentList, postId);
//set adapter
if (commentAdapter.getItemCount() > 0) {
recyclerView.setAdapter(commentAdapter);
emptyRecycler.setVisibility(View.GONE);
} else {
recyclerView.setVisibility(View.GONE);
emptyRecycler.setVisibility(View.VISIBLE);
}
}

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

private void setLikes(final String postKey) {
likesRef.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
if (dataSnapshot.child(postKey).hasChild(myUid)) {
//user has liked this post
//indicate it with new design
likeBtn.setCompoundDrawablesRelativeWithIntrinsicBounds(R.drawable.ic_liked, 0, 0, 0);
} else {
//user has not liked
likeBtn.setCompoundDrawablesRelativeWithIntrinsicBounds(R.drawable.ic_upvote_black, 0, 0, 0);
}
}

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

private void setDislike(final String postKey) {
dislikeRef.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
if (dataSnapshot.child(postKey).hasChild(myUid)) {
//user has liked this post
//indicate it with new design
dislikeBtn.setCompoundDrawablesRelativeWithIntrinsicBounds(R.drawable.ic_disliked, 0, 0, 0);
} else {
//user has not liked
dislikeBtn.setCompoundDrawablesRelativeWithIntrinsicBounds(R.drawable.ic_downvote_black, 0, 0, 0);
}
}

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

}
});

}

@Override
public boolean onSupportNavigateUp() {
onBackPressed();
return super.onSupportNavigateUp();
}

@Override
public void onBackPressed() {
// PostFragment.recyclerView.getAdapter().notifyItemChanged(position);
if (isTaskRoot() && getSupportFragmentManager().getBackStackEntryCount() == 0) {
finishAfterTransition();
} else {
super.onBackPressed();
}
}

}
当我按下后退按钮时,我得到这个:
┬───
│ GC Root: System class

├─ android.app.ActivityThread class
│ Leaking: NO (a class is never leaking)
│ ↓ static ActivityThread.sCurrentActivityThread
│ ~~~~~~~~~~~~~~~~~~~~~~
├─ android.app.ActivityThread instance
│ Leaking: UNKNOWN
│ ↓ ActivityThread.mNewActivities
│ ~~~~~~~~~~~~~~
├─ android.app.ActivityThread$ActivityClientRecord instance
│ Leaking: UNKNOWN
│ ↓ ActivityThread$ActivityClientRecord.nextIdle
│ ~~~~~~~~
├─ android.app.ActivityThread$ActivityClientRecord instance
│ Leaking: UNKNOWN
│ ↓ ActivityThread$ActivityClientRecord.activity
│ ~~~~~~~~
╰→ com.RLD.newmemechat.PostDetailActivity instance
​ Leaking: YES (ObjectWatcher was watching this because com.RLD.newmemechat.PostDetailActivity received Activity#onDestroy() callback and Activity#mDestroyed is true)
​ key = 533b7987-0f38-41f4-9f1a-e468dcf83264
​ watchDurationMillis = 8537
​ retainedDurationMillis = 3530~~~

最佳答案

这明显是Android框架造成的漏洞。 leaktrace 中没有任何内容与您的代码有关,据我所知,ActivityThread 在 ActivityThread.mNewActivities 中维护着 ActivityThread$ActivityClientRecord 的链表。

你可以在这里看到:

https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/java/android/app/ActivityThread.java;l=312-314;drc=d9b11b058c6a50fa25b75d6534a2deaf0e62d4b3

    // List of new activities (via ActivityRecord.nextIdle) that should
// be reported when next we idle.
ActivityClientRecord mNewActivities = null;

看起来这是由 ActivityThread.Idler 完成的,它在主线程空闲时运行:

https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/java/android/app/ActivityThread.java;l=2059-2096;drc=master

    private class Idler implements MessageQueue.IdleHandler {
@Override
public final boolean queueIdle() {
ActivityClientRecord a = mNewActivities;
boolean stopProfiling = false;
if (mBoundApplication != null && mProfiler.profileFd != null
&& mProfiler.autoStopProfiler) {
stopProfiling = true;
}
if (a != null) {
mNewActivities = null;
IActivityTaskManager am = ActivityTaskManager.getService();
ActivityClientRecord prev;
do {
if (localLOGV) Slog.v(
TAG, "Reporting idle of " + a +
" finished=" +
(a.activity != null && a.activity.mFinished));
if (a.activity != null && !a.activity.mFinished) {
try {
am.activityIdle(a.token, a.createdConfig, stopProfiling);
a.createdConfig = null;
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
prev = a;
a = a.nextIdle;
prev.nextIdle = null;
} while (a != null);
}
if (stopProfiling) {
mProfiler.stopProfiling();
}
applyPendingProcessState();
return false;
}
}

这用于在创建 Activity 后主线程空闲时通知 Activity 管理器。不幸的是,如果主线程在 Activity.onCreate() 和 Activity.onDestroy() 之间没有空闲,这似乎会导致泄漏。

关于android - 修复由 Leak Canary 发现的 Activity 内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62848503/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com