Communicate between Activity and ViewPager Fragments - android

Like in the image below, I have an Activity with a ViewPager (with TabLayout) inside.
Now I want to refresh for example the text of an TextView in a ViewPager Fragment. How can I do this?
http://imgur.com/0kWQCfx
[Sorry for the image link, but I don't have enough reputations yet.]
I already tried something like this:
//In Activity
View root = getLayoutInflater().inflate(R.layout.fragment_home, null);
TextView textView = (TextView) root.findViewById(R.id.text_view);
textView.setText("test");
But I get a NullPointerException for the textView.
Edit 1:
I only need to access the components inside one Fragment, so I am not using an array inside the Adapter.
I changed my ViewPagerAdapter to this:
public class ViewPagerAdapter extends FragmentPagerAdapter {
public HomeFragment fragment;
...
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return fragment = new HomeFragment();
case 1:
...
default:
return null;
}
}
But I still get a NullPointerException here:
final Fragment root = viewPagerAdapter.fragment;
Log.d("testtest", String.valueOf(root == null));

Write this code in your activity where you want to change fragment value. Your fragment id is e.g. my_fragment
Fragment frag = getFragmentManager().findFragmentById(R.id.my_fragment)
((TextView) frag.getView().findViewById(R.id.text_view)).setText(s);

You can create your own Adapter:
private class YourAdapter extends FragmentPagerAdapter implements ViewPager.OnPageChangeListener
{
Fragment screens[];
public CheckinHistoryAdapter(FragmentManager fm) {
super(fm);
screens = new Fragment[3];
screens[0] = new CoachFragment();
screens[1] = new LogingFragment();
screens[2] = new HistoryFragment();
}
#Override
public Fragment getItem(int index) {
if(index <= screens.length)
{
return screens[index];
}
return null;
}
#Override
public int getCount() {
return screens.length;
}
}
Use it like this
mViewPager.setAdapter(this.mPagerAdapter);
You can access fragment object with getItem method.

If you only need a reference to one Fragment, then just use the position parameter passed into instantiateItem(), and only assign your Fragment reference for the desired position:
public class ViewPagerAdapter extends FragmentPagerAdapter {
public HomeFragment fragment;
//...
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return new HomeFragment(); //modified
case 1:
...
default:
return null;
}
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment createdFragment = (Fragment) super.instantiateItem(container, position);
if (position == 0) {
fragment = (HomeFragment) createdFragment;
}
return createdFragment;
}
}

Related

Replacing fragment in ViewPager causes IllegalStateException

Following this example I'm trying to replace one fragement with another within a single tab of a ViewPager. I'm getting this exception:
java.lang.IllegalStateException: Can't change tag of fragment DailyWordFragment
class ViewPagerAdapter extends FragmentPagerAdapter {
private final FragmentManager fragmentManager;
Fragment fragment;
public ViewPagerAdapter(FragmentManager manager) {
super(manager);
fragmentManager = manager;
}
#Override
public Fragment getItem(int position) {
switch (position){
case 0:
if(fragment == null){
fragment = DailyWordFragment.newInstance();
}
return fragment;
case 1:
if(fragment == null){
fragment = WordListFragment.newInstance(new WordListFragment.OnWordItemAddListener() {
#Override
public void onWordItemAddListener() {
fragmentManager.beginTransaction().remove(fragment).commit();
fragment = AddWordFragment.newInstance();
notifyDataSetChanged();
}
});
}
return fragment;
default:
return null;
}
}
#Override
public int getItemPosition(Object object) {
if(object instanceof WordListFragment && fragment instanceof AddWordFragment)
return POSITION_NONE;
return POSITION_UNCHANGED;
}
#Override
public int getCount() {
return 2;
}
}
According to other posts this exception seems to be caused by adding the same fragment repeatedly, or getting miscounting the number of fragments but I can't see where either of these are occurring if at all? Clearly I'm missing something. I would appreciate any help. Thank you.
Have you tried before you initialize the Fragment to set it to null?
#Override
public Fragment getItem(int position) {
fragment = null
switch (position){
case 0:
if(fragment == null){
fragment = DailyWordFragment.newInstance();
}
return fragment;
case 1:
if(fragment == null){
fragment = WordListFragment.newInstance(new WordListFragment.OnWordItemAddListener() {
#Override
public void onWordItemAddListener() {
fragmentManager.beginTransaction().remove(fragment).commit();
fragment = AddWordFragment.newInstance();
notifyDataSetChanged();
}
});
}
return fragment;
default:
return null;
}
}
To SWAP fragments in one tab of a View Pager you have to do it in a different way:
You need a fragment that goes in the ViewPager that acts as a container. which is managed by the ViewPager. This Fragment is allways there in the tab, never swaps or changes.
Inside that Fragment you have 2 child fragments that you can swap using transactions with the ChildFragmentManager. But the ViewPager doesn't even know about their existance.

