Sergi0
Sergi0

Reputation: 1096

PullToRefresh list in paged fragment

I want to create PullToRefresh list fragment with pager. I'm using ActionBarSherlock, and this implementation of the list. I had no problems without fragment, but I need to support two-pane layout.

layout files

activity
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin" >

    <android.support.v4.view.ViewPager
        android:id="@+id/pager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".SubcatNavActivity" />

</LinearLayout>

fragment
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ListView
        android:id="@+id/subcat_list"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" >
    </ListView>
</LinearLayout>

Activity is pretty simple

public class SubcatNavActivity extends SherlockFragmentActivity
{
    private SubcatNavPager mPager;


    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);

        setContentView(R.layout.activity_subcat_nav);

        mPager = new SubcatNavPager(this);
        mPager.initialisePaging();

        setProgressBarIndeterminateVisibility(true);
    }
}

I have created pager class to also use it later in main activity for two-pane mode.

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.view.ViewPager;

import com.actionbarsherlock.app.ActionBar;
import com.actionbarsherlock.app.ActionBar.Tab;
import com.actionbarsherlock.app.SherlockFragmentActivity;


public class SubcatNavPager implements ActionBar.TabListener
{   
    public SectionsPagerAdapter mSectionsPagerAdapter;
    public ViewPager mViewPager;
    private SherlockFragmentActivity mFragmentActivity;

    public SubcatNavPager(SherlockFragmentActivity fa) {
        mFragmentActivity = fa;
    }

    public void initialisePaging() {
        mFragmentActivity.setTitle(mFragmentActivity.getResources().getString(SiteContent.curr_cat.nameID));

        try {
            List<Fragment> fragments = new Vector<Fragment>();
            mSectionsPagerAdapter = new SectionsPagerAdapter(mFragmentActivity.getSupportFragmentManager(), fragments);

            for (int i = 0; i < SiteContent.curr_cat.content.size(); ++i) {
                Fragment tmp = SiteContent.curr_cat.fragment.newInstance();

                if (!(tmp instanceof ContentDownloader)) {
                    throw new IllegalStateException(
                            "Fragment must implement content downloader interface.");
                }

                Bundle args = new Bundle();
                args.putInt(SubcatListFragment.SUBCAT_IDX, i);
                tmp.setArguments(args);
                fragments.add((Fragment)tmp);
            }

            mViewPager = (ViewPager)mFragmentActivity.findViewById(R.id.pager);
            mViewPager.setAdapter(mSectionsPagerAdapter);

            final ActionBar actionBar = mFragmentActivity.getSupportActionBar();
            actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

            mViewPager
                    .setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
                        @Override
                        public void onPageSelected(int position) {
                            actionBar.setSelectedNavigationItem(position);
                        }
                    });

            for (int i = 0; i < mSectionsPagerAdapter.getCount(); i++) {
                actionBar.addTab(actionBar.newTab()
                        .setText(mSectionsPagerAdapter.getPageTitle(i)).setTabListener(this));
            }

            actionBar.setDisplayHomeAsUpEnabled(true);
        }
        catch (Exception e) {}
    }

    @Override   
    public void onTabSelected(Tab tab, FragmentTransaction fragmentTransaction) {
        int pos = tab.getPosition();
        SiteContent.setCurrSubCat(pos);
        mViewPager.setCurrentItem(pos);
        ((ContentDownloader)mSectionsPagerAdapter.getItem(pos)).downloadContent(false);
    }

    @Override
    public void onTabUnselected(Tab tab, FragmentTransaction ft) {}

    @Override
    public void onTabReselected(Tab tab, FragmentTransaction ft) {}


    public class SectionsPagerAdapter extends FragmentPagerAdapter
    {
        private List<Fragment> fragments;

        public SectionsPagerAdapter(FragmentManager fm, List<Fragment> fList) {
            super(fm);
            fragments = fList;
        }

        @Override
        public Fragment getItem(int position) {
            Fragment tmp = fragments.get(position);
            return tmp;
        }

        @Override
        public int getCount() { return fragments.size(); }

        @Override
        public CharSequence getPageTitle(int position) {
            return mFragmentActivity.getResources().getString(SiteContent.curr_cat.content.get(position).nameID);
        }
    }
}

And finally, the fragment itself

import com.actionbarsherlock.app.SherlockListFragment;
import com.handmark.pulltorefresh.library.PullToRefreshBase;
import com.handmark.pulltorefresh.library.PullToRefreshBase.Mode;
import com.handmark.pulltorefresh.library.PullToRefreshListView;

