0

I have 8 tabs. As all the tabs should display the custom list, i am trying to add the same Fragment instance. I am downloading the list using EventBus in OnEventBackGroundThread and adding it to adapter in OnEventMainThread.
I can see the PageSlidingTabStrip downloads the data for the selected tab and also the data of other two tabs(next to the selected tab). Tab titles are accurate. I am able to download the data for each tab. Now the problem is the tabs are displaying wrong views. Sometimes, the data of next tab and sometimes the data of previous selected tab. I went through this solution but didn't work for me. PagerSlidingTabStrip: How refresh inner fragment Listview in current tab at run time and stop the loading data for next tab.

  1. What should be done to display the correct view?

  2. Can we save each fragments in destroy method and reuse it?

  3. If I implement the downloading task using AsyncTask(instead of EventBus), tabs are working as expected. Am i missing anything in EventBus as i am new to all these concepts. I am new to android.

I am trying to create my app similar to youtube app. Each item in navigation drawer will have new fragment with tabs and list of items in each tab.

Here is my code.

TabsFragmentPageAdapter

public class TabsFragmentPagerAdapter extends FragmentStatePagerAdapter {
    private ArrayList<String> tabTitles = new ArrayList<String>(); //  Contains name of the tab
    private ArrayList<Integer> subCategoryIdList = new ArrayList<Integer>(); // Contains its id
    private ArrayList<CategoryModel> categoryModelArrayList = new ArrayList<CategoryModel>();
    private int categoryId;

    public TabsFragmentPagerAdapter(FragmentManager fm, int cid) {
        super(fm);
        this.categoryId = cid;
        categoryModelArrayList = TabsFragment.subCategoriesHashMap.get(cid); // Gets prepopulated data from other class.
        for(CategoryModel c: categoryModelArrayList) {
            tabTitles.add(c.getName()); 
            subCategoryIdList.add(c.getCategoryId()); 
        }
    }

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

    @Override
    public Fragment getItem(int position) {
        return AllCategoriesFragment.getInstance(subCategoryIdList.get(position)); 
// Using same Fragment. Position is used as a parameter(Using Id's instead of position which is populated in Constructor)
    }

    @Override
    public CharSequence getPageTitle(int position) {
        // Generate title based on item position
        return tabTitles.get(position);
    }

    @Override
    public void destroyItem(ViewGroup container,int position, Object object ) {
        Log.d("Destroy","Destroying tab# "+position);
        FragmentManager manager = ((Fragment) object).getFragmentManager();
        FragmentTransaction trans = manager.beginTransaction();
        trans.remove((Fragment) object);
        trans.commit();

        super.destroyItem(container, position, object);
        container.removeView(container.getRootView());
    }
}

AllCategoriesFragment.java

package com.android.thetake;

// import statements

public class AllCategoriesFragment extends Fragment implements AbsListView.OnItemClickListener, AbsListView.OnScrollListener {

    private View view;

    private OnFragmentInteractionListener mListener;

    /**
     * The fragment's ListView/GridView.
     */
    private AbsListView mListView;

    /**
     * The Adapter which will be used to populate the ListView/GridView with
     * Views.
     */
    private ListAdapter mAdapter;

    private CustomListAdapter customListAdapter;

    MessageListEvent msgEvent = new MessageListEvent();

    private static int categoryId=0;

    private static int startIndex=1;

    private Activity mActivity;

    static List<Item> newItemList= new LinkedList<Item>();

    static AllCategoriesFragment allCategoriesFragment;

    static EventBus eventBus;

    public static final String CATEGORY_ID = "CATEGORY_ID";


    /**
     * Mandatory empty constructor for the fragment manager to instantiate the
     * fragment (e.g. upon screen orientation changes).
     */
    public AllCategoriesFragment() {
        startIndex = 1;
        newItemList.clear();
    }


    public static AllCategoriesFragment getInstance(int categoryId) {
         Bundle args = new Bundle();
        args.putInt(CATEGORY_ID,categoryId); 
        allCategoriesFragment = new AllCategoriesFragment();
        allCategoriesFragment.msgEvent.itemList.clear();
        allCategoriesFragment.newItemList.clear();
        startIndex=1;
        allCategoriesFragment.setArguments(args);
        return allCategoriesFragment;
    }

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

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        customListAdapter = null;
        view = inflater.inflate(R.layout.fragment_item, container, false);
        allCategoriesFragment.categoryId = getArguments().getInt(CATEGORY_ID);
        eventBus = EventBus.getDefault();
        if (!eventBus.isRegistered(this))
            eventBus.register(this);   //Register this class to eventBus

        eventBus.post(new StartDownloadEvent()); // publish event