In tab layout activity my fragment does not refresh while swiping

I'm using fragmentpageradapter to inflate fragment , this is my coding.
i'm adding cart item in one fragment and showing it to other fragment and all fragment comes in tab layout.My problem is cart item is not refreshing on other fragment while swiping fragment.
public class ProfileDetailePagerAdapter extends FragmentPagerAdapter
{
int TabCount;
HashMap<Integer, String> mFragmentTags;
FragmentManager mFragmentManager;
private boolean isPagingEnabled = true;
public ProfileDetailePagerAdapter(FragmentManager fm, int TabCount) {
super(fm);
this.TabCount = TabCount;
mFragmentTags = new HashMap<Integer, String>();
mFragmentManager = fm;
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
MenuFragment tab1 = new MenuFragment();
return tab1;
case 1:
SelectMember_fragment tab2 = new SelectMember_fragment();
return tab2;
case 2:
ViewCart_fragment tab3 = new ViewCart_fragment();
return tab3;
/* case 3:
PaymentMode_fragment tab4=new PaymentMode_fragment();
return tab4;*/
}
return null;
}
#Override
public int getCount() {
return TabCount;
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
Object obj = super.instantiateItem(container, position);
if (obj instanceof Fragment) {
// record the fragment tag here.
Fragment f = (Fragment) obj;
String tag = f.getTag();
mFragmentTags.put(position, tag);
}
return obj;
}
public Fragment getFragment(int position) {
String tag = mFragmentTags.get(position);
if (tag == null)
return null;
return mFragmentManager.findFragmentByTag(tag);
}
}
Call FragmentStatePagerAdapter
You should use addOnTabSelectedListener
This method is used to add a listener that will be invoked when tab
selection changes.
tabLayoutOBJ.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener(){
public void onTabReselected(TabLayout.Tab tab) {
}
public void onTabSelected(TabLayout.Tab tab){
String getTAB = (String)tab.getText();
// Do your WORK
}
public void onTabUnselected(TabLayout.Tab tab){
}
});
The reason behind it is the implementation of viewpager. There is a property called offset in ViewPager to make ready fragments next to it up to offset(int) value.
Default value is 1. For example, you are in 1st position, 0th and 2nd positions are also created.
On the other hand if you are in 0th position 1st is the only created fragment. If you swipe to right (going 1st) then 2nd is going to be created.
I assume you are changing a shared object from 1st fragment and want to notify 2nd fragment with changed data. To solve it you need to use listener. The elegant way to solve it is adding observer pattern to your shared object.
Good luck
Emre

Reload fragments inside ViewPager which inside another fragment inViewPager

