使用装载程序的TabsPager中的多个碎片,滑动工作,单击不

时间:2012-12-19 19:39:06

标签: android android-listfragment android-loadermanager fragmentpageradapter android-loader

我正在使用ActionBarSherlock example来构建。 我有3个片段(每个片段扩展SherlockListFragment并实现LoaderManager.LoaderCallbacks<>),每个标签中有1个片段。 他们都使用加载器。选项卡2和3使用相同的加载器类(我不认为这是一个问题)。

我将标签添加到我的FragmentPagerAdapter,其中包含对不同片段的类引用,以及必要时的包。当我的应用程序启动并显示选项卡0时,FragmentPagerAdapter中的getItem通过创建其片段获得选项卡0和选项卡1。标签2尚未创建。当我SWIPE到选项卡1时,加载选项卡2。当我再次滑动时,正确显示选项卡2。

当我从标签0点击标签2 时会出现问题。 getItem确实创建了片段,并且加载器开始其doInBackground处理,但是tab 2的片段永远不会获取onLoadFinished中的数据,因此坐在不确定的进度条上。

早些时候发生了一些奇怪的事。如果我点击,标签2的onLoadFinished将从标签0的加载器接收数据。当我更改每个选项卡的片段Loader以使用不同的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 Loader(非常类似于其他Loaders,所以我会省略其他的):

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

0 个答案:

没有答案