        return view;
    }

    public void onEventBackgroundThread(StartDownloadEvent event) {
        //Downloading the images in background thread
        HttpClient httpClient = new DefaultHttpClient();
        HttpContext localContext = new BasicHttpContext();
        String url = "https://company.com/listProducts?categoryId="+allCategoriesFragment.categoryId+"&start="+AllCategoriesFragment.startIndex+"&limit=20";

        HttpGet httpGet = new HttpGet(url);
        String results = null;

        boolean flag = msgEvent.itemList.size()==0;

        try {
            HttpResponse response = httpClient.execute(httpGet, localContext);
            HttpEntity entity = response.getEntity();
            results = msgEvent.getASCIIContentFromEntity(entity);
            if (results != null) {
                JSONArray jsonArray = new JSONArray(results);
                for (int i = 0; i < jsonArray.length(); i++) {

                        JSONObject obj = jsonArray.getJSONObject(i);
                        String product_id = obj.getString("product_id");
                        String actorImageLink = obj.getString("500pxCropLink");
                        String actorName=new String();
                        try {
                            actorName = obj.getString("actorName");
                        } catch (JSONException e) {
                            Log.d("Exception",e.getLocalizedMessage());
                        }
                        String largePicLink = obj.getString("500pxCropLink");
                        String smallPicLink = obj.getString("125pxLink");
                        String movieName = obj.getString("movieName");
                        String itemName = obj.getString("name");
                        String brand = obj.getString("brand");
                        String price = obj.getString("price");
                        boolean isMatchVerified = obj.getBoolean("verified");
                        Item item = new Item(product_id, actorImageLink, largePicLink, smallPicLink, movieName, itemName, brand, actorName, price, isMatchVerified);
                        if(flag) {
                        msgEvent.itemList.add(item);
                        } else
                            newItemList.add(item);

                }
            }
        } catch(IOException e) {
             Log.d("Exception",e.getLocalizedMessage());
        }
        catch (JSONException e) {
            Log.d("Exception",e.getLocalizedMessage());
        }
        if(!flag) {
            FragmentActivity f = getActivity();
                f.runOnUiThread(new Runnable() {

                    @Override
                    public void run() {
                        customListAdapter.addAll(newItemList);
                        customListAdapter.notifyDataSetChanged();
                    }
                });
        }
        EventBus.getDefault().post(msgEvent);
    }

    public void onEventMainThread(MessageListEvent event) {
        //Create Adapter
        //Set Adapter to List View
        customListAdapter = new CustomListAdapter(getActivity(),event.itemList);
        mListView = (ListView) view.findViewById(android.R.id.list);
        mListView.setAdapter(customListAdapter);
        mListView.setOnItemClickListener(this);
        // This loads the next images when scrolled all the way down to bottom.
        // Overrides onScroll and onScrollStateChanged function
        mListView.setOnScrollListener(this);
    }

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem,
                         int visibleItemCount, int totalItemCount) {
        int loaded = firstVisibleItem+visibleItemCount;
        if(loaded>=totalItemCount && startIndex+19==loaded) {
            startIndex = loaded+1;
            newItemList.clear();
            Log.d("Scroll","Next Start Index "+startIndex);
            eventBus.post(new StartDownloadEvent());
        }
    }

    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        mActivity = activity;
        try {
            mListener = (OnFragmentInteractionListener) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString()
                    + " must implement OnFragmentInteractionListener");
        }


    }

    @Override
    public void onDetach() {
        super.onDetach();
        EventBus.getDefault().unregister(this);
        mListener = null;
    }


    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        if (null != mListener) {
            // Notify the active callbacks interface (the activity, if the
            // fragment is attached to one) that an item has been selected.
            mListener.onFragmentInteraction(msgEvent.itemList.get(position).movieName);
        }

    }

    /**
     * The default content for this Fragment has a TextView that is shown when
     * the list is empty. If you would like to change the text, call this method
     * to supply the text it should use.
     */
    public void setEmptyText(CharSequence emptyText) {
        View emptyView = mListView.getEmptyView();

        if (emptyText instanceof TextView) {
            ((TextView) emptyView).setText(emptyText);
        }
    }

    /**
     * This interface must be implemented by activities that contain this
     * fragment to allow an interaction in this fragment to be communicated
     * to the activity and potentially other fragments contained in that
     * activity.
     * <p/>
     * See the Android Training lesson <a href=
     * "http://developer.android.com/training/basics/fragments/communicating.html"
     * >Communicating with Other Fragments</a> for more information.
     */
    public interface OnFragmentInteractionListener {
        // TODO: Update argument type and name
        public void onFragmentInteraction(String id);
    }

    public static class StartDownloadEvent {

    }

    public class MessageListEvent {
        public List<Item> itemList = new ArrayList<Item>();
        protected String getASCIIContentFromEntity(HttpEntity entity) throws IllegalStateException, IOException {
            ...
            return out.toString();
        }
    }
}
Community
  • 1
  • 1

2 Answers2

0

After observing the behavior of the tabs this should work for you.

@Override 
public Fragment getItem(int position) {
    if(position==0){
         return AllCategoriesFragment.getInstance(subCategoryIdList.get(position)); 
    }else{
        int index=position-1;
        return AllCategoriesFragment.getInstance(subCategoryIdList.get(index)); 
    }
}
Pang
  • 9,564
  • 146
  • 81
  • 122
  • Thanks for the help Carlton. I tried with this before. It works when we move to next tab by sliding. If we directly jump between tabs by clicking on tab name, it shows previous viewed tab. I tried the downloading work with Async Task instead of EventBus.OnBackgroundThread and its working fine for me. – androidbeginner Apr 23 '15 at 17:09
  • As i know, PageSlidingTabStrip downloads the data for 3 tabs including selected one. If i use AsyncTask to download data, it will attach the downloaded data to the right tabs. But if i use Event Bus backgroundThread to download data, it fails to attach to the right tabs. – androidbeginner Apr 23 '15 at 17:15
0

The PageSlidingTabStrip is evidently buggy to avoid complications I would recommend Android PagerSlidingTabStrip (default Material Design)

The implementation is very similar. This will however also give you better customization options