9

Sorry about my dumb title, I will describe it clearly below:

Situation

I have a ViewPager with 4 OnBoardingFragments inside. Each Fragment have exactly same layout which was inflatedfrom same xml file. This layout contain a Button which I called btnNext and I set the OnClickListener for it.

Function getItem of my PagerAdapter

@Override
public Fragment getItem(int position) {
    String title, description, button;
    int resource;
    boolean end = false;
    switch (position) {
        case 0:
            title = context.getString(R.string.on_boarding_title_1);
            description = context.getString(R.string.on_boarding_description_1);
            resource = R.drawable.on_boarding_bg_0;
            button = context.getString(R.string.on_boarding_button_1);
            break;
        case 1:
            title = context.getString(R.string.on_boarding_title_2);
            description = context.getString(R.string.on_boarding_description_2);
            resource = R.drawable.on_boarding_bg_1;
            button = context.getString(R.string.on_boarding_button_2);
            break;
        case 2:
            title = context.getString(R.string.on_boarding_title_3);
            description = context.getString(R.string.on_boarding_description_3);
            resource = R.drawable.on_boarding_bg_2;
            button = context.getString(R.string.on_boarding_button_3);
            break;
        default:
            title = context.getString(R.string.on_boarding_title_4);
            description = context.getString(R.string.on_boarding_description_4);
            resource = R.drawable.on_boarding_bg_3;
            button = context.getString(R.string.on_boarding_button_4);
            end = true;
    }
    return OnBoardingFragment.newInstance(title, description, resource, button, end);
}

@Override
public int getCount() {
    return 4;
}

Functions of OnBoardingFragment:

public static OnBoardingFragment newInstance(String title, String description, int resource,
                                             String button, boolean end) {
    Bundle bundle = new Bundle();
    bundle.putString(EXTRA_TITLE, title);
    bundle.putString(EXTRA_DESCRIPTION, description);
    bundle.putInt(EXTRA_IMAGE, resource);
    bundle.putString(EXTRA_BUTTON, button);
    bundle.putBoolean(EXTRA_END, end);
    OnBoardingFragment fragment = new OnBoardingFragment();
    fragment.setArguments(bundle);
    return fragment;
}

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Bundle bundle = getArguments();
    if (bundle != null) {
        title = bundle.getString(EXTRA_TITLE);
        description = bundle.getString(EXTRA_DESCRIPTION);
        button = bundle.getString(EXTRA_BUTTON);
        end = bundle.getBoolean(EXTRA_END);
        imageResource = bundle.getInt(EXTRA_IMAGE);
        show log ---> Log.e(this.toString() + "/" + end + "/" + title);
    }
}

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    View rootView = inflater.inflate(R.layout.on_boarding_fragment, container, false);
    TextView tvTitle = (TextView) rootView.findViewById(R.id.tv_title);
    TextView tvDescription = (TextView) rootView.findViewById(R.id.tv_description);
    TextView btnDiscovery = (TextView) rootView.findViewById(R.id.tv_discovery);
    imageView = (ImageView) rootView.findViewById(R.id.iv_image);
    final Button btnNext = (Button) rootView.findViewById(R.id.btn_next);
    if (end) {
        btnDiscovery.setVisibility(View.VISIBLE);
        btnDiscovery.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startRegionActivity();
            }
        });
    }
    btnNext.setText(button);
    btnNext.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            show log ---> Log.e(OnBoardingFragment.this.toString() + "/" + end + "/" + title + "/" + ((Button)v).getText());
            if (end) {
                ((SplashActivity) getActivity()).gotoNextPage();
            } else {
                startLoginActivity();
            }
        }
    });
    tvTitle.setText(title);
    tvDescription.setText(description);
    ImageUtils.loadBitmap(getActivity(), imageResource, imageView, 0.8f, new ImageUtils.LoadBitmapCallback() {
        @Override
        public void onLoadComplete(ImageView imageView) {

        }

        @Override
        public void onLoadFail() {

        }
    });

    return rootView;
}

The problem is

When my app started it show the first Fragment, then I pressed the Button and trigger onItemClick() method, and the method was referenced to the last Fragment.

Log when create Fragment

