[英]understanding leaks in android MVP
我在这里已经阅读了一些类似的问题,但是由于缺少所提供的代码,所以我不确定我的问题是否描述了相同的情况。
我希望以下代码片段和问题能帮助其他人澄清此MVP实现中泄漏的内容和时间: https : //github.com/frogermcs/GithubClient/tree/1bf53a2a36c8a85435e877847b987395e482ab4a
BaseActivity.java:
public abstract class BaseActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setupActivityComponent();
}
protected abstract void setupActivityComponent();
}
SplashActivityModule.java:
@Module
public class SplashActivityModule {
private SplashActivity splashActivity;
public SplashActivityModule(SplashActivity splashActivity) {
this.splashActivity = splashActivity;
}
@Provides
@ActivityScope
SplashActivity provideSplashActivity() {
return splashActivity;
}
@Provides
@ActivityScope
SplashActivityPresenter
provideSplashActivityPresenter(Validator validator, UserManager
userManager, HeavyLibraryWrapper heavyLibraryWrapper) {
return new SplashActivityPresenter(splashActivity, validator,
userManager, heavyLibraryWrapper);
}
}
SplashActivityPresenter被注入SplashActivity.java中:
public class SplashActivity extends BaseActivity {
...
@Inject
SplashActivityPresenter presenter;
@Override
protected void setupActivityComponent() {
GithubClientApplication.get(this)
.getAppComponent()
.plus(new SplashActivityModule(this))
.inject(this);
}
SplashActivityPresenter.java:
public class SplashActivityPresenter {
public String username;
private SplashActivity splashActivity;
private Validator validator;
private UserManager userManager;
private HeavyLibraryWrapper heavyLibraryWrapper;
public SplashActivityPresenter(SplashActivity splashActivity,
Validator validator, UserManager userManager,
HeavyLibraryWrapper heavyLibraryWrapper) {
this.splashActivity = splashActivity;
this.validator = validator;
this.userManager = userManager;
this.heavyLibraryWrapper = heavyLibraryWrapper;
//This calls should be delivered to ExternalLibrary right after it will be initialized
this.heavyLibraryWrapper.callMethod();
this.heavyLibraryWrapper.callMethod();
this.heavyLibraryWrapper.callMethod();
this.heavyLibraryWrapper.callMethod();
}
public void onShowRepositoriesClick() {
if (validator.validUsername(username)) {
splashActivity.showLoading(true);
userManager.getUser(username).subscribe(new
SimpleObserver<User>() {
@Override
public void onNext(User user) {
splashActivity.showLoading(false);
splashActivity.showRepositoriesListForUser(user);
}
@Override
public void onError(Throwable e) {
splashActivity.showLoading(false);
splashActivity.showValidationError();
}
});
} else {
splashActivity.showValidationError();
}
}
}
onDestroy()
内部,我们还必须将活动实例设置为null
。 我不同意,因为取消订阅会取消请求,从而阻止引用该活动的回调(如onNext(User)
)被调用。 有人可以回应我在上面概述的观点,以便可以确认我的理解或了解我可能做错的地方吗? 谢谢
我将尽我所能尽可能准确地回答这些问题(如果不准确,欢迎进行编辑),但是此答案很好阅读: https : //stackoverflow.com/a/10968689/4252352
- 如果在获取用户名时用户旋转屏幕,则由于活动被破坏,我们将泄漏在观察者的回调中引用的活动实例。
答:这是正确的,但是在处理后清除资源之前,这将是短期内存泄漏。 但是,不应依赖于此,如果您具有Flowable / Observable,则它可能永远不会处置和清除资源。 重要的是要注意,Rx链中所有不引用(捕获)封闭类的lambda(通常是map
, filter
等运算符)都是无泄漏的。
- 如果用户旋转屏幕而没有进行中的获取,则活动实例不会泄漏。
答:正确,您永远都没有有效的订阅。
- 为了解决此泄漏(1),我们需要存储订阅,然后在presenter.onDestroy()中取消订阅(从SplashActivity onDestroy()调用)
答:这应该可以解决问题。 但是,有一个更好的方法,在MVP中, View
应该是抽象/接口,并且Presenter
应该具有该视图的入口和出口点,而不是在构造函数上,即bind(view : View)
和unbind()
<-在这里清理,演示者不应该知道特定的android hook回调。 这具有巨大的优势,不仅从OOP(程序到接口而不是实现)方面,而且在测试方面。
- 有人告诉我做(3)是不够的,在onDestroy()内部,我们还必须将活动实例设置为null。 我不同意,因为取消订阅会取消请求,从而阻止引用该活动的回调(如onNext(User))被调用。
答:我首先会要求澄清他们的理由。 由于您的Presenter
的作用域是Activity
(它们都有相同的生命周期),因此取消订阅就足够了。 但是,如果您的Presenter
的生命周期比“ Activity
更长,则有必要删除该引用(这可能是您与之交谈的人的道理)。
- 他还告诉我,虽然(3)和(4)防止ACTIVITY泄漏,但由于活动引用了PRESENTER,因此在旋转期间PRESENTER也泄漏了。 我不同意,因为每旋转创建一个新的演示者,并在BaseActivity onCreate调用setupActivityComponent时将其初始化为注入的演示者。 旧的演示者会自动作为SplashActivity的成员进行垃圾收集。
答: Presenter
被泄漏,如果Activity
被泄漏(以及活动引用的所有内容!)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.