我正在使用ActionBarSherlock 示例进行构建。我有 3 个片段(每个扩展SherlockListFragment
和实现LoaderManager.LoaderCallbacks<>
),每个选项卡中有 1 个。他们都使用装载机。选项卡 2 和 3 使用相同的加载器类(我认为这不是问题)。
我将选项卡添加到我的选项卡中,FragmentPagerAdapter
其中包含对不同片段的类引用,如果需要,还包括捆绑包。当我的应用程序启动并显示选项卡 0 时,getItem inFragmentPagerAdapter
通过创建它们的片段来准备选项卡 0 和选项卡 1。选项卡 2 尚未创建。当我滑动到选项卡 1 时,会加载选项卡 2。当我再次滑动时,选项卡 2 正确显示。
当我从 tab 0 单击到 tab 2 时,会出现问题。getItem
确实创建了片段,并且加载器开始了它的doInBackground
处理,但是选项卡 2 的片段永远不会在 onLoadFinished 中获取数据,因此与不确定的进度条保持一致。
之前发生了一些奇怪的事情。如果我单击,选项卡 2onLoadFinished
将从选项卡 0 的加载器接收数据。当我将每个选项卡的片段加载器更改为使用不同的 ID 时(我认为即使它们具有相同的 ID,它们也不应该发生冲突),问题就消失了。例如:getLoaderManager().initLoader(0, null, this)
,getLoaderManager().initLoader(1, null, this)
等。我不确定这是否只是说明我对装载机或其他东西的无知。
我的主要问题是,我可以强制FragmentPagerAdapter
一次加载所有标签吗?即使这样做也可能不会完全消除我的代码中的这个错误。
第二个问题:当我四处滑动并单击刷新(请参阅下面的代码以了解其作用)时,操作栏中的刷新按钮最终会消失。有什么想法吗?
MainActivity(非常类似于链接的 ABS 示例):
public class MainActivity extends SherlockFragmentActivity{
private static final int NUMBER_OF_STREAMS = 9;
ViewPager mViewPager;
TabHost mTabHost;
TabsAdapter mTabsAdapter;
private JTVApplication mApplication;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Set up application
if (mApplication == null)
this.mApplication = (JTVApplication)getApplication();
mTabHost = (TabHost)findViewById(android.R.id.tabhost);
mTabHost.setup();
// Set up the ViewPager with the sections adapter.
mViewPager = (ViewPager) findViewById(R.id.pager);
// SET UP TABS ADAPTER
mTabsAdapter = new TabsAdapter(this, mTabHost, mViewPager);
mTabsAdapter.addTab(mTabHost.newTabSpec("categories").setIndicator("Categories"), CategoryListFragment.class, null);
mTabsAdapter.addTab(mTabHost.newTabSpec("top_streams").setIndicator("Top Streams"), StreamListFragment.class, StreamListFragment.instanceBundle(null, null, null, null, NUMBER_OF_STREAMS, 0));
mTabsAdapter.addTab(mTabHost.newTabSpec("favorites").setIndicator("Favorites"), FavoriteListFragment.class, null);
if (savedInstanceState != null) {
mTabHost.setCurrentTabByTag(savedInstanceState.getString("tab"));
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("tab", mTabHost.getCurrentTabTag());
}
/**
* A {@link FragmentPagerAdapter} that returns a fragment corresponding to
* one of the sections/tabs/pages.
*/
public static class TabsAdapter extends FragmentPagerAdapter implements TabHost.OnTabChangeListener, ViewPager.OnPageChangeListener {
private final Context mContext;
private final TabHost mTabHost;
private final ViewPager mViewPager;
private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
static final class TabInfo {
@SuppressWarnings("unused")
private final String tag;
private final Class<?> clss;
private final Bundle args;
TabInfo(String _tag, Class<?> _class, Bundle _args) {
tag = _tag;
clss = _class;
args = _args;
}
}
static class DummyTabFactory implements TabHost.TabContentFactory {
private final Context mContext;
public DummyTabFactory(Context context) {
mContext = context;
}
@Override
public View createTabContent(String tag) {
View v = new View(mContext);
v.setMinimumWidth(0);
v.setMinimumHeight(0);
return v;
}
}
List<Fragment> fragments = new ArrayList<Fragment>();
public TabsAdapter(FragmentActivity activity, TabHost tabHost, ViewPager pager) {
super(activity.getSupportFragmentManager());
mContext = activity;
mTabHost = tabHost;
mViewPager = pager;
mTabHost.setOnTabChangedListener(this);
mViewPager.setAdapter(this);
mViewPager.setOnPageChangeListener(this);
}
public void addTab(TabHost.TabSpec tabSpec, Class<?> clss, Bundle args) {
tabSpec.setContent(new DummyTabFactory(mContext));
String tag = tabSpec.getTag();
TabInfo info = new TabInfo(tag, clss, args);
mTabs.add(info);
mTabHost.addTab(tabSpec);
notifyDataSetChanged();
}
@Override
public Fragment getItem(int position) {
TabInfo info = mTabs.get(position);
return Fragment.instantiate(mContext, info.clss.getName(), info.args);
}
@Override
public int getCount() {
return mTabs.size();
}
@Override
public void onPageScrollStateChanged(int arg0) {}
@Override
public void onPageScrolled(int arg0, float arg1, int arg2) {}
@Override
public void onPageSelected(int position) {
TabWidget widget = mTabHost.getTabWidget();
int oldFocusability = widget.getDescendantFocusability();
widget.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
mTabHost.setCurrentTab(position);
widget.setDescendantFocusability(oldFocusability);
}
@Override
public void onTabChanged(String tabId) {
int newPosition = mTabHost.getCurrentTab();
mViewPager.setCurrentItem(newPosition, true);
}
}
}
Tab0 片段(与其他片段非常相似,因此我将省略其他片段):
public class CategoryListFragment extends SherlockListFragment implements LoaderManager.LoaderCallbacks<List<Category>>{
public List<Category> mCategories;
public List<Stream> mStreams;
private int mLimit;
private CategoryAdapter mCategoryAdapter;
private String mSearchFilter;
private RestClient mCategoryClient;
public List<Category> getCategories() {
return mCategories;
}
public void setCategories(List<Category> categories) {
this.mCategories = categories;
}
public CategoryListFragment() {
}
@Override
public void onCreate(Bundle savedInstance){
super.onCreate(savedInstance);
this.setHasOptionsMenu(true);
if (mCategoryClient == null)
this.mCategoryClient = JTVApi.getCategories();
// Prepare the loader
getLoaderManager().initLoader(0, null, this);
}
@Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater){
// CREATE REFRESH BUTTON
MenuItem refreshMenu = menu.add("Refresh");
refreshMenu.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
refreshMenu.setIcon(R.drawable.ic_menu_refresh);
refreshMenu.setOnMenuItemClickListener(new OnMenuItemClickListener() {
public boolean onMenuItemClick(MenuItem item) {
CategoryListFragment.this.setListShown(false);
CategoryListFragment.this.getLoaderManager().restartLoader(0, null, CategoryListFragment.this);
return true;
}
});
}
@Override
public void onLoadFinished(Loader<List<Category>> arg0, List<Category> data) {
if (mCategories == null){
mCategoryAdapter = new CategoryAdapter(getActivity(), R.id.listItem, data);
this.setListAdapter(mCategoryAdapter);
} else {
mCategoryAdapter.setData(data);
}
this.setListShown(true);
}
@Override
public void onLoaderReset(Loader<List<Category>> arg0) {
// TODO check for null
mCategoryAdapter.setData(null);
}
@Override
public Loader<List<Category>> onCreateLoader(int arg0, Bundle arg1) {
return new CategoryLoader(getActivity(), mLimit, mCategoryClient);
}
}
Tab0 加载器(与其他加载器非常相似,因此我将省略其他加载器):
public class CategoryLoader extends AsyncTaskLoader<List<Category>> {
JTVApplication mApplication;
RestClient mRestClient;
List<Category> mCategories;
public CategoryLoader(Context context, int limit, RestClient restClient) {
super(context);
this.mRestClient = restClient;
mApplication = (JTVApplication)context.getApplicationContext();
}
@Override
public List<Category> loadInBackground() {
List<Category> categories = null;
Object json;
try {
json = mApplication.getJSON(mRestClient, mRestClient.bypassCache());
if (mRestClient.getApiMethod() == APIMethod.CATEGORY_LIST && json instanceof JSONObject){
JSONObject jsonObject = (JSONObject)json;
categories = Category.parseCategories(jsonObject);
// Get total count of viewers for "All Categories"
int total_viewers = 0;
for (Category category : categories)
total_viewers += category.getViewers_count();
categories.add(new Category(Category.ALL_CATEGORIES, "All Streams", total_viewers, 0, 0, null, "All Streams"));
// Update global categories list with this data
mApplication.setCategories(categories);
return categories;
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
/**
* Called when there is new data to deliver to the client. The
* super class will take care of delivering it; the implementation
* here just adds a little more logic.
*/
@Override
public void deliverResult(List<Category> data) {
mCategories = data;
if (isStarted()) {
super.deliverResult(data);
}
}
/**
* Handles a request to start the Loader.
*/
@Override
protected void onStartLoading() {
if (mCategories != null){
// If we currently have a result available, deliver it
// immediately.
deliverResult(mCategories);
}
// TODO CHECK FOR NEW DATA OR TIMER
if (mCategories == null){
forceLoad();
}
}
/**
* Handles a request to stop the Loader.
*/
@Override protected void onStopLoading() {
// Attempt to cancel the current load task if possible.
cancelLoad();
}
/**
* Handles a request to completely reset the Loader.
*/
@Override
protected void onReset() {
super.onReset();
}
}
适配器非常基本,我相信它们不是问题。如果有人问我可以提供更多代码,但我认为这已经足够了。 提前感谢您的帮助。
更新:
当我简单地替换FragmentPagerAdapter
它FragmentStatePagerAdapter
时。我看到它在FragmentPagerAdapter getItem is not called中引用。我的代码和使用有什么问题FragmentPagerAdapter
?