使用范围匕首2避免活动泄漏

时间:2017-08-09 12:42:43

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

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

我一直在用匕首探索范围,我的问题是更好地理解活动背景下的范围。

尽管使用了活动范围,我还是通过演示者泄漏了活动(视图)。

因为我是匕首的新手,我觉得我错过了什么。

我假设范围应该在活动被销毁时处理我的视图为null(虽然现在不明白它会如何)。我的假设是对的吗?如果是,我做错了,否则可以避免使用匕首查看泄漏?我知道detachView方法,只是好奇我们是否可以使用dagger 2实现相同的目的。

P.S:我通过leakCanary来了解泄漏。

以下是我的代码

LoginActivity.class

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
<tr>
<td>3</td>
<td>4</td>
<td>5</td>
</tr>
<tr>
<td>6</td>
<td>7</td>
<td>8</td>
</tr>
<tr>
<td>9</td>
<td>10</td>
<td>11</td>
</tr>
</table>

LoginPresenterModule.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;
}

LoginComponent.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;
}
}

LoginPresenter.class

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

  void inject(LoginActivity loginActivity);
}

}

DataRespositoryComponent.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() {

}

基本上,在进行网络呼叫时,视图会泄露。 我的泄漏堆栈: enter image description here

1 个答案:

答案 0 :(得分:3)

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

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

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

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

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

在回调中访问视图之前,请务必检查视图是否为空。