public class SubcatListFragment extends SherlockListFragment implements ContentDownloader
{
    public static final String SUBCAT_IDX = "subcat_idx";
    protected ArrayAdapter<SiteItem> adapter;
    protected DownloadSubcatTask loadTask;
    protected SiteSubcat subcat;
    private PullToRefreshListView mPullToRefreshListView;
    private boolean loadRequested;

    public SubcatListFragment() {           
        adapter = null;
        loadRequested = false;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Bundle args = getArguments();           
        subcat = SiteContent.curr_cat.content.get(args.getInt(SUBCAT_IDX));
        adapter = new ArrayAdapter<SiteItem>(getActivity(), android.R.layout.simple_list_item_1, subcat.items);
        this.setListAdapter(adapter);

        if (loadRequested == true)
            downloadContent(false);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View layout = inflater.inflate(R.layout.fragment_subcat_nav, container, false);

        ListView lv = (ListView) layout.findViewById(R.id.subcat_list);
        ViewGroup parent = (ViewGroup) lv.getParent();

        int lvIndex = parent.indexOfChild(lv);
        parent.removeViewAt(lvIndex);
        mPullToRefreshListView = new PullToRefreshListView(layout.getContext());
        mPullToRefreshListView.setMode(Mode.BOTH);
        mPullToRefreshListView.setOnRefreshListener(new PullToRefreshBase.OnRefreshListener<ListView>()
                                {
                                    @Override
                                    public void onRefresh(PullToRefreshBase<ListView> refreshView) {
                                        downloadContent(true);
                                    }
                                });

        parent.addView(mPullToRefreshListView, lvIndex, lv.getLayoutParams());        
        return layout;
    }

    @Override
    public void onListItemClick(ListView l, View v, int position, long id) {
        Intent subcatIntent = new Intent(getActivity(), NewsActivity.class);
        SiteContent.setCurrItem((int)id);
        startActivity(subcatIntent);
    }

    @Override
    public void downloadContent(boolean bRefresh) {
        // on first call to onTabSelected this fragment is not created, yet
        if (subcat == null)
            loadRequested = true;
        else
        {
            loadRequested = false;
            if (loadTask == null && (adapter.isEmpty() == true || bRefresh == true))
                (loadTask = new DownloadSubcatTask()).execute(subcat.getUrl());
        }
    }   

    protected void showProgress(boolean bShow) {
        getActivity().setProgressBarIndeterminateVisibility(bShow);
    }

    private class DownloadSubcatTask extends DownloadTask {
        public DownloadSubcatTask() {}      

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            showProgress(true);
        }

        @Override
        protected void onPostExecute(String result) {
            super.onPostExecute(result);
            adapter.clear();
            loadTask = null;

            try {
                SiteContent.curr_cat.parser.newInstance().parse(result, adapter);
            }
            catch (Exception e) {}

            mPullToRefreshListView.onRefreshComplete();
            adapter.notifyDataSetChanged();
            showProgress(false);
        }
    }
}

As you can see, everything consists of stuff from examples. But the problem is that list is not shown when I start the app. I can see the tabs, the loading indicator is gone (and I know adapter has data) but list area is clear white. And I can't pull the list to refresh it. But if i try to swap pages, suddenly data appears in previous page (actually not previous, but the one before). It seems it has something to do with adapter loading first two fragments, but I can figure out what's wrong.

How to make lists appears when they are loaded? And more general question, is this the right architecture to go on?

EDIT:
if I remove all pull-to-refresh code like this public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View layout = inflater.inflate(R.layout.fragment_subcat_nav, container, false); return layout; }

and set default list id in the fragment layout android:id="@android:id/list" list view is displayed as it should. can't figure out why pull-to-refresh causes problems.

Upvotes: 0

Views: 3280

Answers (1)

Sergi0
Sergi0

Reputation: 1096

this is how i fixed the problem (list fragment need to return a list view)

@Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View layout = inflater.inflate(R.layout.fragment_subcat_nav, container, false);
        ListView lv = (ListView) layout.findViewById(android.R.id.list);

        mPullToRefreshListView = new PullToRefreshListView(getActivity());
        mPullToRefreshListView.setLayoutParams(lv.getLayoutParams());

        mPullToRefreshListView.setOnRefreshListener(new PullToRefreshBase.OnRefreshListener<ListView>()
                                {
                                    @Override
                                    public void onRefresh(PullToRefreshBase<ListView> refreshView) {
                                        downloadContent(true);
                                    }
                                });

        return mPullToRefreshListView;
    }

Upvotes: 2

Related Questions