Android MVP-在配置更改期间仍然存在的网络请求
我在网上学习了一些教程和开源软件,并使用RxJava、Dagger 2和改型构建了基于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{
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();
}
}
}