This is killing me. I have one DemoFragment which has 3 instances created. Within these instances different data is loaded into the fragments. What I want to be able to do is have a button (within the fragment) that forces all of the Fragments to refresh or reload. This is necessary as the button also commits new data that needs to be pulled newly for every fragment.
I've search plenty of solutions, but can't get to the bottom of it. Currently I have a an activity, fragment and adapter. Below is the abridged code (as expected this loads 3 pages):
Activity (RoutineDetailsActivity.java)
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.view.ViewPager;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Button;
public class RoutineDetailsActivity extends FragmentActivity {
ViewPager mViewPager;
Button mLogout;
CustomPagerAdapter mSectionsPagerAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_routine_details);
mSectionsPagerAdapter = new CustomPagerAdapter(getSupportFragmentManager());
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(mSectionsPagerAdapter);
}
}
Adapter (CustomPagerAdapter.java)
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter;
import java.util.Locale;
public class CustomPagerAdapter extends FragmentStatePagerAdapter {
public CustomPagerAdapter (FragmentManager fm) {
super(fm);
}
#Override
public int getCount() {
return 3;
}
#Override
public Fragment getItem(int position) {
return DemoFragment.newInstance(position);
}
#Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
}
}
Fragment (DemoFragment.java)
public class DemoFragment extends Fragment {
int mNum;
static DemoFragment newInstance(int num) {
DemoFragment f = new DemoFragment();
Bundle args = new Bundle();
args.putInt("num", num);
f.setArguments(args);
return f;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mNum = getArguments() != null ? getArguments().getInt("num") : 1;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_routine_details, container, false);
}
#Override
public void onResume() {
// CODE CLIPPED, do loads of sh*t
Button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// New data uploaded to server
// What code to force reload the fragments?
}
});
}
So within this code, more specifically, within the button click, what do I need to do to force the all Fragments to reload and retrieve the latest data.
I've sen answers around this, but I'm sure how to relate it to here.
Thanks.
If you a willing to add a small library called EventBus: https://github.com/greenrobot/EventBus
You can do like this:
public class AnyFragment extends Fragment {
#Override
public void onAttach(final Activity activity) {
super.onAttach(activity);
EventBus.getDefault().register(this);
}
#Override
public void onDetach() {
EventBus.getDefault().unregister(this);
super.onDetach();
}
public void onEventMainThread(UpdateUIEvent ev) {
// perform refresh
}
}
UpdateUIEvent is just a simple empty object in my case but could contain arbitrary data as well:
public class UpdateUIEvent {}
With this in place you can refresh AnyFragment from anywhere in your code by doing:
EventBus.getDefault().post(new UpdateUIEvent());
I want to stress that you can do this Anywhere, but in you case, the above line would be the only thing you would have to do in click of your button. Then all fragments listening, as shown with AnyFragment, will receive the event :)
Implement an interface in your fragment say IRefresher. Keep track of references of the 3 fragments in your activity. When button is clicked call the interface method say refreshMe() which would work as a listener/callback in the fragments and in that method refresh your fragment.
I have done it in one of my project and it works flawlessly
I am not sure whether I have understood your problem or not. From your button trigger you can call the parent activity which one is holding all the fragments. Create a method in the parent activity. Inside the method register listener (Call Interface method) which update the fragments lists. Call the parent method from fragment(s) when you need it.
Related
So if I have three Fragments A,B, and C.
So when I launch Fragment B I want viewpager to let me swipe from LEFT to RIGHT and it should take me back to Fragment A, but viewpager, by default lets me swipe from RIGHT to LEFT to go to Fragment A.
So basically I want viewpager to let me swipe from LEFT to RIGHT and not from RIGHT to LEFT.
Also I tried:
viewpager.setRotationY=180
That does let me do what I want but all the contents in my Fragments get flipped upside down.
The adapter I am using:
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
import org.jetbrains.annotations.NotNull;
public class Adapter extends FragmentPagerAdapter {
public Adapter(FragmentManager fragmentManager){
super(fragmentManager);
}
#NonNull
#NotNull
#Override
public Fragment getItem(int position) {
if(position==0){
return new SettingsFragment();
}
if(position==1){
return new BlankFragment();
}
if(position==2){
return new VersionFragment();
}
return null;
}
#Override
public int getCount() {
return 3;
}
}
The activity where I use the adapter:
public class SettingsActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_settings);
Fragment fr=new Fragment();
getSupportFragmentManager().beginTransaction().addToBackStack(null).add(fr,"settings_fragment").commit();
runOnUiThread(new Runnable() {
#Override
public void run() {
ViewPager viewPager=findViewById(R.id.ViewPager);
viewPager.setCurrentItem(1);
viewPager.setAdapter(new Adapter(getSupportFragmentManager()));
viewPager.setOffscreenPageLimit(1);
}
});
}
}
I think your code is misleading you, because you using viewPager.setCurrentItem(1); before setAdapter(...) which you ViewPager will not go to item 1 as you expected.
So, try put that viewPager.setCurrentItem(1); after setAdapter(...)
This question already has answers here:
Proper implementation of ViewPager2 in Android
(12 answers)
Closed 3 years ago.
Android Studio 3.6
I want in my activity to use 2 fragments inside ViewPager2.
Here my activity:
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.viewpager2.widget.ViewPager2;
public class QRBluetoothSwipeActivity extends AppCompatActivity {
private ViewPager2 myViewPager2;
private ViewPagerFragmentAdapter myAdapter;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
// Make sure this is before calling super.onCreate
setTheme(R.style.AppTheme); // show splash screen
super.onCreate(savedInstanceState);
setContentView(R.layout.qr_bluetooth_swipe_activity);
init();
}
private void init() {
myAdapter = new ViewPagerFragmentAdapter(getSupportFragmentManager());
myAdapter.addFragment(new BluetoothPageFragment());
myAdapter.addFragment(new QrPageFragment());
myViewPager2.setOrientation(ViewPager2.ORIENTATION_VERTICAL);
myViewPager2.setAdapter(myAdapter);
}
}
here ViewPagerFragmentAdapter
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.viewpager2.adapter.FragmentStateAdapter;
import java.util.ArrayList;
public class ViewPagerFragmentAdapter extends FragmentStateAdapter {
private ArrayList<Fragment> arrayList = new ArrayList<>();
public ViewPagerFragmentAdapter(#NonNull FragmentManager fragmentManager) {
super(fragmentManager);
}
#NonNull
#Override
public Fragment getItem(int position) {
return arrayList.get(position);
}
public void addFragment(Fragment fragment) {
arrayList.add(fragment);
}
#Override
public int getItemCount() {
return arrayList.size();
}
}
but I get compile error:
ViewPagerFragmentAdapter is not abstract and does not override abstract method createFragment(int) in FragmentStateAdapter
How I can fix this and use FRAGMENTS in ViewPager2 ?
Thanks
FragmentStateAdapter in ViewPager2 is a little bit different than in ViewPager as follows:
Instead of implementing getCount(), implement getItemCount()
Instead of implementing getItem(int position), implement createFragment(int position)
Constructor signature is different by adding Lifecycle argument
which should be included in super as well
So replace your ViewPagerFragmentAdapter with below
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.lifecycle.Lifecycle;
import androidx.viewpager2.adapter.FragmentStateAdapter;
import java.util.ArrayList;
public class ViewPagerFragmentAdapter extends FragmentStateAdapter {
private ArrayList<Fragment> arrayList = new ArrayList<>();
public ViewPagerFragmentAdapter(#NonNull FragmentManager fragmentManager, #NonNull Lifecycle lifecycle) {
super(fragmentManager, lifecycle);
}
public void addFragment(Fragment fragment) {
arrayList.add(fragment);
}
#Override
public int getItemCount() {
return arrayList.size();
}
#NonNull
#Override
public Fragment createFragment(int position) {
// return your fragment that corresponds to this 'position'
return arrayList.get(position);
}
}
Also make sure to import/extend the right adapter of ViewPager2
import androidx.viewpager2.adapter.FragmentStateAdapter;
UPDATE 2021
This answered the original issue of the question; However creating the FragmentStateAdapter this way is not that right generally speaking; because of:
To have a high performant ViewPager, it should keep only a few instantiated off-screen page fragments.
Keeping all the page fragments into a list is not good in terms of wasting device resources.
createFragment(), as its name implies, is intended to create a new fragment for a particular page and return it; not to return a fragment from a list that has already instantiated fragments.
Above all as per documentation createFragment()::
Provide a new Fragment associated with the specified position.
The adapter will be responsible for the Fragment lifecycle:
The Fragment will be used to display an item.
The Fragment will be destroyed when it gets too far from the
viewport, and its state will be saved. When the item is close to the
viewport again, a new Fragment will be requested, and a previously
saved state will be used to initialize it.
So, I'd suggest to change this design to include that into consideration:
Assuming your page fragment is PageFragment; then you can have single instance pattern by having static PageFragment newInstance(int position) {} method in the PageFragment, and then the createFragment() should be then:
#NonNull
#Override
public Fragment createFragment(int position) {
// return a brand new fragment that corresponds to this 'position'
return PageFragment.newInstance(position); // Create a new instance of the page fragment
}
I am not sure how to ask this. I tried in here, but I guess I was not clear enough. So, I thought I just write a small App to describe the situation. Please note, the App uses Googles SlidingTabLayout.
Long story short, at any point if I click Button1, the FrameLayout should contain Fragment1, removing Fragment2 (if exists). Therefore, FragmentViewPager should also be destroyed as Fragment2. However, even then if I change the orientation of my device, I get the Toast which is defined in the onCreate() method of FragmentViewPager.
Why FragmentViewPager's onCreate is called even if Fragment2 is paused/destroyed? Is it possible that, the Toast of FragmentViewPager will not be shown when Fragment2 is destroyed?
MainActivity:
package com.abdfahim.testproject;
import android.app.Fragment;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button1 = (Button) findViewById(R.id.button1);
button1.setOnClickListener(onClickListener);
Button button2 = (Button) findViewById(R.id.button2);
button2.setOnClickListener(onClickListener);
}
private View.OnClickListener onClickListener = new View.OnClickListener() {
#Override
public void onClick(View v) {
Fragment fragment;
switch (v.getId()){
case R.id.button1:
fragment = new Fragment1();
break;
case R.id.button2:
fragment = new Fragment2();
break;
default:
return;
}
getFragmentManager().beginTransaction().replace(R.id.frame_container, fragment, v.getTag().toString()).addToBackStack(null).commit();
}
};
}
Fragment1
package com.abdfahim.testproject;
import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class Fragment1 extends Fragment {
public Fragment1(){}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment1,container,false);
setHasOptionsMenu(true);
return rootView;
}
}
Fragment2
package com.abdfahim.testproject;
import android.app.Fragment;
import android.app.FragmentManager;
import android.os.Bundle;
import android.support.v13.app.FragmentStatePagerAdapter;
import android.support.v4.view.ViewPager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class Fragment2 extends Fragment {
public Fragment2(){}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment2,container,false);
setHasOptionsMenu(true);
CharSequence titles[]= {"Tab A", "Tab B"};
// Creating The ViewPagerAdapter
ViewPagerAdapter adapter = new ViewPagerAdapter(getActivity().getFragmentManager(), titles, titles.length);
ViewPager pager = (ViewPager) rootView.findViewById(R.id.pager);
pager.setAdapter(adapter);
// Assigning the Sliding Tab Layout View
SlidingTabLayout tabs = (SlidingTabLayout) rootView.findViewById(R.id.tabs);
// Setting the ViewPager For the SlidingTabsLayout
tabs.setViewPager(pager);
return rootView;
}
static class ViewPagerAdapter extends FragmentStatePagerAdapter {
private CharSequence titles[];
private int numbOfTabs;
public ViewPagerAdapter(FragmentManager fm, CharSequence mTitles[], int mNumbOfTabs) {
super(fm);
this.titles = mTitles;
this.numbOfTabs = mNumbOfTabs;
}
#Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
#Override
public Fragment getItem(int position) {
Bundle bundle = new Bundle();
bundle.putString("displayText", "Inside Fragment 2, " + titles[position]);
FragmentViewPager fragment = new FragmentViewPager();
fragment.setArguments(bundle);
return fragment;
}
// This method return the titles for the Tabs in the Tab Strip
#Override
public CharSequence getPageTitle(int position) {
return titles[position];
}
// This method return the Number of tabs for the tabs Strip
#Override
public int getCount() {
return numbOfTabs;
}
}
}
FragmentViewPager
package com.abdfahim.testproject;
import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;
public class FragmentViewPager extends Fragment {
public FragmentViewPager(){}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_view_pager,container,false);
setHasOptionsMenu(true);
Bundle bundle = this.getArguments();
TextView textView = (TextView) rootView.findViewById(R.id.tabText);
textView.setText(bundle.getString("displayText"));
return rootView;
}
#Override
public void onStart() {
super.onStart();
Toast.makeText(getActivity(), "This is View Pager Fragment", Toast.LENGTH_SHORT).show();
}
}
when you use fragment inside another fragment. you use getChildFragmentManager() instead of getFragmentManager. You can call setAdapter() for the ViewPager from onCreateView() or onActivityCreated()
for more detail. have a look at it
Why it is not possible to use ViewPager within a Fragment? It actually is
For every click your OnClickListener creates the instance of Fragment2 and does not create Fragment1. That is due to the misuse of View#getTag.
In MainActivity#onCreate, change the if in the definition of onClickListener to this(using this answer):
switch (v.getId()){
case R.id.button1:
fragment = new Fragment1();
break;
case R.id.button2:
fragment = new Fragment2();
break;
default:
return;
}
In your code, in the if that is checked upon a click (for example after clicking button1) android asks v (the clicked View) for its tag - but as none was set using View#setTag - it returns null which is of course not equal to the String object created for "button1", thus the if reverts to the else every time.
i followed this article http://www.truiton.com/2015/06/android-tabs-example-fragments-viewpager/ to implement swipe view and it work nice. So now i want to add button on Tab1 and when clicked has to send data to Tab2.
I know there is the issue of using interface but honestly i don't know how to add it on these codes and work provide am completely new to the android.
so far i have tried my best on these links Communication between SlidingTabLayout tabs, How to pass data from one swipe tab to another? and How can I communicate/pass data through different Fragments with Swipe Tab? but i fail.
Any one help please to make it work on every stage , i mean from Tab1 ->Mainactivity->Tab2
thanks alot
Here are the codes after i edit the question
Fragment1
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class TabFragment1 extends Fragment implements AdapterView.OnItemSelectedListener{
Button send;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v= inflater.inflate(R.layout.tab_fragment_1, container, false);
send=(Button)v.findViewById(R.id.send);
send.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// value to be sent to the TabFragment2 on button click
String value=" My Data";
}
});
return v;
}
}
Fragment2
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class TabFragment2 extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.tab_fragment_2, container, false);
//Display value from TabFragment1
textview.setText(value);
}
}
Interface class
public Interface FragmentCommunication
{
public void printMessage(String message);
}
MainActivity
import android.os.Bundle;
import android.support.design.widget.TabLayout;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
public class MainActivity extends AppCompatActivity implements FragmentCommunication{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout);
tabLayout.addTab(tabLayout.newTab().setText("Tab 1"));
tabLayout.addTab(tabLayout.newTab().setText("Tab 2"));
tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
final ViewPager viewPager = (ViewPager) findViewById(R.id.pager);
final PagerAdapter adapter = new PagerAdapter
(getSupportFragmentManager(), tabLayout.getTabCount());
viewPager.setAdapter(adapter);
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 void printMessage(String message)
{
Toast.makeText(MainActivity.this,message,Toast.LENGTH_LONG).show();
}
}
Adapter Class
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter;
public class PagerAdapter extends FragmentStatePagerAdapter {
int mNumOfTabs;
public PagerAdapter(FragmentManager fm, int NumOfTabs) {
super(fm);
this.mNumOfTabs = NumOfTabs;
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
TabFragment1 tab1 = new TabFragment1();
return tab1;
case 1:
TabFragment2 tab2 = new TabFragment2();
return tab2;
default:
return null;
}
}
#Override
public int getCount() {
return mNumOfTabs;
}
}
so after posting more code I'm answering:
Implement some FragmentCommunication for both your Fragments:
//public class TabFragment1 extends Fragment implements FragmentCommunication{
public class TabFragment2 extends Fragment implements FragmentCommunication{
//public static final String TAG="TabFragment1";
public static final String TAG="TabFragment2";
...
#Override
public void onActivityCreated (Bundle savedInstanceState){
super.onActivityCreated(savedInstanceState);
if(getActivity() instanceOf MainActivity)
((MainActivity) getActivity()).registerFragmentCommunication(
TAG, this);
}
#Override
public void printMessage(String message){
Toast.makeText(getActivity(), TAG+" says: "+message,
Toast.LENGTH_SHORT).show();
}
}
note this line inside onActivityCreated:
((MainActivity) getActivity()).registerFragmentCommunication(TAG, this);
this means implemented FragmentCommunication, TAG will be unique key/name of Fragment and whole method is registration of your interface in Activity. so now you have to add registerFragmentCommunication method to your MainActivity and keep reference to passed interfaces, e.g. in HashMap:
HashMap<String, FragmentCommunication> fragmentCommunications =
new HashMap<String, FragmentCommunication>();
...
public void registerFragmentCommunication(String key, FragmentCommunication fc){
fragmentCommunications.put(key, fc);
}
so now you can access each FragmentCommunication of both fragments from your MainActivity, e.g by using method like this:
public void callFragmentCommunication(String key, String msg){
if(fragmentCommunications.get(key)!=null)
fragmentCommunications.get(key).printMessage();
}
callFragmentCommunication(TabFragment1.TAG, "hi!");
callFragmentCommunication(TabFragment2.TAG, "hi!");
method is public, so Fragments can call it simply like this:
//inside TabFragment1
if(isAdded() && getActivity()!=null &&
getActivity() instanceOf MainActivity &&
!getActivity().isFinishing())
((MainActivity) getActivity()).callFragmentCommunication(
TabFragment2.TAG, "hi!");
this will show Toast with text: "TabFragment2 says: hi!", which was called inside TabFragment1. now you may pass another kind of data as well :)
there is much more methods like communicating through FragmentStatePagerAdapter like here, passing Bundle arguments where fragments are initialized, additional feedback interfaces (e.g. returning true/false when message was passed) etc. Above is just very simplified way, good luck with improving it! :)
I have a Fragment with a method setName() that changes an EditText text, by means of the setText function.
What is the best way to call that method from the activity that hosts that fragment by means of a ViewPager?
In other words, how can I access a Fragment's methods (which change that fragment's layout, for example) from the Activity that hosts that fragment by means of a ViewPager?
I am asking this because I have tried several ways, but always with errors.
Best way to do this, just call
CallingFragmentName fragment = (CallingFragmentName) viewPager
.getAdapter()
.instantiateItem(viewPager, viewPager.getCurrentItem());
It will re-instantiate your calling Fragment, so that it will not throw null pointer exception.
I know this is a little late, but I ran into the same problem and maybe it will help others if you already solved it.
The first problem I found with ViewPager is that it is almost impossible to get a reference to a fragment. The fragments are created dynamically in getItem() and therefore you can't set an ID and they are automatically re-taged by the swicher, so you can't find it by tag either. There are some ways out there to do it, but they are all workarounds. (Update data in ListFragment as part of ViewPager)
The way I solved it was using essentially a double Callback. Fragment A has an interface implemented by the Main Activity, the Main Activity has a interface implemented by Fragment B. On e.g. a button clink in Fragment A the callback function in Main Activity is called, which than in turn calls the callback in Fragment B. Look at the code below. I hope I posted everything and it will help. btw, I have only tried this with a ViewPager, but I assume it would work with any sort of Fragment communication.
Main Avtivity java:
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
public class MainActivity extends FragmentActivity implements FragmentA.Caller {
SectionsPagerAdapter mSectionsPagerAdapter;
ViewPager mViewPager;
PassCallToB passOnToB = null;
FragmentManager myManager = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(mSectionsPagerAdapter);
}
public class SectionsPagerAdapter extends FragmentPagerAdapter {
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
MyManager = fm;
}
#Override
public Fragment getItem(int position) {
Fragment fragment = null;
if(position == 0) {
fragment = new FragmentA();
} else if (position == 1) {
fragment = new FragmentB();
passOnToB = (PassCallToB)fragment;
}
return fragment;
}
#Override
public int getCount() {
return 2;
}
#Override
public CharSequence getPageTitle(int position) {
switch (position) {
case 0:
return "Frag A";
case 1:
return "Frag B";
}
return null;
}
public void setCallback() {
List<Fragment> frags = myManager.getFragments();
for(Fragment fragment : frags) {
if(fragment instanceof FragmentB){
passOnToB = (PassCallToB)fragment;
}
}
}
}
public interface PassCallToB {
public void passItOn();
}
#Override
public void CallB() {
if(passOnToB instanceof Fragment)
passOnToB.passItOn();
else {
mSectionsPagerAdapter.setCallback();
passOnToB.passItOn();
}
}
}
Main Activity xml:
<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >
<android.support.v4.view.PagerTitleStrip
android:id="#+id/pager_title_strip"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:background="#33b5e5"
android:paddingBottom="4dp"
android:paddingTop="4dp"
android:textColor="#fff" />
</android.support.v4.view.ViewPager>
Fragment A java:
import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
public class FragmentA extends Fragment {
Button btnCallB = null;
Caller listener = null;
public FragmentA() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle inState) {
View rootView = inflater.inflate(R.layout.fragment_a, container, false);
btnCallB = (Button)rootView.findViewById(R.id.btnCallB);
btnCallB.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
listener.CallB();
}
});
return rootView;
}
public interface Caller {
public void CallB();
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if (activity instanceof FragmentActivity) {
listener = (Caller) activity;
} else {
throw new ClassCastException(activity.toString() + " must implemenet listener");
}
}
#Override
public void onDetach() {
super.onDetach();
listener = null;
}
}
Fragment A xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:text="This is Fragment A" />
<Button
android:id="#+id/btnCallB"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="#+id/textView1"
android:text="Call Fragment B" />
</RelativeLayout>
Fragment B Java:
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
public class FragmentB extends Fragment implements MainActivity.PassCallToB {
public FragmentB() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle inState) {
View rootView = inflater.inflate(R.layout.fragment_b, container, false);
return rootView;
}
#Override
public void passItOn() {
Toast.makeText(getActivity(), "Hello from B", Toast.LENGTH_SHORT).show();
}
}
Fragment B xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:text="This is Fragment B" />
</RelativeLayout>
You can access public methods within the fragments held by your ViewPager. You need to either (1) store a reference to the Fragment when you create it and add it to the list that will back your pager adapter or (2) you need to get a reference to the fragment from the pager adapter itself. For example:
Fragment fragmentA = null; //instance variable
fragmenA = new Fragment(); //whereever you instantiate your fragment
If your method is
public void setName(String args){
//do something
}
all you would do is call that method from the reference to the fragment held by your ViewPager
fragmentA.setName(args);
You pass whatever arguments you need just like calling a regular method. Note this ONLY works if you are calling a method within a fragment from its containing ViewPager or FragmentActivity. If you want to do the reverse, fragment to activity, you need to use an inerface.
Fragment
private static FragmentName instance;
public static synchronized FragmentName getInstance()
{
return instance;
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
instance=this;
....
}
public void methodName()
{...}
Activity
FragmentName.getInstance().methodName();