I have an activity, which includes ViewPager with three fragments. In the second fragment i have ViewPager with two different fragments too.
This my MainActivityPagerAdapter which connected with ViewPager in MainActivity:
public class MainActivityPagerAdapter extends FragmentStatePagerAdapter implements LoginView.LoginStateChangeListener {
private static final String TAG = MainActivityPagerAdapter.class.getName();
private MapFragment mapFragment = new MapFragment();
private UserProfileFragment userProfileFragment = new UserProfileFragment();
private CompanyProfileFragment CompanyProfileFragment = new DiveCenterProfileFragment();
private NotificationsFragment notificationsFragment = new notificationsFragment();
public MainActivityPagerAdapter(FragmentManager manager) {
super(manager);
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return mapFragment;
case 1:
return notificationsFragment;
case 2:
switch (MyApplication.getInstance().getSharedPreferenceHelper().getActiveUserType()) {
case DIVECENTER:
return companyProfileFragment;
case DIVER:
case INSTRUCTOR:
return userProfileFragment;
case NONE:
return userProfileFragment;
}
default:
return null;
}
}
#Override
public int getCount() {
return 3;
}
#Override
public int getItemPosition(Object object) {
Log.i(TAG, "getItemPosition");
return POSITION_NONE;
}
#Override
public CharSequence getPageTitle(int position) {
return null;
}
}
This my pager adapter for ViewPager at the second fragment:
public class NotificationsPagerAdapter extends FragmentStatePagerAdapter {
private PersonalNotificationsFragment personalNotificationsFragment = new PersonalNotificationsFragment();
private ActivityNotificationsFragment activityNotificationsFragment = new ActivityNotificationsFragment();
public NotificationsPagerAdapter(FragmentManager manager) {
super(manager);
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return personalNotificationsFragment;
case 1:
return activityNotificationsFragment;
default:
return null;
}
}
#Override
public int getCount() {
return 2;
}
public void setPersonalNotificationsFragment(PersonalNotificationsFragment personalNotificationsFragment) {
this.personalNotificationsFragment = personalNotificationsFragment;
}
public void setActivityNotificationsFragment(ActivityNotificationsFragment activityNotificationsFragment) {
this.activityNotificationsFragment = activityNotificationsFragment;
}
#Override
public CharSequence getPageTitle(int position) {
return null;
}
#Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
}
So, there are two user types in app:
Simple user
Company
When user changing his type i need to refresh all fragments in MainActivity including fragments inside second fragment. For this I'm using notifyDataSetChanged() for MainActivityViewPager, it work correctly, but fragments inside second fragment don't update(onCreateView don't called, and i see only empty views).
In what may be a problem?
Use getChildFragmentManager() for inner viewPager
Use getChildFragmentManager() instead of getFragmentManager() for changing fragments inside the viewPager

Refreshing the layout of a Fragment in ViewPager

I have an activity which uses ViewPager with 4 fragments. I am using FragmentPagerAdapter to populate the pages.
public class SectionsPagerAdapter extends FragmentPagerAdapter {
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return new FragmentA()
case 1:
return new ProfileFragment();
case 2:
return new FragmentC();
case 3:
return new FragmentD();
}
return null;
}
#Override
public int getCount() {
return 4;
}
}
One of these fragments shows the details of User (ProfileFragment in the above code) with following criteria:
If the user isn't logged in, show login layout
If the user is logged in, show profile layout
Hence, when user opens the app for the first time, the login layout will be shown and when user logs in, the fragment needs to be refreshed to show the profile layout.
The approach I was planning to take was that when user logs in, navigate him to FragmentA and destroy the existing ProfileFragment. The onCreateView method of ProfileFragment handles which layout to show based on login state.
public class ProfileFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
int layout = userLoggedIn() ? R.layout.fragment_user_login : R.layout.fragment_user_profile;
return inflater.inflate(layout, container, false);
}
// Handler for login
public void loginUser() {
((MyActivity) getActivity()).loginUser();
}
}
public class MyActivity extends AppCompatActivity {
private SectionsPagerAdapter mSectionsPagerAdapter;
public void loginUser() {
// 1. Set login details as needed
...
// 2. Navigate to FragmentA
...
// 3. Destroy ProfileFragment
mSectionsPagerAdapter.destroyItem(container, 1, object); // How to get `object` here?
}
}
I have two questions regarding this:
The method destroyItem takes Object object returned from instantiateItem. How to get this value while destroying? Do I need to overwrite instantiateItem and maintain a Map<Integer, Object> from position to object?
Is there a better way to update the view of the fragment without destroying the fragment completely?
I did something like that before using FragmentStatePagerAdapter, you can call notifyDataSetChanged the getItemPosition is called for each existing fragment if you call super.getItemPosition it returns POSITION_UNCHANGED when means the fragment has not changed if you return POSITION_NONE will cause the fragment at that position to be reloaded. you can use that in the getItem method to provide the profile fragment.
in this solution you just need to call setLoggedIn
public class SectionsPagerAdapter extends FragmentStatePagerAdapter {
boolean isLoggedIn = false;
boolean userHasJustLoggedIn = false;
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
public void setIsLoggedIn() {
isLoggedIn = true;
userHasJustLoggedIn = true;
notifyDataSetChanged();
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return new FragmentA()
case 1:
if (isLoggedIn) {
return new ProfileFragment();
} else {
return new LoginFragment();
}
case 2:
return new FragmentC();
case 3:
return new FragmentD();
}
return null;
}
#Override
public int getItemPosition(Object object) {
Fragment fragment = (Fragment) object;
if (fragment instanceof LoginFragment && userHasJustLoggedIn) {
userHasJustLoggedIn = false;
return POSITION_NONE;
}
return super.getItemPosition(object);
}
#Override
public int getCount() {
return 4;
}
}

How to structure the tabs in a tabHost in Android?

I'm crating a tabHost to contain all the content of my Android application in 3 tabs, should i create the content of the tab inside its linear layout or create the tab content in a separate fragment and include it in the tab layout?
And how to include the fragment inside a layout also?
Excuse me i'm a bit beginner to this.
you just add viewpagger for calling fragment
public class MyPagerAdapter extends FragmentPagerAdapter {
private final String[] TITLES = { "Fragment1", "Fragment2", "Fragment2" };
public MyPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public CharSequence getPageTitle(int position) {
return TITLES[position];
}
#Override
public int getCount() {
return TITLES.length;
}
#Override
public Fragment getItem(int position) {
//return SuperAwesomeCardFragment.newInstance(position);
switch (position) {
case 0:
return new JavaFragment1(); //this call you fragment1
case 1:
return new JavaFragment2(); //this call you fragment2
case 2:
return new JavaFragment3(); //this call you fragment3
}
return null;
}
}

Categories

Resources