私はActionBarSherlock の例を使用して構築しています。各タブに 1 つずつ、3 つのフラグメント(それぞれ extendsSherlockListFragment
と implement ) があります。それらはすべてローダーを使用します。タブ 2 と 3 は同じローダー クラスを使用しています (これは問題ではないと思います)。LoaderManager.LoaderCallbacks<>
FragmentPagerAdapter
必要に応じてバンドルとともに、さまざまなフラグメントへのクラス参照を使用して、タブを my に追加します。アプリケーションが起動してタブ 0 が表示されると、 getItem のFragmentPagerAdapter
タブ 0 とタブ 1 がフラグメントを作成して準備が整います。タブ 2 はまだ作成されていません。タブ 1 にスワイプすると、タブ 2 が読み込まれます。もう一度スワイプすると、タブ 2 が正しく表示されます。
タブ 0 からタブ 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
か?