You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

横竖屏切换时Fragment避免重复请求API的实例状态保存咨询

嘿,这个问题我太有共鸣了——屏幕一旋转,Fragment就重新拉API,不仅浪费流量还影响体验。结合你的NowPlayingFragment代码,给你三个靠谱的解决方案,一步步来:

方案1:用setRetainInstance(true)(传统快速方案)

这个方法能让你的Fragment在Activity重建时不被销毁,直接保留实例,所以成员变量里的arrayList数据自然就不会丢。

怎么实现?

在Fragment的onCreate()方法里加一行核心代码:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setRetainInstance(true); // 关键:让Fragment实例在Activity重建时保留
}

注意事项

  • 虽然Fragment实例保留了,但View会在旋转时重建,所以要在onDestroyView()里把View相关变量置空,避免内存泄漏:
@Override
public void onDestroyView() {
    super.onDestroyView();
    searchMovie = null;
    btnSearch = null;
    mRecyclerView = null;
    mAdapter = null;
}
  • 别让Fragment持有Activity的强引用(比如不要把getActivity()赋值给成员变量),不然容易引发内存泄漏。
方案2:用onSaveInstanceState保存数据(系统标准方式)

如果不想保留Fragment实例,可以用系统自带的状态保存机制,把已加载的arrayList存进Bundle,旋转后再取出来复用。

前提条件

你的Movie类必须实现Serializable或者Parcelable接口(推荐Parcelable,效率更高),这样才能被Bundle序列化存储。比如用Android Studio自动生成Parcelable实现:

public class Movie implements Parcelable {
    // 你的Movie字段(比如id、title、posterUrl等)
    
    // 自动生成Parcelable的构造器、writeToParcel、describeContents等方法
}

保存数据

在Fragment里重写onSaveInstanceState,把列表存进Bundle:

@Override
public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putParcelableArrayList("saved_movie_list", arrayList); // 存储数据
}

恢复数据

在onCreateView或者onViewCreated里判断是否有保存的数据,有就直接复用,不用请求API:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.your_fragment_layout, container, false);
    // 初始化RecyclerView、按钮等View...
    
    if (savedInstanceState != null) {
        // 从Bundle取出之前保存的列表
        arrayList = savedInstanceState.getParcelableArrayList("saved_movie_list");
        if (arrayList != null) {
            // 直接给RecyclerView设置适配器,跳过API请求
            mAdapter = new YourMovieAdapter(arrayList);
            mRecyclerView.setAdapter(mAdapter);
            return view;
        }
    }
    
    // 没有保存的数据时,才去请求API
    loadDataFromApi();
    return view;
}
方案3:使用ViewModel(Jetpack推荐,最稳定)

这是现在Android开发的最佳实践,ViewModel的生命周期独立于Activity/Fragment的重建——屏幕旋转时ViewModel不会被销毁,数据自然保留,还能避免内存泄漏。

步骤1:添加ViewModel依赖

在模块级build.gradle里添加依赖(如果还没加):

dependencies {
    def lifecycle_version = "2.6.2"
    implementation "androidx.lifecycle:lifecycle-viewmodel:$lifecycle_version"
}

步骤2:创建ViewModel类

新建一个专门存数据的MovieViewModel:

import androidx.lifecycle.ViewModel;
import java.util.ArrayList;

public class MovieViewModel extends ViewModel {
    private ArrayList<Movie> movieList;

    public ArrayList<Movie> getMovieList() {
        return movieList;
    }

    public void setMovieList(ArrayList<Movie> movieList) {
        this.movieList = movieList;
    }
}

步骤3:在Fragment中使用ViewModel

修改你的NowPlayingFragment,从ViewModel中读取和存储数据:

public class NowPlayingFragment extends Fragment {
    private EditText searchMovie;
    private Button btnSearch;
    private String lang;
    private RecyclerView mRecyclerView;
    private RecyclerView.Adapter mAdapter;
    private RecyclerView.LayoutManager mLayoutManager;
    private MovieViewModel viewModel; // 新增ViewModel变量

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 获取ViewModel,关联Fragment生命周期
        viewModel = new ViewModelProvider(this).get(MovieViewModel.class);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.your_fragment_layout, container, false);
        // 初始化View和RecyclerView...
        
        // 先从ViewModel取数据
        ArrayList<Movie> savedList = viewModel.getMovieList();
        if (savedList != null && !savedList.isEmpty()) {
            // 有保存的数据,直接显示
            arrayList = savedList;
            mAdapter = new YourMovieAdapter(arrayList);
            mRecyclerView.setAdapter(mAdapter);
        } else {
            // 无数据时请求API
            loadDataFromApi();
        }
        
        // 搜索按钮点击后,更新数据要同步到ViewModel
        btnSearch.setOnClickListener(v -> {
            // 执行搜索逻辑...
            loadSearchResults();
        });
        
        return view;
    }

    // 假设这是你的API加载方法
    private void loadDataFromApi() {
        yourApiClient.getNowPlayingMovies(lang, new Callback() {
            @Override
            public void onSuccess(ArrayList<Movie> movies) {
                arrayList = movies;
                mAdapter = new YourMovieAdapter(arrayList);
                mRecyclerView.setAdapter(mAdapter);
                // 把数据存到ViewModel,确保旋转时不丢失
                viewModel.setMovieList(arrayList);
            }

            @Override
            public void onFailure(Throwable t) {
                // 处理错误逻辑...
            }
        });
    }
}

为什么推荐这个方案?

  • 完全规避内存泄漏风险,ViewModel会在Fragment真正销毁时才被清理
  • 数据与UI逻辑分离,代码更清晰易维护
  • 不仅支持屏幕旋转,还能应对Activity因其他系统原因重建的情况
总结
  • 快速实现选方案1,但要注意内存泄漏坑
  • 追求系统标准实现选方案2,适合小体量序列化数据
  • 现代Android开发首选方案3,稳定、安全且扩展性强

内容的提问来源于stack exchange,提问作者Pieter Haro

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 03:43:02