繁体   English   中英

了解Android MVP中的泄漏

[英]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();
        }
    }
}
  1. 如果在获取用户名时用户旋转屏幕,则由于活动被破坏,我们将泄漏在观察者的回调中引用的活动实例。
  2. 如果用户旋转屏幕而没有进行中的获取,则活动实例不会泄漏。
  3. 为了解决此泄漏(1),我们需要存储订阅,然后在presenter.onDestroy()中取消订阅(从SplashActivity onDestroy()调用)。
  4. 有人告诉我,做(3)是不够的,在onDestroy()内部,我们还必须将活动实例设置为null 我不同意,因为取消订阅会取消请求,从而阻止引用该活动的回调(如onNext(User) )被调用。
  5. 他还告诉我,虽然(3)和(4)防止ACTIVITY泄漏,但由于活动引用了PRESENTER,因此在旋转期间PRESENTER也泄漏了。 我不同意,因为每旋转创建一个新的演示者,并在BaseActivity onCreate调用setupActivityComponent时将其初始化为注入的演示者。 旧的演示者会自动作为SplashActivity的成员进行垃圾收集。

有人可以回应我在上面概述的观点,以便可以确认我的理解或了解我可能做错的地方吗? 谢谢

我将尽我所能尽可能准确地回答这些问题(如果不准确,欢迎进行编辑),但是此答案很好阅读: https : //stackoverflow.com/a/10968689/4252352

  1. 如果在获取用户名时用户旋转屏幕,则由于活动被破坏,我们将泄漏在观察者的回调中引用的活动实例。

答:这是正确的,但是在处理后清除资源之前,这将是短期内存泄漏。 但是,不应依赖于此,如果您具有Flowable / Observable,则它可能永远不会处置和清除资源。 重要的是要注意,Rx链中所有不引用(捕获)封闭类的lambda(通常是mapfilter等运算符)都是无泄漏的。

  1. 如果用户旋转屏幕而没有进行中的获取,则活动实例不会泄漏。

答:正确,您永远都没有有效的订阅。

  1. 为了解决此泄漏(1),我们需要存储订阅,然后在presenter.onDestroy()中取消订阅(从SplashActivity onDestroy()调用)

答:这应该可以解决问题。 但是,有一个更好的方法,在MVP中, View应该是抽象/接口,并且Presenter应该具有该视图的入口和出口点,而不是在构造函数上,即bind(view : View)unbind() <-在这里清理,演示者不应该知道特定的android hook回调。 这具有巨大的优势,不仅从OOP(程序到接口而不是实现)方面,而且在测试方面。

  1. 有人告诉我做(3)是不够的,在onDestroy()内部,我们还必须将活动实例设置为null。 我不同意,因为取消订阅会取消请求,从而阻止引用该活动的回调(如onNext(User))被调用。

答:我首先会要求澄清他们的理由。 由于您的Presenter的作用域是Activity (它们都有相同的生命周期),因此取消订阅就足够了。 但是,如果您的Presenter的生命周期比“ Activity更长,则有必要删除该引用(这可能是您与之交谈的人的道理)。

  1. 他还告诉我,虽然(3)和(4)防止ACTIVITY泄漏,但由于活动引用了PRESENTER,因此在旋转期间PRESENTER也泄漏了。 我不同意,因为每旋转创建一个新的演示者,并在BaseActivity onCreate调用setupActivityComponent时将其初始化为注入的演示者。 旧的演示者会自动作为SplashActivity的成员进行垃圾收集。

答: Presenter被泄漏,如果Activity被泄漏(以及活动引用的所有内容!)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM