I am designing a constitution app and I want to use a tabbed layout with swipe view. The tabs get data from the database using a custom adapter. Since the data size (no of fragment) is unknown, I want every swipe to generate a new view which are the different chapter content from the Constitution.
I want something that looks like the dictionary app below, with those swipe labels on both sides. I am familiar with tabs but I would love to get a resource to help me achieve this, since most documentation I have seen doesn't explain this. Thanks
Modify this with your desired OutPut
onCreate
ArrayList<McqQuestionBean> mcqQuestionBeans= new ArrayList<McqQuestionBean>();
adapter = new NewsFragmentPagerAdapter(getSupportFragmentManager(),
mcqQuestionBeans, MCQTestActivity.this);
pager.setAdapter(adapter);
Base Adapter
public class NewsFragmentPagerAdapter extends FragmentStatePagerAdapter {
private ArrayList<McqQuestionBean> mcqQuestionBeans;
private McqQuestionFragment fragment;
private Activity context;
public NewsFragmentPagerAdapter(FragmentManager fm, ArrayList<McqQuestionBean> mcqQuestionBeans, Activity context) {
super(fm);
this.mcqQuestionBeans = mcqQuestionBeans;
this.context = context;
}
public void update(ArrayList<McqQuestionBean> mcqQuestionBeans) {
this.mcqQuestionBeans = mcqQuestionBeans;
notifyDataSetChanged();
}
#Override
public int getCount() {
return mcqQuestionBeans.size();
}
#Override
public int getItemPosition(Object object) {
// TODO Auto-generated method stub
return super.getItemPosition(object);
}
#Override
public Fragment getItem(int position) {
fragment = McqQuestionFragment.newInstance(mcqQuestionBeans.get(position), position, context);
return fragment;
}
}
Your Fragment McqQuestionFragment
public class McqQuestionFragment extends Fragment {
private int position, porrefid;
private String question;
private ArrayList<McqQuestionChoiceBean> choices;
#SuppressWarnings("unchecked")
#Override
public void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
position = getArguments().getInt("position");
porrefid = getArguments().getInt("porrefid");
userMarkedOn = getArguments().getInt("userMarkedOn");
question = getArguments().getString("question");
choices = (ArrayList<McqQuestionChoiceBean>) getArguments()
.getSerializable("choices");
}
public static McqQuestionFragment newInstance(
McqQuestionBean mcqQuestionBean, int position, Activity activity) {
final McqQuestionFragment f = new McqQuestionFragment();
final Bundle args = new Bundle();
args.putString("question", mcqQuestionBean.getQuestion());
args.putInt("position", position);
args.putInt("userMarkedOn", mcqQuestionBean.getUserCorrectedOn());
args.putSerializable("choices", mcqQuestionBean.getChoices());
args.putInt("porrefid", mcqQuestionBean.getPorrefid());
f.setArguments(args);
return f;
}
}
Related
I receive a list (of Categories) from server and make tabs using SectionsPagerAdapter. I use one common Fragment within which I have a RecyclerView. After user logs in, I store Categories in TempData.productCategories and they are less than 15. When user selects a tab, I refresh the RecyclerView with the products of the selected Category. The issue is, currently I have 4 Categories. Only the first and the last ones have products (one product under each category). The first tab showing no product maybe because the second one is empty and Android automatically loads the second tab just after the first one. I want to see the products of the first category. Can anybody tell me what am I doing wrong?
The server gets my store ID and one store ID has less than 15 categories:
#Override
public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
mViewPager.setCurrentItem(tab.getPosition());
//doing after a delay otherwise activity is null
final int position = tab.getPosition();
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
String cat = TempData.productCategories.get(position).getName();
Log.i("Temp", "pos: " + position + ", cat: " + cat);
AnyItemFragment.updateList(cat, context);
}
}, 400);
}
Here are the other methods used in this functionality:
public static void setupListForCategory(final Activity context, final RecyclerView listView, final String category) {
List<ProductUserModel> prods = getProductsUser(category);
if(prods.isEmpty()) return;
setupList(context, listView, prods);
}
And here I update the adapter:
private static void setupList(final Activity context, RecyclerView listView, List<ProductUserModel> prods){
FastItemAdapter<ProductUserModel> p = new FastItemAdapter<>();
p.add(prods);
p.withSelectable(true);
p.withOnClickListener(new FastAdapter.OnClickListener<ProductUserModel>() {
#Override
public boolean onClick(final View v, final IAdapter<ProductUserModel> adapter, final ProductUserModel item, final int position) {
PopupUtils.getUserInputQuantity(context, item, v);
return false;
}
});
//fill the recycler view
Log.i("Temp", "updating list : " + prods.size());
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(context);
listView.setLayoutManager(layoutManager);
listView.setAdapter(p);
// p.notifyAdapterDataSetChanged();
// p.notifyDataSetChanged();
listView.invalidate();
}
private static List<ProductUserModel> getProductsUser(String category) {
List<ProductUserModel> pum = new ArrayList<>();
for(int i = 0; i < TempData.productsUser.size(); i++){
if(TempData.productsUser.get(i).getCategory().equals(category))
pum.add(TempData.productsUser.get(i));
}
return pum;
}
And the sections pager adapter in the activity:
private class SectionsPagerAdapter extends android.support.v13.app.FragmentPagerAdapter {
SectionsPagerAdapter(android.app.FragmentManager fm) {
super(fm);
}
#Override
public android.app.Fragment getItem(int position) {
return AnyItemFragment.newInstance(position-1);
}
#Override
public int getCount() {
// Show 3 total pages.
return TempData.productCategories.size();
}
#Override
public CharSequence getPageTitle(int position) {
// switch (position) {
return TempData.productCategories.get(position).getName();
// case 0:
// return getString(R.string.toys);
// case 1:
// return getString(R.string.stationaries);
// case 2:
// return getString(R.string.books);
// }
// return null;
}
#Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
}
Update: My fragment:
public class AnyItemFragment extends Fragment {
static AnyItemFragment fragment;
public static Activity context;
private static String TAG = "AllItemsFragment";
int selectedPosition = 0;
#BindView(R.id.listAll)
RecyclerView listAll;
private OnFragmentInteractionListener mListener;
public AnyItemFragment() {
// Required empty public constructor
}
public static AnyItemFragment newInstance(int categoryID) {
fragment = new AnyItemFragment();
fragment.selectedPosition = categoryID;
Log.i(TAG, "sel pos: " + fragment.selectedPosition);
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_inv_any_item, container, false);
ButterKnife.bind(this, view);
context = getActivity();
return view;
}
#Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if(!isVisibleToUser) return;
String cat = TempData.productCategories.get(fragment.selectedPosition).getName();
}
// TODO: Rename method, update argument and hook method into UI event
public void onButtonPressed(Uri uri) {
if (mListener != null) {
mListener.onFragmentInteraction(uri);
}
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
}
#Override
public void onDetach() {
super.onDetach();
mListener = null;
}
interface OnFragmentInteractionListener {
// TODO: Update argument type and name
void onFragmentInteraction(Uri uri);
}
public static void updateList(String cat, Activity context){
TempData.setupListForCategory(context, fragment.listAll, cat);
}
}
I think for starters, you should keep the flow simple and not have a static fragment instance on which you keep calling refresh.
Your code right now is difficult to read and understand.
One basic thing to note with fragments is since they are already re-usable in tandem with a FragmentStatePagerAdapter, you almost never have to deal with this hassle of having a single static instance doing all the work.
Few problems I spotted right now for example were -
You want to attach multiple fragments (as many as there are categories) so you make a new instance and update the static field
public static AnyItemFragment newInstance(int categoryID) {
fragment = new AnyItemFragment();
fragment.selectedPosition = categoryID;
Log.i(TAG, "sel pos: " + fragment.selectedPosition);
return fragment;
}
What is happening right now is since the default offscreenPageLimit on your ViewPager defaults to 1 all your updates are going to the second instance of the fragment which most probably is linked with category-2 and hence nothing renders in the first tab.
You can confirm this by adding debug break-points.
What you would ideally want to do is send the categories to your ViewPagerAdapter and based on the position set the product model list to the correct fragment itself so it knows how to render post creation.
private class SectionsPagerAdapter extends android.support.v13.app.FragmentPagerAdapter {
private final Map<String, List<ProductUserModel>> mapOfCategoryAndProductUsers;
SectionsPagerAdapter(FragmentManager fm, Map<String, List<ProductUserModel>> mapOfCategoryAndProductUsers) {
super(fm);
this.mapOfCategoryAndProductUsers = mapOfCategoryAndProductUsers;
}
#Override
public android.app.Fragment getItem(int position) {
AnyItemFragment fragment = AnyItemFragment.newInstance(position-1);
// Logic to map position to category...
String category = TempData.productCategories.get(position)
fragment.setProductUsers(mapOfCategoryAndProductUsers.get(category))
return fragment;
}
#Override
public int getCount() {
// Show 3 total pages.
return TempData.productCategories.size();
}
...
...
}
And then have the render logic inside the fragment -
private List<ProductUserModel> productUsers;
public void setProductUsers(List<ProductUserModel> productUsers) {
this.productUsers = productUsers;
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
setupList()
}
private void setupList() {
FastItemAdapter<ProductUserModel> p = new FastItemAdapter<>();
p.add(prods);
p.withSelectable(true);
p.withOnClickListener(new FastAdapter.OnClickListener<ProductUserModel>() {
#Override
public boolean onClick(final View v, final IAdapter<ProductUserModel> adapter, final ProductUserModel item, final int position) {
PopupUtils.getUserInputQuantity(context, item, v);
return false;
}
});
//fill the recycler view
Log.i("Temp", "updating list : " + prods.size());
LayoutManager layoutManager = new LinearLayoutManager(context);
listView.setLayoutManager(layoutManager);
listView.setAdapter(p);
}
PS: You should avoid as much as you can the use of static methods, since they make unit testing a nightmare. Also if you don't test your code before hand, I'd suggest checking out unit tests and Espresso for instrumentation test to have more re-assurance around the working of your app and be free of regression blues.
Let me know if this helped or if you'd need more explanation
I have a ListView which contains product details. On Item click of listview I open new activity with particular product detail. I wanted to convert activity to ViewPager so that I can swipe to load next and previous records in same fragment. Fragment structure will be same for all records. I don't know from where should I start. Can you give me overview idea how to achieve this. Here is my model class.
Product.java
public class Product implements Serializable{
public int id;
public String Name;
public String description;
public String longDescription;
public String amount;
public String image;
}
Here is my FragmentPagerAdapter class
ProductPagerAdapter.java
public class ProductPagerAdapter extends FragmentPagerAdapter {
private Context context;
private ArrayList<Product> list;
public ProductPagerAdapter(FragmentManager fm, Context context, ArrayList<Product> list) {
super(fm);
this.context = context;
this.list = list;
}
#Override
public Fragment getItem(int position) {
return ProductFragment.newInstance(position);
}
#Override
public int getCount() {
return list.size();
}
}
And this is my Fragment
ProductFragment.java
public class ProductFragment extends Fragment {
public ProductFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View v = inflater.inflate(R.layout.fragment_product, container, false);
//findViewById...
return v;
}
public static Fragment newInstance(int id) {
Bundle args = new Bundle();
args.putInt("Id", id);
ProductFragment fragment = new ProductFragment();
fragment.setArguments(args);
return fragment;
}
}
And now on list item Click I am opening new activity. And I am sending Product object to it.
lv_itemRateList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
Intent intent = new Intent(getActivity(), DetailsActivity.class);
Product r = new Product();
r = rateListArrayList.get(i);
intent.putExtra("product",r);
startActivity(intent);
}
});
My DetailsActivity contains my viewpager. Now can someone tell me how to do this?
1-) Need a custom adapter for ViewPager.
I assumed that all the pages will have the same content, so all of them have the same layout so ProductPagerAdapter extends the PagerAdapter.
public class ProductPagerAdapter extends PagerAdapter
{
//variables
private Context context;
private ArrayList<Product> list;
private Product product
//views
TextView txtName ;
public ProductPagerAdapter(Context context, List<Product> list)
{
this.context = context;
this.list = list;
}
#Override
public int getCount()
{
return list.size();
}
#Override
public boolean isViewFromObject(View view, Object object)
{
return view == ( object);
}
#Override
public Object instantiateItem(ViewGroup container, int position)
{
product = list.get(position);
inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View itemView = inflater.inflate(R.layout.fragment_product, container,false);
txtName = (TextView) itemView.findViewById(R.id.txtName);
txtName.setText(product.Name)
((ViewPager) container).addView(itemView);
return itemView;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object)
{
((ViewPager) container).removeView((LinearLayout) object);
}
}
2-) Adapter is ready. Now let's prepare the activity that will show the details. First initialize ViewPager and ProductPagerAdapter. Then show the details of the item which is selected by clicking on the previous activity.
public class DetailsActivity extends Activity
{
#Override
protected void onCreate(Bundle savedInstanceState)
{
...
//getting product object
Intent intent = getIntent();
Product product = (Product) getIntent().getSerializableExtra("product");
//get selected item id
int selectedItemID = 0;
for(int i = 0 ; i < list.size() ; i++)
{
if(list.get(i).id == product.id)
{
selectedItemID = i;
break;
}
}
//Init ViewPager and adapter
ViewPager viewPager = (ViewPager) findViewById(R.id.pager);
ProductPagerAdapter detailAdapter = new ProductPagerAdapter(DetailActivity.this, list);
// Binds the Adapter to the ViewPager
viewPager.setAdapter(detailAdapter);
viewPager.setCurrentItem(selectedItemID); // set selection
viewPager.setPageTransformer(true, new ForegroundToBackgroundTransformer()); //custom transformer
...
}
}
3-) We've done what we have to do so far. So it will work like this. But what I would like to point out is that there are a few things to make the ViewPager better.
Performance : Use Parcelable instead of Serializable. Parcelable takes more time to implement but it will perform 10 times faster and use less resources. Please check this SO answer
Animation : You may want to need animations for transforming ViewPager. I suggest you to use ViewPagerTransforms
Indicators : If you want to use the paging indicator, I recommend ViewPagerIndicator.
For more on ViewPager
I am trying to fetch results from sqllite db in ViewPager using Adapater class
public class AppDetailPagerAdapter extends android.support.v4.app.FragmentStatePagerAdapter {
private List<AppPagingData> mData;
public AppDetailPagerAdapter(FragmentManager fm, List<AppPagingData> data) {
super(fm);
this.mData = data;
}
#Override
public Fragment getItem(int i) {
sCurrentPosition = i;
Fragment fragment = AppDetailFragment.newInstance(mData, i);
return fragment;
}
#Override
public int getCount() {
return mData.size();
}
#Override
public CharSequence getPageTitle(int position) {
return "OBJECT " + (position + 1);
}
}
And my fragment is
public class AppDetailFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor> {
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private List<AppPagingData> mData;
private int mCurrentPosition;
private int mToken;
private static final String EXTRA_KEY_APP_DATA = "EXTRA_KEY_APP_DATA";
private static final String EXTRA_KEY_APP_CURR_POSITION = "EXTRA_KEY_APP_CURR_POSITION";
public static AppDetailFragment newInstance(ArrayList<AppPagingData> param1, int currentPosition) {
AppDetailFragment fragment = new AppDetailFragment();
Bundle args = new Bundle();
args.putParcelableArrayList(EXTRA_KEY_APP_DATA, param1);
args.putInt(EXTRA_KEY_APP_CURR_POSITION, currentPosition);
fragment.setArguments(args);
return fragment;
}
public AppDetailFragment() {
// Required empty public constructor
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
getLoaderManager().restartLoader(mToken, null, this);
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
if (loader.getId() == mToken) {
ViewGroup oocsGroup = (ViewGroup) getActivity().findViewById(R.id.oocsGroup);
// Remove all existing timings (except 1 ie header)
//I think this line remove childs for all fragment????
for (int i = oocsGroup.getChildCount() - 1; i >= 1; i--) {
oocsGroup.removeViewAt(i);
}
} else {
cursor.close();
}
}...
Now, the problem is my fragment linear layout items get deleted, as android call my fragment second instance. for e.g. if i select 1st item second will called automatically.
How to avoid layout of first instance to destry because of second.
As your adapter creates a new instance of fragment at getItem(), you are probably loosing the previous fragment to the garbage collector.
You could keep your fragments in an array (or ArrayList) and return fragment from the array at getItem().
like:
// keep created instances of AppDetailFragments
private AppDetailFragment[] frags;
public AppDetailPagerAdapter(FragmentManager fm, List<AppPagingData> data) {
super(fm);
this.data = data;
frags = new AppDetailFragment[data.size()];
// init all frags
for (int i=0;i<data.size();i++) {
frags[i] = AppDetailFragment.newInstance(data, i);
}
}
#Override
public Fragment getItem(int i) {
sCurrentPosition = i;
return frags[i]; // may want to check for arrayindexoutofboundsEx..
}
This way you will keep a reference to all created fragments.
note:
You no longer need to keep the data as for getCount you can return length of frags-array.
Below is an screenshot from my app.
This screen is a fragment that has sliding tabs layout. It will hold another fragment that will show data in listview. The problem is, in order to load data the value selected from the spinner need to pass within the fragment in tab. I am not getting idea how to do this. One approach would be the tab fragment would implement a callback and within that callback data should be loaded. But I am not getting how to register that callback in onItemSelected of spinner.
Note: All fragments within the tab will show data in listview only, so I have created a common fragment.
This is my code so far:
Fragment for the screenshot
public class BuyListingFragment2 extends BaseFragment {
private Context ctx;
private Spinner vehicle_type;
private ArrayList<ListingTabModel> mListingTabs = new ArrayList<ListingTabModel>();
private ArrayAdapter<String> spinnerAdapter;
private ArrayList<String> vehicleTypeSpinnerlist;
private int spinnerPosition;
private SlidingTabLayout sliding_tabs;
private BuyListingPagerAdapter buyListingPagerAdapter;
public static BuyListingFragment2 newInstance(String category,
int position, String preselectedFilters) {
BuyListingFragment2 fragment = new BuyListingFragment2();
Bundle args = new Bundle();
args.putString("vehicle_type", category);
args.putInt("spinner_position", position);
fragment.setArguments(args);
return fragment;
}
public BuyListingFragment2() {
}
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.vehicleType = getArguments().getString("vehicle_type");
this.selectedVehicle = this.vehicleType;
this.spinnerPosition = getArguments().getInt("spinner_position");
ArrayList<CategoryType> vehicleTypeList = RegistrationResponse
.getInstance().getVehicleTypeList();
spinnerAdapter = new ArrayAdapter<String>(getActivity(),
android.R.layout.simple_list_item_1, vehicleTypeList);
buyListingPagerAdapter = new BuyListingPagerAdapter(
getChildFragmentManager(), mListingTabs);
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
ctx = getActivity();
vehicle_type = (Spinner) view.findViewById(R.id.vehicle_type);
vehicle_type.setAdapter(spinnerAdapter);
vehicle_type.setSelection(spinnerPosition, false);
if (mListingTabs.isEmpty()) {
String[] tabNames = getResources().getStringArray(
R.array.listing_tab_names);
for (int i = 0; i < tabNames.length; i++) {
String tabName = tabNames[i];
ListingTabModel mListingTabModel = new ListingTabModel();
mListingTabModel.setTagName(tabName);
mListingTabs.add(mListingTabModel);
}
}
buyListingPagerAdapter.notifyDataSetChanged();
listing_layout_viewpager = (ViewPager) view
.findViewById(R.id.listing_layout_viewpager);
listing_layout_viewpager.setAdapter(buyListingPagerAdapter);
sliding_tabs = (SlidingTabLayout) view.findViewById(R.id.sliding_tabs);
sliding_tabs.setDistributeEvenly(true);
sliding_tabs.setViewPager(listing_layout_viewpager);
vehicle_type.setOnItemSelectedListener(new OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view,
int position, long id) {
spinnerPosition = position;
//How to register listener here
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
}
}
Common Fragment inside Tab
public class ListingFragment extends BaseFragment implements
OnSpinnerDataSelected {
private InfiniteListView mListView;
private BuyListingListAdapter buyListingAadapter;
private RobotoLightTextView emptyMessage;
private int currentPageNumber = 1;
private int totalPages;
private HashMap<String, String> params = new HashMap<String, String>();
private int apiCallCount = 0;
private Context ctx;
private String vehicleType;
private ProgressBar progressBar;
public ListingFragment() {
}
public static ListingFragment newInstance(ListingTabModel mListingTabModel) {
ListingFragment mFragment = new ListingFragment();
Bundle bundle = new Bundle();
// bundle.putBoolean("is_grid_view", mListingTabModel.isShowGridView());
// bundle.putString("vehicle_type", mListingTabModel.getVehicleType());
mFragment.setArguments(bundle);
return mFragment;
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
ctx = getActivity();
emptyMessage = (RobotoLightTextView) view
.findViewById(R.id.empty_message);
mListView = (InfiniteListView) view.findViewById(R.id.lstVw_buy);
boolean isGrid = getArguments().getBoolean("is_grid_view");
vehicleType = getArguments().getString("vehicle_type");
buyListingAadapter = new BuyListingListAdapter(ctx,
mVehicleListingList, isGrid);
mListView.setAdapter(buyListingAadapter);
progressBar = new ProgressBar(ctx);
}
#Override
public int getLayoutId() {
return R.layout.layout_messages;
}
#Override
public void onSpinnerDataSelected(String vehicleCategory) {
// TODO: fetch listing data
}
}
Callback implemented by the ListingFragment
public interface OnSpinnerDataSelected {
void onSpinnerDataSelected(String vehicleCategory);
}
FragmentStatePagerAdapter
public class BuyListingPagerAdapter extends FragmentStatePagerAdapter {
ArrayList<ListingTabModel> mFragmentsList;
public BuyListingPagerAdapter(FragmentManager fm,
ArrayList<ListingTabModel> mFragmentsList) {
super(fm);
this.mFragmentsList = mFragmentsList;
}
#Override
public Fragment getItem(int index) {
ListingFragment listingFragment = ListingFragment
.newInstance(mFragmentsList.get(index));
return listingFragment;
}
#Override
public int getCount() {
return mFragmentsList.size();
}
#Override
public CharSequence getPageTitle(int position) {
String tagName = mFragmentsList.get(position).getTagName();
tagName = tagName.replace("_", " ");
return tagName;
}
#Override
public boolean isViewFromObject(View view, Object object) {
return object == view;
}
}
When using one activity and multiple fragments, I suggest to let the Fragment manage the UI and use the Activity has a controller/model.
Workflow for a spinner to communicate with other fragments :
Register the spinner listener in Frag1
Register a data listener from Frag2 in Activity
OnItemSelected from Frag1 prevent Activity from the Spinner value change
Activity received the spinner change value
Activity call Frag2 listener to prevent Frag2 of the spinner change
Frag2 receive spinner change, do your stuff
Here is a litle schema
I would base everything on an event bus like Otto. IMHO, Fragments were meant to be decoupled from hosting activities and such, but all the interfaces and callbacks end up creating spaghetti code. Otto lets you post event on a common bus -- the receiver doesn't need to be tied to the sender via some listener/callback mechanism. Plus, it works great in conjunction with dependency injection, see Dagger.
I have problem with FragmentPagerAdapter ,I have set fragments in viewpager through FragmentPagerAdapter,
I have to show viewpager dynamically,I have listview data , which I need to show in viewpager,
when I click on the listview , I have to load exact position in the viewpager
so i just set the total size of the item to show in FragmentPagerAdapter, But the problem is that when I select the viewpager position through mPager.setCurrentItem(listposition) it show correct position of the viewpager,
but the data load at wrong place, it load in next fragement in viewpager position,after some tracking in FragmentPagerAdapter, I show that instantiateItem method initailize one fragment in advance, like i set the currentitem (from listview)of viewpager 2
then instantiateItem method initalize 0 to 3 fragment, I think that the reason the data load in 3rd fragment,I tried a lot with FragmentStatePagerAdapter also but no any success , please help me , thanks in advance.
Mainactivity class(Fragmnetactivity) :
public class NewsDetail extends FragmentActivity implements OnClickListener {
public static ViewPager mPager;
private static int NUM_PAGES;
private PagerAdapter mPagerAdapter;
public static ArrayList<Integer> exist_detail = new ArrayList<Integer>();
public static ArrayList<PageFragment> detailfragment = new ArrayList<PageFragment>();
mPager = (ViewPager) findViewById(R.id.pager);
mPagerAdapter = new ScreenSlidePagerAdapter(getSupportFragmentManager());
mPager.setAdapter(mPagerAdapter);
NUM_PAGES = topList.size();
PageFragment fragment = new PageFragment();
Bundle args = new Bundle();
args.putInt("page", i);
fragment.setArguments(args);
detailfragment.add(fragment);
mPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
#Override
public void onPageSelected(int arg0) {
if (PageFragment.getInstance() != null) {
Log.d("LOG","PageFragment || "+ PageFragment.getInstance());
PageFragment.getInstance().startLoadingNews(
MusicList.topMusicList.get(arg0)._id);
}
return;
}
#Override
public void onPageScrolled(int arg0, float arg1, int arg2) {}
#Override
public void onPageScrollStateChanged(int arg0) {}
});
mPagerAdapter.notifyDataSetChanged();
mPager.setCurrentItem(listposition);// setcurrent item from here , it is selected from list. "listposition" indicate list position click
private class ScreenSlidePagerAdapter extends FragmentPagerAdapter {
private FragmentManager mFragmentManager;
private FragmentTransaction mCurTransaction = null;
private Fragment mCurrentPrimaryItem = null;
private static final boolean DEBUG = false;
public ScreenSlidePagerAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
this.mFragmentManager = fragmentManager;
}
#Override
public Fragment getItem(int position) {
return detailfragment.get(position);
}
#Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return super.getItemId(position);
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
Log.v("LOG", "On InstantiateItem " + position);// it indicate that this method initialize one fragment in advance.
return super.instantiateItem(container, position);
}
public String makeFragmentName(int viewId, long index) {
return "android:switcher:" + viewId + ":" + index;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
if (DEBUG)
Log.e("LOG", "Detaching item #" + position + ": f=" + object
+ " v=" + ((Fragment) object).getView());
mCurTransaction.detach((Fragment) object);
}
#Override
public void restoreState(Parcelable state, ClassLoader loader) {
}
#Override
public int getCount() {
return NUM_PAGES;
}
}
}
PageFragment
public class PageFragment extends Fragment implements OnClickListener {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mPageNumber = getArguments().getInt(ARG_PAGE);
mDetailPageFragment = this;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout containing a title and body text.
rootView = (ViewGroup) inflater.inflate(R.layout.newsdetail, container,
false);
//init();
return rootView;
}
public void startLoadingNews(String _id) {
if (NetworkUtil.cheackNetwork(mActivity)) {
executeTask(_id);
} else {
showRetryCancelDialog();
}
}
}
I can see two issues in the code you've posted:
Only instantiate your fragments in FragmentPagerAdapter.getItem. Don't instantiate them and save them to some list or array, let the FragmentPagerAdapter do that for you. In FragmentPagerAdapter.instantiateItem it checks if the Fragment was already created and if so it returns it, if not, it'll call your getItem to create the fragment.
Don't use the Singleton scheme for your fragment, create a new fragment using a constructor or a .newInstance() static helper.