Android MVP-在配置更改期间仍然存在的网络请求

Android MVP-在配置更改期间仍然存在的网络请求,android,mvp,dagger-2,rx-android,onconfigurationchanged,Android,Mvp,Dagger 2,Rx Android,Onconfigurationchanged,我在网上学习了一些教程和开源软件,并使用RxJava、Dagger 2和改型构建了基于MVP架构的简单应用程序。一切正常,除了我开始下载数据并立即旋转屏幕时,上一个请求被取消,新的请求被提出 取消网络请求的原因是,我正在从视图的onDestroyView中的Observable取消订阅。那是为了防止内存泄漏 如何保留以前的网络请求而不让订阅泄漏 以下是我的看法: public class MoviesFragment extends Fragment implements MoviesView{

我在网上学习了一些教程和开源软件,并使用RxJava、Dagger 2和改型构建了基于MVP架构的简单应用程序。一切正常,除了我开始下载数据并立即旋转屏幕时,上一个请求被取消,新的请求被提出

取消网络请求的原因是,我正在从视图的
onDestroyView
中的Observable取消订阅。那是为了防止内存泄漏

如何保留以前的网络请求而不让
订阅
泄漏

以下是我的看法:

public class MoviesFragment extends Fragment implements MoviesView{

    @Inject
    MoviesPresenter moviesPresenter;
   //....

    public MoviesFragment(){

    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setHasOptionsMenu(true);
        setRetainInstance(true);
        ((BaseApplication) getActivity().getApplication()).createListingComponent().inject(this);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    {
        View rootView = inflater.inflate(R.layout.fragment_movies, container, false);
        ButterKnife.bind(this, rootView);
        return rootView;
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState)
    {
        super.onViewCreated(view, savedInstanceState);
        moviesPresenter.setView(this);
    }

    // ....

    @Override
    public void onDestroyView()
    {
        super.onDestroyView();
        moviesPresenter.destroy();
        ButterKnife.unbind(this);
    }

    @Override
    public void onDetach()
    {
        super.onDetach();
    }

    @Override
    public void onDestroy()
    {
        super.onDestroy();
        ((BaseApplication)getActivity().getApplication()).releaseListingComponent();
    }
    //....
}
以下是演示者:

public class MoviesPresenterImpl implements MoviesPresenter {

    private final MoviesInteractor moviesInteractor;
    private MoviesView view;
    private Subscription fetchSubscription;

    public MoviesPresenterImpl(MoviesInteractor moviesInteractor) {
        this.moviesInteractor = moviesInteractor;
    }

    @Override
    public void downloadMovies() {

        fetchSubscription = moviesInteractor.getMovieList(new MoviesInteractorImpl.GetMovieListCallback() {
            @Override
            public void onSuccess(List<MovieModel> movieModels) {
                onMovieFetchSuccess(movieModels);
            }

            @Override
            public void onError(NetworkError networkError) {
                onMovieFetchFailed(new Throwable(networkError));
            }
        });

    }

    @Override
    public void setView(MoviesView view) {
        this.view = view;
        downloadMovies();
    }

    @Override
    public void destroy() {
        view = null;
        fetchSubscription.unsubscribe();
    }

    private void onMovieFetchSuccess(List<MovieModel> movies) {
        if (isViewAttached()) {
            view.showMovies(movies);
        }
    }

    //....
}
public class MoviesInteractorImpl implements MoviesInteractor {

    private Observable<MoviesResponseModel> call;

    public MoviesInteractorImpl(MoviesRetrofitService moviesRetrofitService) {
        call = moviesRetrofitService.getMovies("en", "popularity.desc", "MY_API_KEY");
    }

    @Override
    public Subscription getMovieList(final GetMovieListCallback callback) {

        return call
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Subscriber<MoviesResponseModel>() {
                    @Override
                    public void onStart() {
                        super.onStart();
                    }

                    @Override
                    public void onCompleted() {
                    }

                    @Override
                    public void onError(Throwable e) {
                        callback.onError(new NetworkError(e));
                    }

                    @Override
                    public void onNext(MoviesResponseModel cityListResponse) {
                        callback.onSuccess(cityListResponse.getMovieList());
                    }
                });
    }

    public interface GetMovieListCallback {
        void onSuccess(List<MovieModel> movieModels);

        void onError(NetworkError networkError);
    }

}
匕首模块:

@Module
public class ListingModule {

    @Provides
    public MoviesRetrofitService provideMoviesRetorfitService(Retrofit retrofit) {
        return retrofit.create(MoviesRetrofitService.class);
    }

    @Provides
    MoviesInteractor provideMoviesInteractor(MoviesRetrofitService moviesRetrofitService){
        return new MoviesInteractorImpl(moviesRetrofitService);
    }

    @Provides
    MoviesPresenter provideMoviesPresenter(MoviesInteractor moviesInteractor){
        return new MoviesPresenterImpl(moviesInteractor);
    }

}
匕首组件-子组件:

@ListingScope
@Subcomponent(modules = {ListingModule.class})
public interface ListingComponent {
    MoviesFragment inject(MoviesFragment moviesFragment);
}

您可以使用清单上的一个简单属性来防止销毁活动(及其片段):

android:configChanges="orientation|screenSize"
使用此选项,当您旋转屏幕时,活动将不会执行任何生命周期方法(onResume、onPause等)

有一个具体的问题:


和官方文档:

您可以等待取消订阅,直到通过GetMovieListCallback收到MoviesInteractor的响应

如果在
onMovieFetchSuccess
onMovieFetchFailed
之前调用了
setView
,则
fetchSubscription
将不会取消订阅。 如果在重置MoviesView之前完成抓取,则可以保存该电影,并在MoviesView重置后立即更新视图

public class MoviesInteractorImpl implements MoviesInteractor {
    private boolean needToUnsubscribe = false;
    private List<MovieModel> lastMovies;

    //....

    @Override
    public void setView(MoviesView view) {
        this.view = view;
        needToUnsubscribe = false;
        if(lastMovies != null) {
            view.showMovies(movies);
        }
        downloadMovies();
    }

    @Override
    public void destroy() {
        view = null;
        needToUnsubscribe = true;
    }

    private void onMovieFetchSuccess(List<MovieModel> movies) {
        lastMovies = movies;
        if (isViewAttached()) {
            view.showMovies(movies);
        }
        if(needToUnsubscribe) {
            fetchSubscription.unsubscribe();
        }
    }

    private void onMovieFetchFailed(Throwable throwable) {
         //....
        lastMovies = null;
        if(needToUnsubscribe) {
            fetchSubscription.unsubscribe();
        }
    }
}
公共类MoviesInteractitorImpl实现MoviesInteractitor{
私有布尔值needToUnsubscribe=false;
私人电影;
//....
@凌驾
公共void集合视图(MoviesView视图){
this.view=视图;
needToUnsubscribe=false;
如果(lastMovies!=null){
观看。放映电影(电影);
}
下载电影();
}
@凌驾
公共空间销毁(){
视图=空;
needToUnsubscribe=true;
}
私有void onMovieFetchSuccess(列出电影){
最后的电影=电影;
如果(isViewAttached()){
观看。放映电影(电影);
}
如果(需要订阅){
fetchSubscription.unsubscripte();
}
}
MovieFetchFailed上的私有void(可丢弃可丢弃){
//....
lastMovies=null;
如果(需要订阅){
fetchSubscription.unsubscripte();
}
}
}
文档中的“自行处理配置更改会使使用替代资源变得更加困难,因为系统不会自动为您应用这些资源。当您必须避免因配置更改而重新启动时,应将此技术视为最后手段,大多数应用程序不建议使用此技术。”
public class MoviesInteractorImpl implements MoviesInteractor {
    private boolean needToUnsubscribe = false;
    private List<MovieModel> lastMovies;

    //....

    @Override
    public void setView(MoviesView view) {
        this.view = view;
        needToUnsubscribe = false;
        if(lastMovies != null) {
            view.showMovies(movies);
        }
        downloadMovies();
    }

    @Override
    public void destroy() {
        view = null;
        needToUnsubscribe = true;
    }

    private void onMovieFetchSuccess(List<MovieModel> movies) {
        lastMovies = movies;
        if (isViewAttached()) {
            view.showMovies(movies);
        }
        if(needToUnsubscribe) {
            fetchSubscription.unsubscribe();
        }
    }

    private void onMovieFetchFailed(Throwable throwable) {
         //....
        lastMovies = null;
        if(needToUnsubscribe) {
            fetchSubscription.unsubscribe();
        }
    }
}