【问题标题】:Avoid activity leak using scope dagger 2使用范围匕首 2 避免活动泄漏
【发布时间】:2017-08-09 12:42:42
【问题描述】:

首先从我的项目架构开始,我使用 MVP 和 Dagger 2 进行依赖注入。

我一直在探索 dagger 中的作用域,我的问题是更好地理解 Activity 上下文中的作用域。

尽管使用了活动范围,但我有一个活动(视图)通过演示者泄漏。

因为我是匕首新手,我觉得我错过了一些东西。

我假设作用域应该在活动被销毁时将我的视图处理为 null(尽管现在不明白它会如何)。我的假设是否正确?如果是,我做错了什么,否则是否可以使用匕首避免视图泄漏?我知道 detachView 方法,只是好奇我们是否可以使用 dagger 2 实现相同的目标。

P.S: 我是通过leakCanary 得知泄漏的。

以下是我的代码

LoginActivity.class

public class LoginActivity extends BaseActivity implements LoginContract.View {


    private static final String TAG = "LoginActivity";
    @Inject
    LoginPresenter presenter;

    private LoginComponent loginComponent;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_login);
    createComponent();
    initViews();
    }

   private void createComponent() {
    loginComponent = ((MyApplication) getApplication()).getRepositoryComponent()
            .COMPONENT(new LoginPresenterModule(this));
    loginComponent.inject(this);
}

 @Override
 protected void onDestroy() {
    super.onDestroy();
    loginComponent = null;
}

LoginPresenterModule.class

@Module
public class LoginPresenterModule {

private final LoginContract.View view;

public LoginPresenterModule(LoginContract.View view) {
    this.view = view;
}


@Provides
@ActivityScoped
public LoginContract.View providesView(){
    return view;
}
}

LoginComponent.class

@ActivityScoped
@Subcomponent(modules = LoginPresenterModule.class)
public interface LoginComponent {

  void inject(LoginActivity loginActivity);
}

LoginPresenter.class

@ActivityScoped
public class LoginPresenter implements LoginContract.Presenter {

private static final String TAG = "LoginPresenter";
private LoginContract.View view;

private DataRespository dataRespository;

@Inject
LoginPresenter(LoginContract.View view, DataRespository dataRespository) {
    this.view = view;
    this.dataRespository = dataRespository;
}


@Override
public void initTest(String testNo) {

    view.showProgressIndicator();
    dataRespository.sendTest(testNo, new DataSource.onResponseCallback<Void>() {
        @Override
        public void onSuccess(Void obj) {
            Log.d(TAG, "onSuccess: ");

        }

        @Override
        public void onError(@NotNull ErrorWrapper error) {
            Log.d(TAG, "onError: ");
        }
    });

}

@Override
public void start() {

}

}

DataRespositoryComponent.class

@ApplicationScoped
@Component(dependencies = ApplicationComponent.class,modules = 
DataRespositoryModule.class)
public interface DataRepositoryComponent {

LoginComponent COMPONENT(LoginPresenterModule loginPresenterModule);
}

基本上,在进行网络调用时会泄露视图。 我的泄漏堆栈:

【问题讨论】:

  • 您能否将泄漏金丝雀的跟踪/信息包括在哪里泄漏?
  • 刚刚做了。看看

标签: android dependency-injection memory-leaks garbage-collection dagger-2


【解决方案1】:

此活动泄漏与 Dagger 无关,Dagger 也无法帮助防止它。

这里的问题在于dataRespository.sendTest(..anonymousCallback..),您可以在其中添加回调以接收结果。

匿名类和非静态内部类将保留对其封闭对象的引用。在您的情况下,回调保留对演示者的引用,演示者保留对视图的引用,视图保留对 Activity 的引用(这就是 LeakCanary 显示的内容)。

由于回调在收到响应或错误之前一直处于活动状态,因此如果您的 Activity 在回调完成之前被销毁,它将泄漏。


要解决您的问题,您需要停止或取消注册您的回调,或者删除对 Activity 的引用。在这种情况下,当 Activity 被销毁以防止 Activity 泄漏时,在演示者中设置 view = null 可能就足够了。

只需确保在回调中访问视图之前检查视图是否为空。

【讨论】:

  • 视图对象是否应该与活动一样长,因为它是活动范围的?还是说匕首不负责杀死对象?
  • @farhanpatel dagger 仅创建对象。垃圾收集器不会收集它,因为 okHttp 仍在引用它
  • 谢谢你,现在你已经解释了,这似乎很明显!。 :D
  • @farhanpatel 为什么您的演示者有视图?视图应该处于活动状态,这就是 MVP 的全部目的!
猜你喜欢
  • 2012-03-22
  • 2021-12-05
  • 1970-01-01
  • 2012-10-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多