Android:我的应用程序内存超过 300MB 的 ram 只是闲置
Android: my app memory over 300MB of ram just on idle
我注意到我的应用程序使用了大量内存,所以我使用了探查器,发现一旦应用程序启动并出现启动画面,即使在启动主程序或任何其他应用程序之前启动时,应用程序也会超过 150 + MB activity.
更新:我解决了所有的内存泄漏问题,但我的应用程序仍然在使用 recycleview 浏览 MainActivity 时在我的真实 phone 上使用近 300+ MB 的内存。
LeakCanary 和我一直给我错误,这是内存泄漏的原因所以任何人都请告诉我如何解决它 >
如果您点击了任何 recyclerview 项目:
[]
Activity代码:
public class WorkDetailsActivity extends AppCompatActivity {
ArrayList<String> imagesFromURL = new ArrayList<String>();
ActivityWorkDetailsBinding binding;
DatabaseReference databaseReference;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityWorkDetailsBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
String workUid_details = getIntent().getExtras().getString("UID_Details");
String title = getIntent().getExtras().getString("name");
String description = getIntent().getExtras().getString("description");
String location = getIntent().getExtras().getString("location");
String path = getIntent().getExtras().getString("path");
databaseReference = FirebaseDatabase.getInstance().getReference().child("Work").child(path);
databaseReference.child(workUid_details).addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot snapshot) {
binding.workDetailsTitle.setText(title);
binding.workDetailsDescription.setText(description);
binding.workDetailsLocation.setText(location);
binding.getUIDDetails.setText(workUid_details);
for (DataSnapshot dataSnapshot : snapshot.child("images").getChildren()) {
String value = String.valueOf(dataSnapshot.child("image").getValue());
imagesFromURL.add(value);
//Log.i("Value", String.valueOf(imagesFromURL));
}
initRecyclerView();
}
@Override
public void onCancelled(@NonNull DatabaseError error) {
}
});
}
private void initRecyclerView(){
binding.workDetailsImage.setNestedScrollingEnabled(false);
binding.workDetailsImage.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false));
binding.workDetailsImage.setHasFixedSize(true);
PrivateRecyclerAdapter adapter = new PrivateRecyclerAdapter(this, imagesFromURL);
binding.workDetailsImage.setAdapter(adapter);
binding.progressBar.setVisibility(View.VISIBLE);
/* //Add Divider between recyclerView items
DividerItemDecoration itemDecorator = new DividerItemDecoration(this, DividerItemDecoration.HORIZONTAL);
binding.workDetailsImage.addItemDecoration(itemDecorator);
final int radius = getResources().getDimensionPixelSize(R.dimen.radius);
final int dotsHeight = getResources().getDimensionPixelSize(R.dimen.dots_height);
final int color = ContextCompat.getColor(this, R.color.green);
binding.workDetailsImage.addItemDecoration(new DotsIndicatorDecoration(radius, radius * 2, dotsHeight, color, color));
binding.workDetailsImage.setOnFlingListener(null);
new PagerSnapHelper().attachToRecyclerView(binding.workDetailsImage);*/
}
@Override
protected void onDestroy() {
super.onDestroy();
imagesFromURL = null;
binding.workDetailsImage.setAdapter(null);
binding.workDetailsTitle.setText(null);
binding.workDetailsLocation.setText(null);
binding.workDetailsDescription.setText(null);
binding.getUIDDetails.setText(null);
binding.workDetailsImage.setAdapter(null);
}
上述代码的问题在于您将值事件侦听器注册为匿名实现。它将保存 activity 的引用。根据 LeakCanary 堆栈跟踪,您的 activity 处于销毁状态,但由于侦听器,activity 实例无法被垃圾收集,因此它被泄漏了。您需要做的是添加和删除侦听器,如下所示。
创建 ValueEventListener 实例并将其存储在变量中
ValueEventListener valueEventListener = new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot snapshot) {
binding.workDetailsTitle.setText(title);
binding.workDetailsDescription.setText(description);
binding.workDetailsLocation.setText(location);
binding.getUIDDetails.setText(workUid_details);
for (DataSnapshot dataSnapshot : snapshot.child("images").getChildren()) {
String value = String.valueOf(dataSnapshot.child("image").getValue());
imagesFromURL.add(value);
//Log.i("Value", String.valueOf(imagesFromURL));
}
initRecyclerView();
}
@Override
public void onCancelled(@NonNull DatabaseError error) {
}
});
使用
在activity生命周期的onStart方法中注册它
@Override
protected void onStart() {
databaseReference.child(workUid_details).addValueEventListener(valueEventListener);
}
使用
删除 activity 生命周期的 onStop 方法中的侦听器
@Override
protected void onStop() {
databaseReference.child(workUid_details).removeEventListener(valueEventListener);
}
我注意到我的应用程序使用了大量内存,所以我使用了探查器,发现一旦应用程序启动并出现启动画面,即使在启动主程序或任何其他应用程序之前启动时,应用程序也会超过 150 + MB activity.
更新:我解决了所有的内存泄漏问题,但我的应用程序仍然在使用 recycleview 浏览 MainActivity 时在我的真实 phone 上使用近 300+ MB 的内存。
LeakCanary 和我一直给我错误,这是内存泄漏的原因所以任何人都请告诉我如何解决它 >
如果您点击了任何 recyclerview 项目:
[
Activity代码:
public class WorkDetailsActivity extends AppCompatActivity {
ArrayList<String> imagesFromURL = new ArrayList<String>();
ActivityWorkDetailsBinding binding;
DatabaseReference databaseReference;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityWorkDetailsBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
String workUid_details = getIntent().getExtras().getString("UID_Details");
String title = getIntent().getExtras().getString("name");
String description = getIntent().getExtras().getString("description");
String location = getIntent().getExtras().getString("location");
String path = getIntent().getExtras().getString("path");
databaseReference = FirebaseDatabase.getInstance().getReference().child("Work").child(path);
databaseReference.child(workUid_details).addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot snapshot) {
binding.workDetailsTitle.setText(title);
binding.workDetailsDescription.setText(description);
binding.workDetailsLocation.setText(location);
binding.getUIDDetails.setText(workUid_details);
for (DataSnapshot dataSnapshot : snapshot.child("images").getChildren()) {
String value = String.valueOf(dataSnapshot.child("image").getValue());
imagesFromURL.add(value);
//Log.i("Value", String.valueOf(imagesFromURL));
}
initRecyclerView();
}
@Override
public void onCancelled(@NonNull DatabaseError error) {
}
});
}
private void initRecyclerView(){
binding.workDetailsImage.setNestedScrollingEnabled(false);
binding.workDetailsImage.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false));
binding.workDetailsImage.setHasFixedSize(true);
PrivateRecyclerAdapter adapter = new PrivateRecyclerAdapter(this, imagesFromURL);
binding.workDetailsImage.setAdapter(adapter);
binding.progressBar.setVisibility(View.VISIBLE);
/* //Add Divider between recyclerView items
DividerItemDecoration itemDecorator = new DividerItemDecoration(this, DividerItemDecoration.HORIZONTAL);
binding.workDetailsImage.addItemDecoration(itemDecorator);
final int radius = getResources().getDimensionPixelSize(R.dimen.radius);
final int dotsHeight = getResources().getDimensionPixelSize(R.dimen.dots_height);
final int color = ContextCompat.getColor(this, R.color.green);
binding.workDetailsImage.addItemDecoration(new DotsIndicatorDecoration(radius, radius * 2, dotsHeight, color, color));
binding.workDetailsImage.setOnFlingListener(null);
new PagerSnapHelper().attachToRecyclerView(binding.workDetailsImage);*/
}
@Override
protected void onDestroy() {
super.onDestroy();
imagesFromURL = null;
binding.workDetailsImage.setAdapter(null);
binding.workDetailsTitle.setText(null);
binding.workDetailsLocation.setText(null);
binding.workDetailsDescription.setText(null);
binding.getUIDDetails.setText(null);
binding.workDetailsImage.setAdapter(null);
}
上述代码的问题在于您将值事件侦听器注册为匿名实现。它将保存 activity 的引用。根据 LeakCanary 堆栈跟踪,您的 activity 处于销毁状态,但由于侦听器,activity 实例无法被垃圾收集,因此它被泄漏了。您需要做的是添加和删除侦听器,如下所示。
创建 ValueEventListener 实例并将其存储在变量中
ValueEventListener valueEventListener = new ValueEventListener() { @Override public void onDataChange(@NonNull DataSnapshot snapshot) { binding.workDetailsTitle.setText(title); binding.workDetailsDescription.setText(description); binding.workDetailsLocation.setText(location); binding.getUIDDetails.setText(workUid_details); for (DataSnapshot dataSnapshot : snapshot.child("images").getChildren()) { String value = String.valueOf(dataSnapshot.child("image").getValue()); imagesFromURL.add(value); //Log.i("Value", String.valueOf(imagesFromURL)); } initRecyclerView(); } @Override public void onCancelled(@NonNull DatabaseError error) { } });
使用
在activity生命周期的onStart方法中注册它@Override protected void onStart() { databaseReference.child(workUid_details).addValueEventListener(valueEventListener); }
使用
删除 activity 生命周期的 onStop 方法中的侦听器@Override protected void onStop() { databaseReference.child(workUid_details).removeEventListener(valueEventListener); }