当恢复片段时,如何在ViewPager中维护在Fragment的onCreateView中创建的视图实例?

4
故事是这样的,ViewPager中有五个片段,每个片段在ViewPager上出现时都必须运行一个AsyncTask。 我正尝试与正确答案 相同 。 我将我的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;
    }

}

这是我的第二个Fragment代码,其余的Fragments目前都是空白的。
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异步Http客户端代替AsyncTask

2个回答

1

我认为它在少数片段中运行良好。我的只有5个,但我想要一个未来使用的解决方案。 - Zin Win Htet

1
最终我找到了解决方案。它非常简单。
  1. I removed implementation of the interface FragmentLifecycle.
  2. Added the following method to each fragments.

    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
         super.setUserVisibleHint(isVisibleToUser);
         if(isVisibleToUser && !isDataLoaded){
             getVocalistList(Gender.All);
             isDataLoaded = true;
         }
    }
    
它像魔法一样有效。我不需要担心失去RecyclerView实例,因为当调用setUserVisibleHint方法时,它不会为空。

1
我不太相信这是“非常简单”的,但感谢你的发现...我正在使用ButterKnife,我发现每次返回ViewPager内部的Fragment时,我的RecyclerView都被解散并创建了一个新的...我该在哪里找到FragmentLifecycle接口?还有,在AsyncTask完成数据加载之前为什么要将isDataLoaded标志设置为true? - rexxar
1
抱歉回复迟了,这是您需要的链接。https://dev59.com/42Eh5IYBdhLWcg3w32xG#24386516 - Zin Win Htet

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接