OnBoardingFragment{a8ede47 id=0x7f10013b}/false/XIN CHÀO!
OnBoardingFragment{8787674 #0 id=0x7f10013b}/false/BÁN LIỀN TAY, KIẾM TIỀN NGAY
OnBoardingFragment{119f79d #1 id=0x7f10013b}/false/CHAT MIỄN PHÍ
OnBoardingFragment{1ee7412 #2 id=0x7f10013b}/true/NGƯỜI THẬT, HÀNG THẬT

Log when onClickListener() was triggered

OnBoardingFragment{1ee7412 #2 id=0x7f10013b}/true/NGƯỜI THẬT, HÀNG THẬT/Đi chợ ngay nào!

Log when the btnNext was initialized:

button: android.support.v7.widget.AppCompatButton{17c69e97 VFED..C. ......I. 0,0-0,0 #7f1002c8 app:id/btn_next}
button: android.support.v7.widget.AppCompatButton{31941c VFED..C. ......I. 0,0-0,0 #7f1002c8 app:id/btn_next}
button: android.support.v7.widget.AppCompatButton{30765b87 VFED..C. ......I. 0,0-0,0 #7f1002c8 app:id/btn_next}
button: android.support.v7.widget.AppCompatButton{9cf19e VFED..C. ......I. 0,0-0,0 #7f1002c8 app:id/btn_next}

Question

Why it happen and how to resolve?

mr.icetea
  • 2,607
  • 3
  • 24
  • 42
  • I would guess your switch is the problem, Log the value received, since you use `default` for the last element, the `int position` is probably not the one expected. Did you implement the getCount() methods for the adapter ? – AxelH Oct 13 '16 at 08:47
  • @AxelH yes I overrode the `getCount()` method and simplicity return 4. – mr.icetea Oct 13 '16 at 08:55
  • @AxelH I think the switch statement is fine. All the fragments were initialized correctly. – mr.icetea Oct 13 '16 at 09:02
  • @AxelH I will try it. – mr.icetea Oct 13 '16 at 09:05
  • I suggest you to store the reference of the first created fragment (as a member variable) in your onCreate() callback. – Michele Oct 13 '16 at 09:15
  • If understood well, you need a reference to the visible fragment when you press the button, while you get the always last instead. So, why don't you simply save a reference to the visible fragment so you can use it as soon as you press the button? – Michele Oct 13 '16 at 09:30
  • @AxelH seem to be not working. I try to change the default case to `case 3`, but nothing change. – mr.icetea Oct 13 '16 at 09:35
  • @Michele actually I have a solution for my problem. But I don't understand why it happen. Could you explain it? – mr.icetea Oct 13 '16 at 09:37
  • 1
    Look at [this](http://stackoverflow.com/a/21751491/1361250) answer. Simply save the currently visible fragment (as a static variable, for example). So when you tap on the button you are always able to get the fragment you are seeing at the moment. – Michele Oct 13 '16 at 09:46
  • @AxelH the position value is correct 0,1,2,3. And getItem() only called one for initialize each fragment. – mr.icetea Oct 13 '16 at 09:50
  • Sorry, I thought `gotoNextPage()` used the getItem()... but the problem is before that. I wonder if ... the xml doesn't recycle the layout so each fragment use the same instance of the button. And so the last call of `setOnClickListener` is the last Fragment so this is his Listener that is used. I can't test that right now .. but you can find out in the debugger, check the instance references of each button (should be the same) – AxelH Oct 13 '16 at 10:15
  • @AxelH Look at my update. Seem each `Fragment` has a different instance of `btnNext` – mr.icetea Oct 13 '16 at 10:29
  • How can you make sure that when you click the button,the fragment shown is the first one rather than the last? – Qian Sijianhao Oct 13 '16 at 10:40
  • This would be my next guess too. If the button are different, this is clearly using the instance of the last fragment... (I am clearing the comment section ;) ) – AxelH Oct 13 '16 at 10:45
  • Try to click the rest 'btnNext' on the other fragments and see what the log is.Maybe that will provide some clues. – Qian Sijianhao Oct 13 '16 at 10:52
  • @QianSijianhao I tried to press `btnNext` of all `Fragment` but they all referenced to the last `Fragment`. – mr.icetea Oct 13 '16 at 10:54
  • Can you provide more codes so that I can run the fragments on my computer? – Qian Sijianhao Oct 13 '16 at 10:58
  • @QianSijianhao you can simply create an `Activity` contain a `ViewPager`. Then create `Fragment`s with simple `xml` file contain a `Button`. – mr.icetea Oct 13 '16 at 11:03
  • Got it.I will take some minutes to test this strange problem.Letter I will tell you the answer. – Qian Sijianhao Oct 13 '16 at 11:06
  • I guess the "title","description","button","imageResource" are static in your OnBoardingFragment. – Qian Sijianhao Oct 13 '16 at 11:19
  • @QianSijianhao no they are fields. – mr.icetea Oct 13 '16 at 11:27
  • As you said,I create an Activity contain a ViewPager and each fragment with a button.But the demo performs well on my phone.I think something is wrong with the code that you didn't show. – Qian Sijianhao Oct 13 '16 at 11:31
  • @QianSijianhao did you check the the `Fragment` instance reference to the `onClick()` method. – mr.icetea Oct 13 '16 at 11:32
  • Yes.I have checked the Fragment instance reference to the onClick() method.And the button matches with fragment very well. – Qian Sijianhao Oct 13 '16 at 11:38
  • Looks like a logic problem - inside `btnNext's OnClickListener`, you are checking if `end` is `true` and going to the next page. Shouldn't you be checking for `!end` instead? – Vikram Oct 14 '16 at 05:15
  • @Vikram you are right but I do that for debug. – mr.icetea Oct 14 '16 at 06:08
  • I see nothing obviously wrong in the code you posted. Can you post the adapter declaration and it's member variable as well? Try adding an `OnPageChangeListener` to your pager and log out the currently selected page in the `onPageSelected` callback. – Gary Bak Oct 14 '16 at 14:02
  • Every thing is correct. I make everything the same as you and everything is correct. The strange part is why all of your fragments become created ?!?! Did you call viewpager.setOffscreenPageLimit(4); ??? Also in your fragment, where do you define "imageView" ?! please put a full code from your classes not part of them. it would help us to solve your problem easier – Omid Heshmatinia Oct 15 '16 at 06:38
  • @Smartiz yes I called `viewpager.setOffscreenPageLimit(4);`. And `ImageView` was declared as a field. – mr.icetea Oct 15 '16 at 09:41
  • @mr.icetea Make sure you have set visibility as GONE for btn_next in your fragment layout – Jaiprakash Soni Oct 17 '16 at 11:24
  • 1
    Post some more code. With what you shared it's impossibile to help you – Mimmo Grottoli Oct 17 '16 at 23:04
  • @MimmoGrottoli Which part of code do you when to see? – mr.icetea Oct 18 '16 at 02:54
  • The Activity or the frafment containing the pager, the adapter, the layot file. – Mimmo Grottoli Oct 18 '16 at 05:25
  • Post your `gotoNextPage()` method code – Burhanuddin Rashid Oct 19 '16 at 11:39

5 Answers5

2

Please refer the sample in the below link for using view pager with multiple fragments: https://guides.codepath.com/android/ViewPager-with-FragmentPagerAdapter

Bhagya
  • 114
  • 6
0

When the user clicks on the button, send that event back to the activity (or where you have a reference of the viewpager). From there, you should check what fragment in the viewpager is visible (see Determine when a ViewPager changes pages and How to determine when Fragment becomes visible in ViewPager) and then you will know what to do with that event.

Community
  • 1
  • 1
Yair Kukielka
  • 10,686
  • 1
  • 38
  • 46
0

you can use a listener interface for getting the fragment and create a method for getting the position and send it on where you have declare the viewpager by 1. first create an anonymous object of that interface in that fragment 2. secondly pass that object to PagerAdapter 3. thirdly you can use that object in the PagerAdapter and call the method which used in the interface with the fragment position 4. you can include the fragment layout handling code on the method inside the anonymous innerclass of that interface

please try this,it will works. hope you can understand what i have said.

Jijo
  • 510
  • 7
  • 13
  • Using listener is a way I did for resolve my problem. But my question is "Why it happen", could you explain it? – mr.icetea Oct 18 '16 at 02:53
  • It is because of the boolean value return true and go to the default value, so omit default value and add a case value to 3 include the code of default to it. and set the flag value true in case 3:, hope it will works, try it – Jijo Oct 18 '16 at 04:10
  • mr.icetea , please put break in default – Jijo Oct 18 '16 at 04:28
0

Use case 3: with a break at the end and in default, just put a single break and no other statement.

Amit Tiwari
  • 3,684
  • 6
  • 33
  • 75
0

add break statement in default block and also pass argument end = false in case 0,1,2

Chandramouli
  • 76
  • 1
  • 6