I'm trying to add tabs to my TabLayout-ViewPager-Fragment based application dynamically.The TabLayout uses a custom view with an ImageView on top of a TextView.
What I want now is to add tabs according to the number of JSONObjects in my JSONArray created from a PHP/MySQL web service. I tried the method below in my PagerAdapter but it throws:
java.lang.IllegalStateException: Can't change tag of fragment TstFrag{df80bc8 #0 id=0x7f080157 android:switcher:2131231063:0}: was android:switcher:2131231063:0 now android:switcher:2131231063:1.
The method is as in my Adapter below
public class FrgAdapter extends FragmentStatePagerAdapter {
private List<Fragment> mFragmentList = new ArrayList<>();
private List<String> mFragmentTitleList = new ArrayList<>();
public FrgAdapter(FragmentManager fm) {
super(fm);
}
public FrgAdapter(FragmentManager fm, List<Fragment> mFragmentList, List<String> mFragmentTitleList) {
super(fm);
this.mFragmentList = mFragmentList;
this.mFragmentTitleList = mFragmentTitleList;
}
#Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
#Override
public int getCount() {
return mFragmentList.size();
}
public void addFragment(Fragment fragment, String title) {
mFragmentList.add(fragment);
mFragmentTitleList.add(title);
}
public void insertFromJSONObject(JSONObject jsonObject, Fragment fragment, CircularImageView imageView, TextView textView) throws JSONException {
JSONArray dataArray = jsonObject.getJSONArray("data");
for (int i = 0; i < dataArray.length(); i++) {
JSONObject sectionObj = (JSONObject) dataArray.get(i);
JSONArray sectionsArray = sectionObj.getJSONArray("section");
for (int j = 0; j < sectionsArray.length(); j++) {
JSONObject obj = (JSONObject) sectionsArray.get(j);
Picasso.get().load(obj.getString("imag")).into(imageView);
mFragmentList.add(fragment);
mFragmentTitleList.add(obj.getString("name"));
textView.setText(obj.getString("name"));
notifyDataSetChanged();
}
}
}
#Override
public CharSequence getPageTitle(int position) {
return null;
}}
Here is where the method is called in my activity to add the fragments:
private void setUpViewPager(ViewPager viewPager, View view) {
adapter = new FrgAdapter(getSupportFragmentManager());
/*adapter.addFragment(new MleFrag(), "Men");
adapter.addFragment(new FmlFrag(), "Women");
adapter.addFragment(new ChdFrag(), "Children");
adapter.addFragment(new AceFrag(), "Accessories");
*/
String url = "https://44091ee6.ngrok.io/Glam/men.json";
AndroidNetworking.get(url)
.setPriority(Priority.MEDIUM)
.build()
.getAsJSONObject(new JSONObjectRequestListener() {
#Override
public void onResponse(JSONObject response) {
try {
adapter.insertFromJSONObject(response, new TstFrag(), view.findViewById(R.id.circularImageView), view.findViewById(R.id.text_header));
adapter.notifyDataSetChanged();
} catch (JSONException e) {
e.printStackTrace();
}
}
#Override
public void onError(ANError anError) {
Toast.makeText(getApplicationContext(), anError.toString(), Toast.LENGTH_LONG).show();
}
});
adapter.notifyDataSetChanged();
viewPager.setAdapter(adapter);
}
and here is my Fragment. In my mind I want to reuse this one Fragment for each of the times I will be requiring one.
public class TstFrag extends Fragment {
public TstFrag() {
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.layout_cht, container, false);
}}
You may try this:
adapter.insertFromJSONObject(response, view.findViewById(R.id.circularImageView), view.findViewById(R.id.text_header));
adapter.notifyDataSetChanged();
and
public void insertFromJSONObject(JSONObject jsonObject, CircularImageView imageView, TextView textView) throws JSONException {
JSONArray dataArray = jsonObject.getJSONArray("data");
for (int i = 0; i < dataArray.length(); i++) {
JSONObject sectionObj = (JSONObject) dataArray.get(i);
JSONArray sectionsArray = sectionObj.getJSONArray("section");
for (int j = 0; j < sectionsArray.length(); j++) {
JSONObject obj = (JSONObject) sectionsArray.get(j);
Picasso.get().load(obj.getString("imag")).into(imageView);
mFragmentList.add(new TstFrag());
textView.setText(obj.getString("name"));
//mFragmentTitleList.add(obj.getString("name"));
notifyDataSetChanged();
}
}
}
The basic idea here is to create a new instance of TstFrag for each entry of the FrgAdapter.
Consider NOT to add fragments to viewPager manually but just implement getItem && instantiateItem methods on viewPager adapter. Then viewPager will control the instantiation of new TstFrag or just reuse created one. Check this answer for complete adapter.
#Override
public Fragment getItem(final int pos) {
return TstFrag.getInstance(dataList.get(pos));
}
#NonNull
#Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment fragment = (Fragment) super.instantiateItem(container, position);
registeredFragments.put(position, fragment);
return fragment;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
registeredFragments.remove(position);
super.destroyItem(container, position, object);
}
Update
public class DataModel implements Serializable{
private String name;
private String image;
// GETTER && SETTER
}
Replace
private List<String> mFragmentTitleList = new ArrayList<>();
With
private List<DataModel> dataList = new ArrayList<>();
insertFromJSONObject
dataList.clear();
for (int j = 0; j < sectionsArray.length(); j++) {
JSONObject obj = (JSONObject) sectionsArray.get(j);
final DataModel model = new DataModel();
model.setName(obj.getString("name"));
model.setImage(obj.getString("imag"));
// Picasso.get().load(obj.getString("imag")).into(imageView);
// No need to load image here just fetch for cache if you want.
Picasso.get().load(model.getImage()).fetch();
// mFragmentList.add(fragment); // no need handle adding fragment here as mentioned above.
dataList.add(dataModel);
// textView.setText(obj.getString("name")); // It's not good to update UI here but update there with fragment on create called mention below.
// notifyDataSetChanged(); DON'T call this inside the loop but after finish your stuff.
}
// Just notify here...
notifyDataSetChanged();
TstFrag
public class TstFrag extends Fragment {
private DataModel model;
public TstFrag() {
}
public static TstFrag getInstance(DataModel model){
TstFrag fragment = new TstFrag();
Bundle bundle = new Bundle();
bundle.putSerializable("mData", model);
fragment.setArguments(bundle);
return fragment;
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
model = (DataModel)getArguments().getSerializable("mData");
}
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
final View rootView = inflater.inflate(R.layout.layout_cht, container, false);
// findViewById() for imageView and nameTextView
Picasso.get().load(model.getImage()).into(imageView);
nameTextView.setText(model.getName());
}}
Related
I have an Activity with 2 fragments.
Declared a ParentTabFragment in my Activity in which there is a TabLayout and a ViewPager.
There's a method in my ParentTabFragment called addPage which gets called in the Activity.
The addPage has another method called addFrag which is called from a ViewPagerAdapter creating the views in the ChildTabFragment dynamically.
There is a for loop which runs in the Activity, so the Fragments are created according to the number of items in the customList, creating the amount of tabs and pages in the Fragments.
In my ChildTabFragment I load a customList on tab selection event,
when I select a Tab in the ParentTabFragment, I call a getTabID() method from the ChildTabFragment and send the id of the Tab due to which I load the customList according to the id in the ParentTabFragment.
Problem is when I swipe or select tabs, duplicate/false data gets created in the customList.
I get the proper Id of the selected tab but when I try to pass it in the method, random id is called.
In my Activity Class:
for (int j =0;j<it.size();j++){
parentTabFragment.addPage(it.get(j).getTabMenuItem(), it.get(j).getTabMenuId() , selectedMenu);
}
ParentTabFragment:
public void addPage(String pagename, String pageId, String selectedMenu) {
Bundle bundle = new Bundle();
bundle.putString("data", pagename);
//bundle.putString("pageID", pageId);
childTabFragment = new ChildTabFragment();
childTabFragment.setArguments(bundle);
adapter.addFrag(childTabFragment, pagename, pageId);
adapter.notifyDataSetChanged();
if (selectedMenu == null) {
viewPager.setCurrentItem(0);
} else {
for (int i = 0; i < tabLayout.getTabCount(); i++) {
if (tabLayout.getTabAt(i).getText().equals(selectedMenu)) {
viewPager.setCurrentItem(i);
}
}
}
if (adapter.getCount() > 0) tabLayout.setupWithViewPager(viewPager);
setupTabLayout();
}
public void setupTabLayout() {
selectedTabPosition = viewPager.getCurrentItem();
for (int i = 0; i < tabLayout.getTabCount(); i++) {
tabLayout.getTabAt(i).setCustomView(adapter.getTabView(i));
}
}
ChildTabFragment:
public class ChildTabFragment extends Fragment {
String childname;
int menuItemId;
TextView textViewChildName, txtViewItemId;
ListView childTabMenuList;
private ArrayList<ChildTabMenu_POJO> childTabMenuPojoList = new ArrayList<>();
private ListView listView;
private ChildTabMenuAdapter childTabMenuAdapter;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.child_tab_fragment, container, false);
Bundle bundle = getArguments();
childname = bundle.getString("data");
getIDs(view);
return view;
}
private void getIDs(View view) {
childTabMenuList = (ListView) view.findViewById(R.id.childTabMenuList);
loadChildMenu();
}
private void loadChildMenu(menuItemId) {
ChildTabMenu_POJO menu_pojo4 = new ChildTabMenu_POJO(String.valueOf(menuItemId), "4");
childTabMenuPojoList.add(menu_pojo4);
childTabMenuAdapter = new ChildTabMenuAdapter(childTabMenuPojoList, getActivity());
childTabMenuList.setAdapter(childTabMenuAdapter);
}
public void getTabID(int tabId) {
menuItemId = tabId;
Log.e("updatefrag", String.valueOf(menuItemId));
}
}
ViewPagerAdapter:
public class ViewPagerAdapter extends FragmentStatePagerAdapter {
private final ArrayList<Fragment> mFragmentList = new ArrayList<>();
private final ArrayList<Adapter_POJO> mFragmentTitleList = new ArrayList<>();
Context context;
ViewPager viewPager;
TabLayout tabLayout;
Adapter_POJO adapter_pojo;
public ViewPagerAdapter(FragmentManager manager, Context context, ViewPager viewPager,
TabLayout tabLayout) {
super(manager);
this.context = context;
this.viewPager = viewPager;
this.tabLayout = tabLayout;
}
#Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
#Override
public int getCount() {
return mFragmentList.size();
}
public int getItemCount() {
return mFragmentTitleList.size();
}
public void addFrag(Fragment fragment, String title, String pageId) {
mFragmentList.add(fragment);
adapter_pojo = new Adapter_POJO(title,pageId);
mFragmentTitleList.add(adapter_pojo);
}
public View getTabView(final int position) {
View view = LayoutInflater.from(context).inflate(R.layout.view_pager_adapter_layout, null);
TextView tabItemName = (TextView) view.findViewById(R.id.textViewTabItemName);
tabItemName.setText(mFragmentTitleList.get(position).adapterMenuItem);
tabItemName.setTextColor(context.getResources().getColor(android.R.color.background_light));
return view;
}
#Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
#Override
public CharSequence getPageTitle(int position) {
return mFragmentTitleList.get(position).adapterMenuItem;
}
public String getPageId(int position){
return mFragmentTitleList.get(position).adapterMenuId;
}
}
If i understand your question so you need to create newInstance constructor for creating fragment with arguments
public static ChildTabFragment newInstance(int page, String title) {
FirstFragment fragmentFirst = new FirstFragment();
Bundle args = new Bundle();
args.putInt("someInt", page);
args.putString("someTitle", title);
fragmentFirst.setArguments(args);
return fragmentFirst;
}
And Store instance variables based on arguments passed in your ChildTabFragment .
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
page = getArguments().getInt("someInt", 0);
title = getArguments().getString("someTitle");
}
And now update the view in your onCreateView method
TextView tvLabel = (TextView) view.findViewById(R.id.tvLabel);
tvLabel.setText(page + " -- " + title);
And the main thing you should returns the ChildTabFragment to display for that page from your ViewPagerAdapter like this.
#Override
public Fragment getItem(int position) {
return ChildTabFragment.newInstance(position,"page "+String.valueOf(position));
}
How many tabs will be created it depends on web service. It means I cannot discover how many Tabs are going to be Created until web service is called.
The tabs contain the products which I want to show in grid view.
In my project I have ShopProductsPageFragments.java where tabs get created. Please have look below code :
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
CatPosition = getArguments().getInt("CatPosition");
StoreID = getArguments().getString("StoreID");
System.out.println("getStoreID in ShopProductsPageFragments="+ StoreID);
System.out.println("getCatPosition in ShopProductsPageFragments="+ CatPosition);
try {
ShopCategoryData = (GetProductCategoriesByStoreResponsePojo) getArguments().getSerializable("ShopCatNames");
}catch (Exception e){
e.printStackTrace();
}
assert ShopCategoryData != null;
List<Datum> shopcatdata = ShopCategoryData.getData();
for (int i = 0; i < shopcatdata.size(); i++) {
System.out.println("ShopCategoryData in ShopProductsPageFragments "+ shopcatdata.get(i).getCatName());
}
ShopProductsPageView = inflater.inflate(R.layout.activity_product_page_fragment ,container ,false);
viewPager = (ViewPager)ShopProductsPageView.findViewById(R.id.product_viewpager);
setupViewPager(viewPager);
tabLayout = (TabLayout)ShopProductsPageView.findViewById(R.id.product_tabs);
tabLayout.setupWithViewPager(viewPager);
return ShopProductsPageView;
}
private void setupViewPager(ViewPager viewPager) {
ViewPagerAdapter adapter = new ViewPagerAdapter(getFragmentManager());
List<Datum> shopcatdata = ShopCategoryData.getData();
for (int i = 0; i < shopcatdata.size(); i++) {
CommanShopProductFragment commanShopProductFragment = CommanShopProductFragment.newInstance(i);
String CatName = shopcatdata.get(i).getCatName();
Bundle bundle = new Bundle();
bundle.putString("StoreID",StoreID);
bundle.putString("CatName",CatName);
commanShopProductFragment.setArguments(bundle);
System.out.println("ShopCategoryData in ShopProductsPageFragments "+ shopcatdata.get(i).getCatName());
adapter.addFrag(commanShopProductFragment, shopcatdata.get(i).getCatName());
}
adapter.notifyDataSetChanged();
viewPager.setAdapter(adapter);
viewPager.setCurrentItem(CatPosition);
}
class ViewPagerAdapter extends FragmentPagerAdapter {
private final List<Fragment> mFragmentList = new ArrayList<>();
private final List<String> mFragmentTitleList = new ArrayList<>();
FragmentManager fragmentManager;
public ViewPagerAdapter(FragmentManager manager) {
super(manager);
fragmentManager = manager;
}
#Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
#Override
public int getCount() {
return mFragmentList.size();
}
void addFrag(Fragment fragment, String title) {
mFragmentList.add(fragment);
mFragmentTitleList.add(title);
}
#Override
public CharSequence getPageTitle(int position) {
return mFragmentTitleList.get(position);
}
}
Here, you can see how tabs are created. I am using same fragment for showing data in Tabs as follows:
public class CommanShopProductFragment extends Fragment {
private static final String ARG_POSITION = "position";
private int position;
View CategoryTabFragmentView;
GetStoreProductsByCategoriesPresenterImpl presenter;
RestClient service;
GridView gridView;
List<Datum> shopProduct;
ProductByCategoryGridViewAdapter mAdapter;
public CommanShopProductFragment() {
// Required empty public constructor
}
public static CommanShopProductFragment newInstance(int position) {
CommanShopProductFragment f = new CommanShopProductFragment();
Bundle b = new Bundle();
b.putInt(ARG_POSITION, position);
f.setArguments(b);
return f;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String CatName = getArguments().getString("CatName");
String StoreID = getArguments().getString("StoreID");
assert CatName != null;
System.out.println("CommanShopProductFragment >>>>>>>> CatName="+CatName);
assert StoreID != null;
System.out.println("CommanShopProductFragment >>>>>>>> StoreID="+StoreID);
CategoryTabFragmentView = inflater.inflate(R.layout.activity_category_tab_fragment ,container ,false);
service = ((LilubiApplication) getActivity().getApplication()).getNetworkService();
presenter = new GetStoreProductsByCategoriesPresenterImpl(this, service);
String page = "1", itemsPerPage = "10";
try {
presenter.GetStoreProductsByCategories(CatName, StoreID, page, itemsPerPage);
}catch (Exception e){
e.printStackTrace();
}
return CategoryTabFragmentView;
}
public void getStoreProductsByCategories(ProductByCategoriesResponsePojo productByCategoriesResponsePojo){
System.out.println("CategoryTabFragment in getMessage="+productByCategoriesResponsePojo.getMessage());
System.out.println("CategoryTabFragment in getStatus="+productByCategoriesResponsePojo.getStatus());
// prepared arraylist and passed it to the Adapter class
shopProduct = productByCategoriesResponsePojo.getData();
mAdapter = new ProductByCategoryGridViewAdapter(getActivity(),shopProduct);
// Set custom adapter to gridview
gridView = (GridView) CategoryTabFragmentView.findViewById(R.id.category_tab_view_grid_view);
gridView.setAdapter(mAdapter);
}
Now what I want is when user selects a tab then list of products should be displayed according to selected category from the tabs.
All product data also comes from web service. Let me know if I missed any thing to explain. Thank you.
I am editing my previous answer
Edit:
you can use viewpager.getCurrentItem() to get current position //include this in your activity with viewpager
Hi I have Tablayout with Viewpager and i am using Fragment for tablayout. Now in every Tablayout fragments I have Recyclerview and displaying items.Please See this my json response
http://pastebin.com/nUswad9s
here in "typeMaster": array i have categories "typeName": "Dogs", and i am displaying typenames in tablayout i have 4 tablayout, and inside typemaster i have subcategoreis named "catMaster": and i am trying to display catmaster data in recyclerview,but the issue is in every fragment it shows last data "catName": "Vitamins & Minerals",
Activity
public class CategoriesActivity extends AppCompatActivity{
private Header myview;
private ArrayList<SubcategoryModel> subct;
private ArrayList<CategoryModel> filelist;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.categoris_activity);
filelist = (ArrayList<CategoryModel>)getIntent().getSerializableExtra("categorylist");
System.out.println("Category list size"+filelist.size());
myview = (Header) findViewById(R.id.categorisactivity_headerView);
myview.setActivity(this);
TabLayout tabLayout = (TabLayout) findViewById(R.id.cat_tab_layout);
for(int i = 0; i < filelist.size(); i++){
subct=filelist.get(i).getItems();
for(int j=0;j<subct.size();j++)
{
}
System.out.println("SubCategory list size"+subct.size());
}
for(int i = 0; i < filelist.size(); i++){
tabLayout.addTab(tabLayout.newTab().setText(filelist.get(i).getCategory_typename()));
ArrayList<SubcategoryModel> subct=filelist.get(i).getItems();
for(int j=0;j<subct.size();j++)
{
}
}
Bundle bundleObject = new Bundle();
bundleObject.putSerializable("key", filelist);
FirstFragment ff=new FirstFragment();
ff.setArguments(bundleObject);
tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
final ViewPager viewPager = (ViewPager) findViewById(R.id.categories_pager);
CategoriesAdapter mPagerAdapter = new CategoriesAdapter(getSupportFragmentManager(),tabLayout.getTabCount());
viewPager.setAdapter(mPagerAdapter);
viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
#Override
public void onTabSelected(TabLayout.Tab tab) {
viewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(TabLayout.Tab tab) {
}
#Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
}
public class CategoriesAdapter extends FragmentStatePagerAdapter {
ArrayList<CategoryModel> catlist;
int numoftabs;
public CategoriesAdapter(FragmentManager fm, int numoftabs) {
super(fm);
this.numoftabs = numoftabs;
}
#Override
public Fragment getItem(int position) {
Log.v("adapter", "getitem" + String.valueOf(position)+subct.size());
return FirstFragment.create(position,subct);
}
#Override
public int getCount() {
return numoftabs;
}
}
}
Fragment
public class FirstFragment extends Fragment {
// Store instance variables
public static final String ARG_PAGE = "page";
private int mPageNumber;
private Context mContext;
private int Cimage;
private ArrayList<SubcategoryModel> subcatlist;
private RecyclerView rcylervw;
private ArrayList<CategoryModel> filelist;
ArrayList<SubcategoryModel> subct;
public static FirstFragment create(int pageNumber,ArrayList<SubcategoryModel> subct){
FirstFragment fragment = new FirstFragment();
Bundle args = new Bundle();
args.putInt(ARG_PAGE, pageNumber);
args.putSerializable("key", subct);
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mPageNumber = getArguments().getInt(ARG_PAGE);
subct= (ArrayList<SubcategoryModel>) getArguments().getSerializable("key");
System.out.println("Frag Category list size"+subct.size());
/* for(int i = 0; i < filelist.size(); i++){
subct=filelist.get(i).getItems();
for(int j=0;j<subct.size();j++)
{
}
System.out.println("Frag SubCategory list size"+subct.size());
}*/
// image uri get uri of image that saved in directory of app
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
ViewGroup rootView = (ViewGroup) inflater
.inflate(R.layout.test, container, false);
rcylervw=(RecyclerView)rootView.findViewById(R.id.subcategory_recycler_view);
rcylervw.setHasFixedSize(true);
MyAdapter adapter = new MyAdapter(subct);
rcylervw.setAdapter(adapter);
LinearLayoutManager llm = new LinearLayoutManager(getActivity());
rcylervw.setLayoutManager(llm);
return rootView;
}
// this method is not very important
}
MyAdapter
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
private ArrayList<SubcategoryModel> mDataset;
public static class MyViewHolder extends RecyclerView.ViewHolder {
public TextView mTextView;
public MyViewHolder(View v) {
super(v);
mTextView = (TextView) v.findViewById(R.id.subcategory_text);
}
}
// Provide a suitable constructor (depends on the kind of dataset)
public MyAdapter(ArrayList<SubcategoryModel> myDataset) {
mDataset = myDataset;
}
// Create new views (invoked by the layout manager)
#Override
public MyAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent,
int viewType) {
// create a new view
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.list_item_subcategory, parent, false);
// set the view's size, margins, paddings and layout parameters
MyViewHolder vh = new MyViewHolder(v);
return vh;
}
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
holder.mTextView.setText(mDataset.get(position).getSubCategory_name());
}
#Override
public int getItemCount() {
return mDataset.size();
}
}
Output i am getting right now
As you can see it shows same result "Vitamin & Minerals" in every tabs..i want different subcategories instead of same.
I see a lot of problems with your code, but let's get your UI displaying the subcategories since that's your main concern.
Change the getItem in your adapter to this:
#Override
public Fragment getItem(int position) {
ArrayList<SubcategoryModel> subcategories = filelist.get(position).getItems();
Log.v("adapter", "getitem" + String.valueOf(position)+subcategories.size());
return FirstFragment.create(position,subcategories);
}
What caused the problem:
Let's focus on ArrayList<SubcategoryModel> subct in your activity:
First your code did this:
for(int i = 0; i < filelist.size(); i++){
ArrayList<SubcategoryModel> subct=filelist.get(i).getItems();
// for(int j=0;j<subct.size();j++) ...
}
So at the end of this loop subct is set the subcategories of the last category in filelist.
After that, you did another loop to load the tabs, but that used a different subct variable that was declared inside the loop, and that had no effect on the subct field of your activity.
Then you created your view pager and adapter.
In your pager adapter you had this:
#Override
public Fragment getItem(int position) {
Log.v("adapter", "getitem" + String.valueOf(position)+subct.size());
return FirstFragment.create(position,subct);
}
Since subct was set to the last category's subcategories from the loop before, every single fragment created was receiving those subcategories, no matter what position (category) the fragment was for. All I did was change the code to go back to filelist and get the correct category (and subcategories) for the position of the fragment being created.
When you're writing code, you think about what you want the code to do. However, at the point where you run the code and discover you have a problem, you have to forget what you wanted the code to do, then pretend you're the computer and run the code in your head. You want to understand what effect every line of code is having. When you do it that way it's easier to find the problem.
Problem:
There's no way to pass a Serializable ArrayList in a Bundle. Look at the docs page here Bundle docs
Solution:
Change your SubCategoryModel to implement Parcelable and then use bundle.putParcelableArrayList(key, list) and bundle.getParcelableArrayList(key) to pass the ArrayList to the FragmentArgs and get them from the Fragment
this is the main logic of your code I guess... Try it and let me know if you need more help or you find it helpful...
private void parseJsonData() {
try {
listDogs.clear();
JSONArray jsonArray = new JSONArray(loadJSONFromAsset());
JSONObject firstJsonobject = jsonArray.optJSONObject(0);
JSONArray itemListJsonArray = firstJsonobject.optJSONArray("itemList");
JSONObject secondJsonobject = itemListJsonArray.optJSONObject(0);
JSONArray typeMasterArray = secondJsonobject.optJSONArray("typeMaster");
JSONObject thirdJsonobject = typeMasterArray.optJSONObject(0);
JSONArray catMasterArray = thirdJsonobject.optJSONArray("catMaster");
for(int i=0; i<catMasterArray.length(); i++) {
JSONObject jsonObject = catMasterArray.optJSONObject(i);
ModelClass modelClass = new ModelClass();
modelClass.setTypeId(jsonObject.optString("catID"));
modelClass.setTypeName(jsonObject.optString("catName"));
listDogs.add(modelClass);
}
RecyclerViewAdapter recyclerViewAdapter = new RecyclerViewAdapter(getActivity(), listDogs);
recyclerView.setAdapter(recyclerViewAdapter);
} catch (JSONException e) {
e.printStackTrace();
}
}
Note: To parse data for dogs category I've passed 0 position in variable thirdJsonobject. Pass 1 for cats and 2 for horse and you will find your desired output
Screenshots:
Dogs category
Cats category
Horse category
i have a ViewPager that has a Fragment which contains a GridView into it
my code works fine only when i'm scrolling page with delay and each time retrieve's content's from internet again
all i want to do is just get each page content's once and use it when user scroll's a page
one of my issues is that JSON downloding simultaneously when several pages has been scrolled and i don't know how to store my gridview content's for next usage that a page called
is there a standard way to conquer this issue ?
here is PagerAdapter for my ViewPager :
public class ViewPagerAdapter extends FragmentStatePagerAdapter {
String[] tabName;
public ViewPagerAdapter(FragmentManager fm, String[] tabArray) {
super(fm);
this.tabName = new String[tabArray.length];
this.tabName = tabArray;
}
#Override
public Fragment getItem(int position) {
TabPageFragment tabPageFragment = new TabPageFragment(position);
return tabPageFragment;
}
#Override
public int getCount() {
return tabName.length;
}
#Override
public CharSequence getPageTitle(int position) {
return tabName[position];
}
}
each page of ViewPager use's this class for populate Fragment :
public class TabPageFragment extends Fragment {
private GridView mgridview; // gridView inside Fragment
private int tabPosition;
private ArrayAdapterGridview arrayadapter; //adapter for my gridView
public TabPageFragment(int tabposition) {
this.tabPosition = tabposition;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
mgridview = (GridView) rootView.findViewById(R.id.gridView2);
View rootView = inflater.inflate(R.layout.fragment_grid_view, container,false);
DownloadContentTab dct = new DownloadContentTab();
dct.execute();
return rootView;
}
// DownloadJSON AsyncTask
private class DownloadContentTab extends AsyncTask<Void, Void, Integer> {
#Override
protected Integer doInBackground(Void... params) {
JSONfunctions jsf = new JSONfunctions(); //this function retrieve's json for me
JSONArray jsonarray = jsf.getJSONfromURL(myUrl); // this url is differ for each page
String[] gridNameArray = new String[jsonarray.length()];
String[] gridPicArray = new String[jsonarray.length()];
for (int j = 0; j < jsonarray.length(); j++) {
try {
JSONObject jsonobject = jsonarray.getJSONObject(j);
gridNameArray[j] = jsonobject.getString("title");
gridPicArray[j] = jsonobject.getString("pic");
} catch (JSONException e) {
e.printStackTrace();
}
}
arrayadapter = new ArrayAdapterGridview(context, gridPicArray, gridNameArray);
return 0;
}
#Override
protected void onPostExecute(Integer result) {
super.onPostExecute(result);
mgridview.setAdapter(arrayadapter);
}
}
}
i want to know if we can develop tabs using JSON.i want as many tabs depending upon the categories in JSON and each tab must contain the list view if it is possible please let me know how to do it please
MainActivity.class
private void catmethod(){
String url="http://www.souqalkhaleejia.com/webapis/menus.php";
JsonObjectRequest catreq=new JsonObjectRequest(Request.Method.GET, url, (String) null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
try {
JSONArray menuarray=response.getJSONArray("menu");
for (int i=0;i<menuarray.length();i++){
JSONObject menuobj=menuarray.getJSONObject(i);
tabs.addTab(tabs.newTab().setText(menuobj.getString("title")));
Toast.makeText(MainActivity.this, menuobj.getString("title"), Toast.LENGTH_SHORT).show();
}
TabsAdapter tabsAdapter=new TabsAdapter(getSupportFragmentManager(),menuarray.length());
viewpager.setAdapter(tabsAdapter);
tabs.setupWithViewPager(viewpager);
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.d("CatMenu", String.valueOf(error));
}
});
AppController.getInstance().addToRequestQueue(catreq);
}
Your fragment
public class OneFragment extends Fragment{
public OneFragment() {
// Required empty public constructor
}
public static Fragment getInstance(int position){
OneFragment fragment = new OneFragment();
Bundle bundle = new Bundle();
bundle.putInt("position", position)
fragment.setArgument(bundle);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_one, container, false);
int position = getArguments().getInt("position", 0);
// set your list base on position
if(position == 0){
//list 1
} else if(position == 1) {
// list 2
} else {
// list 3
}
return view;
}
}
Your ViewPagerAdapter
class ViewPagerAdapter extends FragmentPagerAdapter {
private JSONArray jsonArray;
public ViewPagerAdapter(FragmentManager manager, JSONArray jsonArray) {
super(manager);
this.jsonArray= jsonArray;
}
#Override
public Fragment getItem(int position) {
return OneFragment.getInstance(position);
}
#Override
public int getCount() {
return jsonArray.length();
}
#Override
public CharSequence getPageTitle(int position) {
return jsonArray.getJSONObject(position).getString("key");
}
}
Tablayout setup
tabLayout = (TabLayout) findViewById(R.id.tabs);
// get your json list
JSONArray jsonArray = your_json_array;
for(int i = 0; i < yourJsonArray.length(); i++){
JSONObject json = yourJsonArray.get(i);
tabLayout.addTab(tabLayout.newTab().setText(json.getString("key")));
}
viewPager = (ViewPager) findViewById(R.id.viewpager);
ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager(), yourJsonArray);
viewPager.setAdapter(adapter);
tabLayout.setupWithViewPager(viewPager);
//JSON => [{"key":"TAB1", "list":[your list]}, {"key":"TAB2", "list":[your list]}, {"key":"TAB3", "list":[your list]}]
Using JSON you can add tab dynamically like...
tabLayout = (TabLayout) findViewById(R.id.tabs);
// get your json list
JSONArray jsonArray = your_json_array;
for(int i = 0; i < yourJsonArray.length(); i++){
JSONObject json = yourJsonArray.get(i);
tabLayout.addTab(tabLayout.newTab().setText(json.getString("key")));
}
Now using ViewPager you can display your list into Fragment base on your tab position.
This link will helpful to setup TabLayout android-material-design-working-with-tabs
You can also your google Gson library to parse your JSON object.