ListFragment有时会跳过Loader的onLoadFinished()方法中的代码
ListFragment sometimes skips code in onLoadFinished() method of Loader
我有一个 ListFragment
,它使用 Loader
从网上获取数据。我在 ViewPager
的每一页中都使用了这个 ListFragment
的新实例。它工作得很好,但是当我使用 TabLayout
或快速移动页面时,Fragment
一直在加载并且不显示 ListView
.
中的数据
当我使用日志消息检查时,我发现 ListFragment
跳过了 onLoadFinished()
方法中的一些代码行。它不会使 ProgressBar
不可见。它确实将项目添加到 Adapter
,但未显示在 ListView
中。 ViewPager
.
的第一页也出现了这个问题
在 ViewPager
中使用 ListFragment
时是否有任何特定规则要遵循?
这里是ListFragment
class。如果您查看 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;
}
}
}
您的 Fragment
class 正在使用 Activity
的 LoaderManager
:
getActivity().getSupportLoaderManager().restartLoader(...);
并且每个实例在其 restartLoader()
调用中使用相同的 ID:
final private int game_loader = 0;
这意味着每个 Fragment
实例都在一次又一次地使用和重新启动相同的 Loader
,导致您观察到的奇怪行为。
解决方案非常简单:使用 Fragment
的本地 LoaderManager
,而不是 Activity
的本地
getLoaderManager().restartLoader(...);
有了这个,您就不必担心在每个实例中更改 ID,因为 Loader
对它们的 Fragment
来说是唯一的,并且 Loader
将是正确的在 Fragment
的生命周期内处理,使用 Activity
的 LoaderManager
.
时可能不会出现这种情况
我有一个 ListFragment
,它使用 Loader
从网上获取数据。我在 ViewPager
的每一页中都使用了这个 ListFragment
的新实例。它工作得很好,但是当我使用 TabLayout
或快速移动页面时,Fragment
一直在加载并且不显示 ListView
.
当我使用日志消息检查时,我发现 ListFragment
跳过了 onLoadFinished()
方法中的一些代码行。它不会使 ProgressBar
不可见。它确实将项目添加到 Adapter
,但未显示在 ListView
中。 ViewPager
.
在 ViewPager
中使用 ListFragment
时是否有任何特定规则要遵循?
这里是ListFragment
class。如果您查看 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;
}
}
}
您的 Fragment
class 正在使用 Activity
的 LoaderManager
:
getActivity().getSupportLoaderManager().restartLoader(...);
并且每个实例在其 restartLoader()
调用中使用相同的 ID:
final private int game_loader = 0;
这意味着每个 Fragment
实例都在一次又一次地使用和重新启动相同的 Loader
,导致您观察到的奇怪行为。
解决方案非常简单:使用 Fragment
的本地 LoaderManager
,而不是 Activity
的本地
getLoaderManager().restartLoader(...);
有了这个,您就不必担心在每个实例中更改 ID,因为 Loader
对它们的 Fragment
来说是唯一的,并且 Loader
将是正确的在 Fragment
的生命周期内处理,使用 Activity
的 LoaderManager
.