ListFragment有时会跳过Loader的onLoadFinished()方法中的代码

时间:2017-10-31 20:26:45

标签: android android-viewpager android-listfragment android-loader

我有一个ListFragment,它使用Loader从网络中提取数据。我在ListFragment的每个页面中使用了此ViewPager的新实例。它工作正常,但当我使用TabLayout或快速移动页面时,Fragment会继续加载,并且不会在ListView中显示数据。

当我使用日志消息检查时,我发现ListFragmentonLoadFinished()方法中跳过了一些代码行。它不会使ProgressBar不可见。它会向Adapter添加项目,但不会显示在ListView中。此问题也发生在ViewPager的第一页。

ListFragment中使用ViewPager时是否需要遵循任何具体规则?

这是ListFragment课程。如果查看onLoadFinished()方法,可以看到导致问题的行:

public class ListViewFragment extends ListFragment
    implements LoaderManager.LoaderCallbacks<List<GameNews>> {

    public static ListViewFragment newInstance(String url) {
        Log.d("ListViewFragment", "newInstance created");
        ListViewFragment f = new ListViewFragment();

        // Supply url input as an argument.
        Bundle args = new Bundle();
        args.putString("url", url);
        f.setArguments(args);
        return f;
    }

    List<GameNews> TotalNews;
    ListView gameListView;
    LinearLayout emptyView;
    Button retryButton;
    ListAdapter adapter ;
    private View progressBar;
    final private int game_loader = 0;
    ArrayList<String> urls = new ArrayList<>();
    String mUrlString;
    int index;

    //LIFE CYCLE OF FRAGMENT
    //------------------------------------------------------------------
    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mUrlString = getArguments().getString("url");
        urls.add(mUrlString);
        TotalNews = new ArrayList<GameNews>();
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.fragment_list_view, container, false);

        ArrayList<GameNews> gameList = new ArrayList<>();
        adapter = new ListAdapter(getActivity(), gameList);
        return rootView;
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        emptyView = (LinearLayout)
            view.findViewById(R.id.no_internet_view);
        progressBar = view.findViewById(R.id.progress_bar);
        retryButton = (Button) view.findViewById(R.id.retry_button);
        gameListView = getListView();
        emptyView.setVisibility(View.INVISIBLE);
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        setListAdapter(adapter);

        //If connected to net start the loader
        if (isConnected()) {
            getActivity().getSupportLoaderManager().restartLoader(game_loader,
                                                                  null,
                                                                  ListViewFragment.this);
        }
    }

    //OVERRIDED METHODS OF LOADERMANAGER
    //---------------------------------------------------------------------
    @Override
    public android.support.v4.content.Loader<List<GameNews>> onCreateLoader(int i, Bundle bundle) {
        AdManager manager =  new AdManager(getActivity());
        return new FragmentLoader(getActivity(), urls, 1000);

    }

    //HERE IS THE PROBLEM PLEASE FOCUS INSIDE THIS METHOD
    //-------------------------------------------------------
    @Override
    public void onLoadFinished(Loader<List<GameNews>> loader, List<GameNews> games) {

        progressBar.setVisibility(View.INVISIBLE); //This line of code is not executed
        adapter.clear();
        TotalNews.addAll(games);
        adapter.addAll(games);//And the listView is not populated
    }
    //-------------------------------------------------------

    @Override
    public void onLoaderReset(Loader<List<GameNews>> loader) {
        adapter.clear();
    }

    //REUSABLE METHODS
    //------------------------------------------------------------------
    //Method checks if there is internet
    public boolean isConnected() {
        ConnectivityManager manager = (ConnectivityManager)
            getActivity().getSystemService(CONNECTIVITY_SERVICE);
        NetworkInfo info = manager.getActiveNetworkInfo();
        if (info != null && info.isConnected()) {
            return true;
        }
        else {
            return false;
        }
    }
}

1 个答案:

答案 0 :(得分:0)

您的Fragment班级正在使用Activity的{​​{1}}:

LoaderManager

每个实例在其getActivity().getSupportLoaderManager().restartLoader(...); 调用中使用相同的ID:

restartLoader()

这意味着每个final private int game_loader = 0; 实例都在反复使用并重新启动相同的Fragment,从而导致您观察到的奇怪行为。

解决方案非常简单:使用Loader的本地Fragment,而不是LoaderManager

Activity

有了这个,您无需担心在每个实例中更改ID,因为getLoaderManager().restartLoader(...); 对于Loader是唯一的,并且Fragment将被正确处理Loader的生命周期,使用Fragment Activity时可能不会出现这种情况。