gpt4 book ai didi

java - 在 Activity 中使用内部 BroadcastReceiver 的内存问题

转载 作者:搜寻专家 更新时间:2023-11-01 09:26:17 25 4
gpt4 key购买 nike

我已经工作了几个月,现在将编写 Android 应用程序代码作为一种爱好。现在,我不得不意识到现实世界并不像某些教程听起来那么简单,而且一个应用程序在多种设备上的表现确实不同。目前,我担心我的应用程序中的内存和 CPU 使用率。我从来没有真正花时间在内存使用方面优化或什至考虑我的应用程序,好吧,我开始了,意识到我可能真的在很多地方搞砸了,而且有很多东西需要清理。

不幸的是,我很难找到最新的且新手可以理解的教程和解释。许多教程都在处理旧的 android studio 版本,非常好的教程是关于使用 DDMS 的。我觉得新的 Android Profiler(在 Android Studio 3.0 中)缺少一些重要的见解。如果你能帮助我消除一些误解,那将是很好的,因为我在一夜之间阅读了大量的操作方法和教程而感到恼火。

我目前想知道 Activity 中的 BroadcastReceiver,这是一种经常使用的做法。因此,例如,我有一个音乐应用程序。 MainActivity 正在启动一个 Service 来处理音乐播放。此 Service 向 Activity 报告当前播放状态和播放时间。通过从 Service 向指定的 MainActivity 中的内部 BroadcastReceiver 发送一个 Intent 来解决报告问题。这是一个简化的例子,可以让您理解我的意思:

public class MainActivity extends Activity {

private class MusicPlayerBroadcast extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
//update UI elements
seekBar.post(() -> seekBar.setProgress(POSITION)); //using post for thread safeness?

//lots of other UI calls

}

}
}

由于我不确定是否由于其他错误的实现而引发了以下问题,因此我决定发布 Intent 接收的完整代码:

                            int currentPos = intent.getIntExtra(KEY_POSITION, -1);

//check if large player is showing, if not it should display mini Player
if(playerRootView.getVisibility() != View.VISIBLE) {
mini_Player.setVisibility(View.VISIBLE);
}

//if the loading hasn't been triggered away yet, this one will help
if(relativeLayoutLoading.getVisibility() == View.VISIBLE) {
relativeLayoutLoading.setVisibility(View.GONE);
playerControls.setVisibility(View.VISIBLE);
}

TrackModel mCurrentTrack=MusicDataMng.getInstance().getCurrentTrackModel();
if (currentPos > 0 && mCurrentTrack != null) {
long duration = currentPos / 1000;
String minute = String.valueOf((int) (duration / 60));
String seconds = String.valueOf((int) (duration % 60));
if (minute.length() < 2) {
minute = "0" + minute;
}
if (seconds.length() < 2) {
seconds = "0" + seconds;
}
String timePassed = minute + ":" + seconds;

if(!seeking) {
// will update the "progress" propriety of seekbar until it reaches progress
seekBar.post(() -> {
ObjectAnimator animation = ObjectAnimator.ofInt(seekBar, "progress", currentPos);
animation.setDuration(1000); // 0.5 second
animation.setInterpolator(new LinearInterpolator());
animation.start();
});

} else {
seekBar.post(() -> seekBar.setProgress(currentPos));
}
mini_ProgressBar.post(() -> mini_ProgressBar.setProgress(currentPos));
trackDurationStart.post(() -> trackDurationStart.setText(timePassed));

}

我现在在开始播放歌曲后记录内存时在 Android Profiler 中看到的是: Screenshot of Android Profiler excerpt

我的问题如下:

  1. 我觉得不应该为每个 Intent 更新 BroadcastReceiver 的实例的位置。为什么在 GC 后它们仍然存储而不被删除?
  2. 实例持有对 arg$1.this$0 中 MainActivity 的引用
    • 从引用 id,我可以看出它们指向相同的 MainActivity。这是否意味着它们只存储指向该引用的指针,或者 BroadcastReceiver 的每个实例都存储对 MainActivity 的完整引用?如果是这样,就意味着大量内存使用,对吧?
  3. 当我将 BroadcastReceiver 设置为静态,然后添加一个构造函数来设置 WeakReferences 时,这种不当行为会消失吗 here

如果您觉得我真的错过了关于这个球洞性能主题的某些内容,或者应该阅读这个或那个教程或书籍,我将非常感谢任何推荐。

提前致谢

最佳答案

通过将您的广播接收器声明为嵌套类,它持有对封闭类 (MainActivity) 的引用。您可以将其称为您对 MainActivity 实例描述的“指针”(内存中只有一个实例)。

我没有浏览您链接的博客,但将其设为静态会删除此实例“指针/引用”。

我的建议是通过 https://docs.oracle.com/javase/tutorial/java/javaOO/nested.html更好地了解 Java 中的嵌套类以及何时/如何最好地使用它们。

至于你的具体问题,我建议使用 EventBus 并在总线上发送你的播放器更新,任何感兴趣的类都可以订阅并收听它们。

http://square.github.io/otto

https://github.com/greenrobot/EventBus

关于java - 在 Activity 中使用内部 BroadcastReceiver 的内存问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50373823/

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