使用范围匕首 2 避免 activity 泄漏
Avoid activity leak using scope dagger 2
首先从我的项目架构开始,我使用 MVP 和 Dagger 2 进行依赖注入。
我一直在探索 Dagger 中的作用域,我的问题是更好地理解 Activity 上下文中的作用域。
尽管使用了 activity 示波器,但我仍然通过演示者 activity(view) 泄漏。
因为我是 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);
}
基本上,在进行网络调用时视图泄漏。
我的 leakcanary 堆栈:
这个 activity 泄漏与 Dagger 无关,Dagger 也不能帮助防止它。
这里的问题在于 dataRespository.sendTest(..anonymousCallback..)
您在其中添加回调以接收结果。
匿名类 以及非静态内部类 将保留对其封闭对象的引用。在您的情况下,回调保留对演示者的引用,演示者保留对视图的引用,视图保留对 Activity 的引用(这就是 LeakCanary 显示的内容)。
由于回调在收到响应或错误之前一直有效,如果您的 Activity 在回调完成之前被销毁,它将泄漏。
要解决您的问题,您需要停止或取消注册您的回调,或者删除对 Activity 的引用。在这种情况下,当 Activity 被销毁以防止 Activity 泄漏时,在演示者中设置 view = null
可能就足够了。
只需确保在回调中访问视图之前检查视图是否为 null。
首先从我的项目架构开始,我使用 MVP 和 Dagger 2 进行依赖注入。
我一直在探索 Dagger 中的作用域,我的问题是更好地理解 Activity 上下文中的作用域。
尽管使用了 activity 示波器,但我仍然通过演示者 activity(view) 泄漏。
因为我是 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);
}
基本上,在进行网络调用时视图泄漏。
我的 leakcanary 堆栈:
这个 activity 泄漏与 Dagger 无关,Dagger 也不能帮助防止它。
这里的问题在于 dataRespository.sendTest(..anonymousCallback..)
您在其中添加回调以接收结果。
匿名类 以及非静态内部类 将保留对其封闭对象的引用。在您的情况下,回调保留对演示者的引用,演示者保留对视图的引用,视图保留对 Activity 的引用(这就是 LeakCanary 显示的内容)。
由于回调在收到响应或错误之前一直有效,如果您的 Activity 在回调完成之前被销毁,它将泄漏。
要解决您的问题,您需要停止或取消注册您的回调,或者删除对 Activity 的引用。在这种情况下,当 Activity 被销毁以防止 Activity 泄漏时,在演示者中设置 view = null
可能就足够了。
只需确保在回调中访问视图之前检查视图是否为 null。