I have the following situation:
I have an Activity
that hosts a ViewPager
, and I have 4 Fragments
;
the ViewPager
Basically what you want to do, is, find which fragment is currently being viewed when you swipe. And then, do your network calls.
You can take advantage of the ViewPager listeners to get notified when the user swipes to a new page. Docs : http://developer.android.com/reference/android/support/v4/view/ViewPager.OnPageChangeListener.html#onPageSelected(int)
This will give you the position of the View. But i'm assuming that what you want is the actual fragment, which is a bit more tricky.
But, this has been answered already in here : Is it possible to access the current Fragment being viewed by a ViewPager?
Hope it helps
Try this, in each fragment
override
below method and call your function when it is visible:
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if(isVisible()){
if(isVisibleToUser){
Log.d("MyTag","My Fragment is visible");
}else{
Log.d("MyTag","My Fragment is not visible");
}
}
}
EDIT
Note: This is only useful when using a FragmentPagerAdapter
or FragmentStatePagerAdapter
@Andrew Carl provide good idea. I also use the similar approach in my projects. I think it's more generalized.
Create an interface:
public interface ViewPagerFragment {
void onSelected();
void onDeselected();
}
And this common helper:
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.view.ViewPager;
public class ViewPagerHelper implements ViewPager.OnPageChangeListener {
private final FragmentManager mFragmentManager;
private final ViewPager mViewPager;
private int mSelectedPage;
public ViewPagerHelper(FragmentManager fragmentManager, ViewPager viewPager) {
mFragmentManager = fragmentManager;
mViewPager = viewPager;
mSelectedPage = -1;
}
@Override
public void onPageSelected(int position) {
Fragment previous = findViewPagerChildFragment(mFragmentManager, mViewPager, mSelectedPage);
if (previous instanceof ViewPagerFragment) {
((ViewPagerFragment) previous).onDeselected();
}
Fragment current = findViewPagerChildFragment(mFragmentManager, mViewPager, position);
if (current instanceof ViewPagerFragment) {
((ViewPagerFragment) current).onSelected();
}
mSelectedPage = position;
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
// empty
}
@Override
public void onPageScrollStateChanged(int state) {
// empty
}
public static Fragment findViewPagerChildFragment(FragmentManager manager, ViewPager pager, int position) {
if (pager == null) {
return null;
}
String tag = "android:switcher:" + pager.getId() + ":" + position;
return manager.findFragmentByTag(tag);
}
}
Now you may use them for any purpose:
Fragment:
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;
public class MyFragment extends Fragment implements ViewPagerFragment {
private boolean mSelected;
public static MyFragment newInstance(int position) {
Bundle args = new Bundle();
args.putInt("position", position);
MyFragment result = new MyFragment();
result.setArguments(args);
return result;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
TextView result = new TextView(inflater.getContext());
result.setText("Position: " + getPosition());
return result;
}
private int getPosition() {
return getArguments().getInt("position");
}
@Override
public void onSelected() {
mSelected = true;
start();
}
@Override
public void onDeselected() {
mSelected = false;
}
private void start() {
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
Activity activity = getActivity();
if (activity == null) {
return;
}
if (!mSelected) {
Toast.makeText(activity, "Fragment #" + getPosition() + " stopped", Toast.LENGTH_SHORT).show();
return;
}
TextView textView = (TextView) activity.findViewById(R.id.text);
if (textView != null) {
textView.setText("Fragment #" + getPosition() + " works: " + System.nanoTime() % 10000);
}
handler.postDelayed(this, 150);
}
}, 150);
}
}
Activity:
import android.os.Bundle;
import android.support.v4.view.ViewPager;
import android.support.v7.app.ActionBarActivity;
public class MainActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ViewPager viewPager = (ViewPager) findViewById(R.id.view_pager);
viewPager.setOnPageChangeListener(new ViewPagerHelper(getSupportFragmentManager(), viewPager));
viewPager.setAdapter(new MyAdapter(getSupportFragmentManager()));
}
}
Adapter:
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
public class MyAdapter extends FragmentPagerAdapter {
public MyAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
return MyFragment.newInstance(position);
}
@Override
public int getCount() {
return 42;
}
}
Check complete demo on github.
Let me introduce my idea to you:
getCurrentItem()
ViewPager
getItem(int position)
FragmentPagerAdapter
Return the Fragment associated with a specified position. You can define an Interface holding the method for Network I/O like
public Interface INetworkOnFragment{
void handle(){
//...
}
}
And implement it on your fragments and handle their own business logic (Network calls).
In main Activity ,set ViewPager.OnPageChangeListener
on ViewPager object like here:
pager.setOnPageChangeListener(new ViewPager.OnPageChangeListener(){
public void onPageScrollStateChanged(int state){
//donothing
}
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels){
//donothing
}
public void onPageSelected(int position){
INetworkOnFragment interface =(INetworkOnFragment) (pager.getAdapter().getItem(position));//get the current fragment and call handle method on it,dont need to care about whichever fragment it is .
interface.handle()
}
});
The most important is onPageSelected(int position)
,Inside the callback it get the current fragment and call handle method on it,dont need to care about whichever fragment it is .
Remember the handle method are called in Activity and not in fragments.All the Network calls are implemention of Interface,which make it easy to deal in Activity.
Check out the solution from my answer here
1) Create LifecycleManager
Interface The interface will have two methods (onPauseFragment
and onResumeFragment
) and each ViewPager
’s Fragment will implement it
2) Let each Fragment implement the interface
3) Implement interface methods in each fragment - start your AsyncTask
in onResumeFragment
4) Call interface methods on ViewPager
page change You can set OnPageChangeListener
on ViewPager
and get callback each time when ViewPager
shows another page
5) Implement OnPageChangeListener
to call your custom Lifecycle methods
Create a page into view method for FragmentStatePagerAdapter which calls a method on the fragment when the fragment comes into view.
Implement the OnPageIntoView interface in your fragment.
public class SomethingDifferent extends Fragment implements OnPageIntoView {
...
/*
* Called when this page comes into view
*
* @see com.gosylvester.bestrides.SettingFragmentPagerSupport.MyAdapter.
* OnPageIntoView#onPageIntoView()
*/
@Override
public void onPageIntoView() {
// this is just some random example code
// that does some heavy lifting it only runs when the fragment
// frist comes into view
if (fragmentActivity != null) {
if (lrc == null) {
lrc = new ClientServiceLocationRecorder(
new WeakReference<Context>(
fragmentActivity.getApplicationContext()),
lrcCallback);
}
// get a status message from the location recorder
lrc.sndMessageToLocationRecorder(ServiceLocationRecorder.MSG_RECORD_STATUS);
}
}
Create a custom FragmentStatePagerAdapter Override the setPrimaryItem method and if the object can be cast to the interface then call through the interface one time only.
public static class MyAdapter extends FragmentStatePagerAdapter {
public interface OnPageIntoView {
public void onPageIntoView();
}
private Fragment mCurrentFragment;
//bonus method to get the current fragment
public Fragment getCurrentFragment() {
return mCurrentFragment;
}
static int lastPosition = -1;
@Override
public void setPrimaryItem(ViewGroup container, int position,
Object object) {
//quickly determine if the primary item has changed
//and one time only call through interface
if (position != lastPosition) {
lastPosition = position;
//determine if this is fragment it should be but lets avoid
//class cast exceptions
if (Fragment.class.isAssignableFrom(object.getClass())) {
mCurrentFragment = ((Fragment) object);
//determine if the onPageIntoView interface has
//been implemented in the fragment
//if so call the onPageIntoView
if (OnPageIntoView.class.isAssignableFrom(mCurrentFragment
.getClass())) {
((OnPageIntoView) mCurrentFragment).onPageIntoView();
}
}
}
super.setPrimaryItem(container, position, object);
}
}