25


I want to schedule an action to change automatically my ViewPager pages. I've tried:

@Override
    public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    ...

    swipeTimer = new Timer();
    swipeTimer.schedule(new TimerTask() {

         @Override
         public void run() {
            if (currentPage == NUM_PAGES) {
                currentPage = 0;
            }
            featureViewPager.setCurrentItem(currentPage++, true);
         }
    }, 100, 500);

but I'm always getting:

E/AndroidRuntime(5381): FATAL EXCEPTION: Timer-0
E/AndroidRuntime(5381): java.lang.IllegalStateException: Must be called from main thread of process

I'm already in main thread right? How can I solve this?
Thanks for your time.

EDIT:
====================================


Thanks for all your answers. Based on these responses I came across 2 solutions:
Solution 1:

swipeTimer = new Timer();
            swipeTimer.schedule(new TimerTask() {

                @Override
                public void run() {
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            if (currentPage == NUM_PAGES) {
                                currentPage = 0;
                            }
                            featureViewPager.setCurrentItem(currentPage++, true);
                        }
                    });
                }
            }, 500, 3000);

Solution 2:

final Handler handler = new Handler();
                final Runnable Update = new Runnable() {
                    public void run() {
                        if (currentPage == NUM_PAGES) {
                            currentPage = 0;
                        }
                        featureViewPager.setCurrentItem(currentPage++, true);
                    }
                };

            swipeTimer = new Timer();
            swipeTimer.schedule(new TimerTask() {

                @Override
                public void run() {
                    handler.post(Update);
                }
            }, 500, 3000);

Which one is better or they are the same?
Thanks once again.

GuilhE
  • 11,591
  • 16
  • 75
  • 116
  • you can use broadcast receiver to change the page on specific time, register receiver and call it when u want to change the page – abhi Jun 18 '13 at 11:34
  • 1
    check [this](http://stackoverflow.com/a/9738560/2479292) out. – zozelfelfo Jun 18 '13 at 11:35
  • You should use a ViewAnimator (e.g. ViewFlipper: http://developer.android.com/reference/android/widget/ViewFlipper.html) and it you will make work easier or use a Handler(built in the main thread: http://developer.android.com/reference/android/os/Handler.html) – Laviniux Jun 18 '13 at 11:38
  • 1
    You may use this code for auto slide http://stackoverflow.com/a/19951862/2987284 – Raghu Nov 19 '13 at 12:54
  • https://github.com/ajaydewari/AutoSlideViewpager – HAXM May 11 '17 at 12:59

4 Answers4

63

If you want to use thread in the main UI then you need to use a hander to hand it.

Handler handler = new Handler();

        Runnable update = new Runnable()  {

            public void run() {
                if ( currentPage == NUM_PAGES ) {

                    currentPage = 0;
                }
                featureViewPager.setCurrentItem(currentPage++, true);
            }
        };


        new Timer().schedule(new TimerTask() {

            @Override
            public void run() {
                handler.post(update);
            }
        }, 100, 500);
khushbu
  • 382
  • 1
  • 3
  • 15
Md Abdul Gafur
  • 6,213
  • 2
  • 27
  • 37
  • 1
    new Handler().postDelayed(new Runnable() { public void run() { if (currentPage == NUM_PAGES - 1) { currentPage = 0; } featureViewPager.setCurrentItem(currentPage++, true); } },3000); Will this work ?? – Sagar Devanga Jan 21 '16 at 09:40
  • 1
    how to change the speed?? – Rishabh Srivastava Jun 02 '16 at 06:54
  • 2
    I have a maximum of 3 pages, `if (currentPage == NUM_PAGES - 1) { currentPage = 0; } featureViewPager.setCurrentItem(currentPage++, true);` I found this one wrong, my pages index was 0,1,2 - it will swipe in the second one, but will not continue to the 2 (page index). – RoCkDevstack Aug 29 '16 at 10:14
  • 1
    @RoCk even I faced the the same issue I have max 4 pages, And my last one was not loading so I changed the condition to `if (currentPage == NUM_PAGES)`. Now it is working. – AkshayT Feb 14 '18 at 07:07
  • i have the same problem, i have 3 images to slide, i have change to this: if (holder.currentPage == holder.dotscount - 0) { holder.currentPage = 0; } its working now. All the images are sliding. – Raj Bedi Feb 28 '19 at 06:25
10

Easiest way how to solve it is to create an postDelayed runnable

    private Handler mHandler;
    public static final int DELAY = 5000;

    Runnable mRunnable = new Runnable()
    {

        @Override
        public void run()
        {
            //TODO: do something like mViewPager.setCurrentPage(mIterator);
            mHandler.postDelayed( mRunnable , DELAY );
        }
    };

as You can see it will loop infinitelly. When you want to stop it, just simply call

        mHandler.removeCallbacks( mRunnable );
Klawikowski
  • 605
  • 3
  • 11
2

The TimerTask will runs on it's own thread ( = not the UI thread).

You can simply call setCurrentItem directly on the main thread using a Handler.

ddewaele
  • 22,363
  • 10
  • 69
  • 82
0

For the kotlin extension lover. This can be helpful on viewPage2 auto page change

fun ViewPager2.enableAutoScroll(totalPages: Int): Timer {
    val autoTimerTask = Timer()
    var currentPageIndex = currentItem
    autoTimerTask.schedule(object : TimerTask() {
        override fun run() {
            currentItem = currentPageIndex++
            if (currentPageIndex == totalPages) currentPageIndex = 0
        }
    }, 0, DELAY_FOUR_SECONDS)

    // Stop auto paging when user touch the view
    getRecyclerView().setOnTouchListener { _, event ->
        if (event.action == MotionEvent.ACTION_DOWN) autoTimerTask.cancel()
        false
    }

    return autoTimerTask // Return the reference for cancel
}

fun ViewPager2.getRecyclerView(): RecyclerView {
    val recyclerViewField = ViewPager2::class.java.getDeclaredField("mRecyclerView")
    recyclerViewField.isAccessible = true
    return recyclerViewField.get(this) as RecyclerView
}
Jayesh
  • 101
  • 6