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.
What should be done to display the correct view?
Can we save each fragments in destroy method and reuse it?
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();
}
}
}