【问题标题】:How to maintain view instances created in onCreateView of Fragment in ViewPager when Resuming the fragment?恢复片段时如何维护ViewPager中Fragment的onCreateView中创建的视图实例?
【发布时间】:2017-02-24 06:02:14
【问题描述】:

故事是ViewPager中有五个片段,每个片段出现在ViewPager上时都必须运行一个AsyncTask。我正在尝试与正确答案here 完全相同。我把我的AsyncTask 放在onResumeFragment 中,它工作正常。但是当我在AsyncTask 成功运行后更新视图时,问题就开始了。因为当我更新数据集时,我在 onCreateView 中创建的视图(RecyclerView)是 null。我还在onActivityCreated 中尝试了setRetainInstance(true)。它没有用。

这是我的代码,

MainActivity.java

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    //Tab & Pager

    viewPager = (ViewPager) findViewById(R.id.main_tab_content);
    adapter = new ViewPagerAdapter(getSupportFragmentManager());
    viewPager.setAdapter(adapter);
    addPagerListener();
}

private void addPagerListener(){
    viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {

        @Override
        public void onPageSelected(int newPosition) {
            FragmentLifecycle fragmentToShow = (FragmentLifecycle)adapter.getItem(newPosition);
            fragmentToShow.onResumeFragment();

            FragmentLifecycle fragmentToHide = (FragmentLifecycle)adapter.getItem(currentPosition);
            fragmentToHide.onPauseFragment();

            currentPosition = newPosition;
        }

        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

        }

        @Override
        public void onPageScrollStateChanged(int state) {

        }
    });
}

class ViewPagerAdapter extends FragmentPagerAdapter {
    public ViewPagerAdapter(FragmentManager manager) {
        super(manager);
    }

    @Override
    public Fragment getItem(int position) {
        switch (position){
            case 0: return new HomeFragment();
            case 1: return new ArtistFragment();
            case 2: return new AlbumsFragment();
            case 3: return new CollectionsFragment();
            case 4: return new SavedFragments();
            default: return null;
        }
    }

    @Override
    public int getCount() {
        return 5;
    }

}

这是我的第二个片段代码,到目前为止,其余片段都是空白的。

public class ArtistFragment extends Fragment implements FragmentLifecycle{

@BindView(R.id.recyclerview_frag_artist)
RecyclerView mRecyclerView;

RecyclerView.Adapter mAdapter;
RecyclerView.LayoutManager mLayoutManager;

@BindView(R.id.radioBtnAll_frag_artist)
RadioButton radioAll;

@BindView(R.id.radioBtnMale_frag_artist)
RadioButton radioMale;

@BindView(R.id.radioBtnFemale_frag_artist)
RadioButton radioFemale;

ArrayList<String> vocalistNameList;
Context context;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    View rootView = inflater.inflate(R.layout.fragment_artists, container, false);
    ButterKnife.bind(this, rootView);
    mRecyclerView.setHasFixedSize(true);
    mLayoutManager = new LinearLayoutManager(rootView.getContext());
    mRecyclerView.setLayoutManager(mLayoutManager);
    vocalistNameList = getDummyDS();
    mAdapter = new MyListAdapter(vocalistNameList);
    mRecyclerView.setAdapter(mAdapter);
    radioAll.setChecked(true);
    return rootView;
}

@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    setRetainInstance(true);
}

private ArrayList<String> getDummyDS(){
    ArrayList<String> dataset = new ArrayList<>();
    dataset.add("test");
    dataset.add("test");
    dataset.add("test");
    dataset.add("test");
    dataset.add("test");
    dataset.add("test");
    dataset.add("test");
    return dataset;
}

private void getVocalistList(Gender gender){
    RequestParams params = new RequestParams();
    params.put("action","query");
    params.put("list","allcategories");
    params.put("acprefix","Vocalist-");
    params.put("format","json");
    params.put("aclimit","5000");

    MyRestClient.get("", params, new JsonHttpResponseHandler(){
        ProgressDialog progress;
        @Override
        public void onStart() {
            progress = ProgressDialog.show(AppConstants.activity, "Please wait",
                        "Loading data..", true);
            progress.setCancelable(true);
        }

        @Override
        public void onSuccess(int statusCode, Header[] headers, JSONObject response) {
            progress.dismiss();
            vocalistNameList = new ArrayList<String>();
            try {
                JSONArray vocalListJsonArray = response.getJSONObject("query").getJSONArray("allcategories");
                for(int i=0; i<vocalListJsonArray.length(); i++){
                    String vocalListName = vocalListJsonArray.getJSONObject(i).getString("*").replace("Vocalist-","");
                    vocalistNameList.add(vocalListName);
                }
                mAdapter = new MyListAdapter(vocalistNameList);
                mRecyclerView.setAdapter(mAdapter); // <= RecyclerView is null and app is crashing
                mAdapter.notifyDataSetChanged();
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) {
            progress.dismiss();
            Log.i("failure", "failed "+statusCode);
        }
    });
}

@Override
public void onPauseFragment() {
    Toast.makeText(AppConstants.applicationContext, "onPauseFragment():", Toast.LENGTH_SHORT).show();
}

@Override
public void onResumeFragment() {
    getVocalistList(Gender.All);
    Toast.makeText(AppConstants.applicationContext, "onResumeFragment(): Artist", Toast.LENGTH_SHORT).show();
}

从一周前开始,我一直在尝试解决这个问题。任何想法? (P.S 我用的是Android Asynchronous Http Client 而不是AsyncTask

【问题讨论】:

    标签: android android-fragments android-asynctask android-viewpager


    【解决方案1】:

    你必须这样做:

    pager.setOffscreenPageLimit([quantity of tabs that you would like to keep in memory]);
    

    看看这个答案。 ViewPager inside Fragment loses content when returning to it

    【讨论】:

    • 我认为它适用于少量片段。我的只有 5 岁,但我想要一个未来使用的解决方案。
    【解决方案2】:

    我终于找到了解决方案。这很简单。

    1. 我删除了 FragmentLifecycle 接口的实现。
    2. 为每个片段添加了以下方法。

      @Override
      public void setUserVisibleHint(boolean isVisibleToUser) {
           super.setUserVisibleHint(isVisibleToUser);
           if(isVisibleToUser && !isDataLoaded){
               getVocalistList(Gender.All);
               isDataLoaded = true;
           }
      }
      

    它就像魔术一样工作。我不必担心会丢失 RecyclerView 实例,因为在调用 setUserVisibleHint 方法时它不为空。

    【讨论】:

    • 好吧,我不太相信这是“非常简单”,但感谢您的发现...我正在使用 ButterKnife,我看到我的 RecyclerView 正在被解雇,并且一个新的每次我返回 ViewPager 中的 Fragment 时都会创建一个...我在哪里可以找到 FragmentLifecycle 接口?还有,为什么要在 AsyncTask 完成加载数据之前将 isDataLoaded 标志设置为 true?
    • 对不起,我的回复晚了,给你。 stackoverflow.com/a/24386516/1976608
    猜你喜欢
    • 2014-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多