我在ViewPager
中使用MainActivity
,FragmentPagerAdapter
有四个片段。在片段中,数据显示在ListView
上,并带有自定义适配器NewsAdapter
。此数据从网络加载并通过Loader
返回到片段。一切都适用于应用程序的初始创建,数据加载到视图上没有错误。我遇到的问题是当我滚动ViewPager
跨越两个标签时onDestroyView
在片段中调用了两个标签,当我返回到该片段时,除ProgressBar
之外没有任何东西被夸大,调用View.GONE
时设置为onLoadFinished
。这首先按预期工作。
onLoadFinished
,mProgressBar.setVisibility.(View.GONE)
也没有被执行。mAdapter
中onCreateView
不为空,并且设置为空onDestroyView
,因此我认为Loader
正在更新mAdapter
时我回到了每个片段onDestroy
并在onResume
中调用MainActivity
时,屏幕上没有任何内容被绘制,直到我再次旋转(返回垂直),然后片段状态如预期直到滚动。FragmentPagerAdapter
更改为FragmentStatePagerAdapter
,但没有任何更改。mAdapter
中清除了mRootView
和onDestroyView
,以便在onResume
片段以下是我的一个片段(除了名称和Loader
ID之外,它们都是相同的)
package com.example.android.greennewswire;
import android.app.LoaderManager; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ListView; import android.widget.ProgressBar;
import java.util.ArrayList;
public class NewsFragmentSky extends Fragment implements LoaderManager.LoaderCallbacks<ArrayList<News>>{
public NewsFragmentSky() {
// Required empty public constructor
}
//String object holding the network request URL to be passed into the Loader
private static final String NEWS_REQUEST_URL = "https://www.googleapis.com/books/v1/volumes?q=android";
private static final String LOG_TAG = "NewsFragmentBBC";
private NewsAdapter mAdapter;
private View mRootView;
private ProgressBar mProgressBar;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
mRootView = inflater.inflate(R.layout.list, container, false);
//Create a LoaderManager and initialise the Loader
LoaderManager loaderManager = getActivity().getLoaderManager();
loaderManager.initLoader(4, null, this);
mProgressBar = (ProgressBar) mRootView.findViewById(R.id.progress_bar);
//TODO fix context problem!
mAdapter = new NewsAdapter(getActivity(), new ArrayList<News>());
ListView listView = (ListView) mRootView.findViewById(R.id.list);
listView.setAdapter(mAdapter);
boolean rootViewEmpty = (mRootView == null);
Log.i(LOG_TAG, "rootView null? " + rootViewEmpty);
Log.i(LOG_TAG, "onCreateView called");
return mRootView;
}
@Override
public void onDestroyView() {
mAdapter.clear();
mRootView = null;
boolean rootViewEmpty = (mRootView == null);
Log.i(LOG_TAG, "rootView null? " + rootViewEmpty);
Log.i(LOG_TAG, "onDestroyView called.");
super.onDestroyView();
}
@Override
public void onPause() {
Log.i(LOG_TAG, "onPause called.");
super.onPause();
}
@Override
public void onStop() {
Log.i(LOG_TAG, "onStop called.");
super.onStop();
}
@Override
public void onResume() {
Log.i(LOG_TAG, "onResume called.");
super.onResume();
}
@Override
public android.content.Loader<ArrayList<News>> onCreateLoader(int i, Bundle bundle) {
Log.i(LOG_TAG, "onCreateLoader called.");
return new NewsLoader(getContext(), NEWS_REQUEST_URL);
}
@Override
public void onLoadFinished(android.content.Loader<ArrayList<News>> loader, ArrayList<News> newses) {
mAdapter.addAll(newses);
mProgressBar.setVisibility(View.GONE);
boolean adapterState = mAdapter.isEmpty();
Log.i(LOG_TAG, "onLoadFinished mAdapter null? " + adapterState);
}
@Override
public void onLoaderReset(android.content.Loader<ArrayList<News>> loader) {
Log.i(LOG_TAG, "onLoaderReset called.");
mAdapter.clear();
} }
FragmentAdapter
package com.example.android.greennewswire;
import android.content.Context;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.util.Log;
public class FragmentAdapter extends FragmentPagerAdapter {
private static final String LOG_TAG = FragmentAdapter.class.getSimpleName();
private Context mContext;
public FragmentAdapter(Context context, FragmentManager fm) {
super(fm);
mContext = context;
}
@Override
public Fragment getItem(int position) {
if (position == 0) {
Log.i(LOG_TAG, "FragmentAdapter position: " + position);
return new NewsFragmentBBC();
} else if (position == 1) {
Log.i(LOG_TAG, "FragmentAdapter position: " + position);
return new NewsFragmentReuters();
} else if (position == 2) {
Log.i(LOG_TAG, "FragmentAdapter position: " + position);
return new NewsFragmentRT();
} else {
Log.i(LOG_TAG, "FragmentAdapter position: " + position);
return new NewsFragmentSky();
}
}
@Override
public int getCount() {
return 4;
}
@Override
public CharSequence getPageTitle(int position) {
if (position == 0) {
return mContext.getString(R.string.category_bbc);
} else if (position == 1) {
return mContext.getString(R.string.category_reuters);
} else if (position == 2) {
return mContext.getString(R.string.category_rt);
} else {
return mContext.getString(R.string.category_sky);
}
}
}
修改:我为片段的LoaderManager
和onDestroy
创建了一个局部变量,名为destroyLoader(i)
。这似乎有效,当我滚动选项卡中的片段并返回时,片段视图是使用数据创建的。我只是添加了这个,因为我不确定这是否是最佳做法?我希望这会创建一个新的Loader
并在每次创建片段时从网络获取数据,这实际上会使Loader
无法解决问题。我的假设是正确的吗?
Edit2:我现在在每个片段的mLoaderManager.initLoader(id, null, this)
方法中调用onResume
。当我滚动选项卡时,检查Android Studio监视网络流量图只能从网络中获取一次数据。我仍然有一个问题,虽然手机旋转,视图不是在第一次旋转(横向)创建,但旋转回到肖像应用程序行为是预期的。我接下来会查看我的MainActivity
生命周期。