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.
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);
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 );
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.
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
}
Related
I'm trying to slide my ViewPager automatically via using TimerTask class, seems I do not have proper delay and period, it is sliding so fast. I tried all possible combinations of delay and period parameters without any luck, still so annoying fast sliding. Below is the code:
class SliderTimer extends TimerTask {
#Override
public void run() {
HomeActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
if (viewPager.getCurrentItem() < listSlides.size() - 1) {
viewPager.setCurrentItem(viewPager.getCurrentItem() + 1);
} else {
viewPager.setCurrentItem(0);
}
}
});
}
}
And the implementations:
Timer timer = new Timer();
timer.scheduleAtFixedRate(new HomeActivity.SliderTimer(), 10000, 10000);
Please guide me, what best can be done for the same.
I think Using Handler is better then TimerTask in this case if ViewPager can slide manually too.
First Create a Handler and Runnable Globally.
private Handler handler=new Handler();
private Runnable runnable=new Runnable() {
#Override
public void run() {
if(pagerSlider.getCurrentItem()==data.size()-1){
pagerSlider.setCurrentItem(0,false);
}else{
pagerSlider.setCurrentItem(pagerSlider.getCurrentItem()+1);
}
}
};
Post the runnable inside onPageChange.
pagerSlider.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener(){
#Override
public void onPageSelected(int position) {
super.onPageSelected(position);
handler.removeCallbacks(runnable);
handler.postDelayed(runnable,2000);
}
});
You need to post for first time Rest the listener will do. Change the delay as per your need :-
handler.postDelayed(runnable,2000);
I just realize that you might be asking about scrolling velocity . Well for this you need to use Customize Scroller. Go to This thread.
Try this one...
public static final long DELAY_MS = 2000;
public static final long PERIOD_MS = 4000;
new MyTimerHeader(DELAY_MS, PERIOD_MS, viewPager, images_total_length);
public MyTimerHeader(long DELAY_MS, long PERIOD_MS, final ViewPager slider1, final
int image_name) {
final int image_name1=image_name;
final Handler handler = new Handler();
final Runnable Update = new Runnable() {
public void run() {
int currentPage = slider1.getCurrentItem();
if (currentPage == image_name1 - 1) {
currentPage = 0;
}
else {
currentPage = currentPage + 1;
}
slider1.setCurrentItem(currentPage);
}
};
Timer timer = new Timer(); // This will create a new Thread
timer .schedule(new TimerTask() { // task to be scheduled
#Override
public void run() {
handler.post(Update);
}
}, DELAY_MS, PERIOD_MS);
}
Hi how i'am to back again my banner. if the gets last banner and back again to early banner. Thanks Before Guys
This example my code :
//Banner Variable
private int currentPage = -1;
private static final int NUM_PAGES = 0;
final Handler handler = new Handler();
final Runnable update = new Runnable() {
#Override
public void run() {
if (currentPage == NUM_PAGES - 1) {
currentPage = 0;
}
vpbanner.setCurrentItem(currentPage++, true);
}
};
Timer timer = new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
handler.post(update);
}
}, 1000, 2000);
Hope below code solve your problem :-
vpbanner.setCurrentItem(currentPage == 0 ? 4 : 0, true);
Hi my app needs a realtime data from database and I'm posting it on my TextView and I can't update the TextView as the database updates. I tried using Timer but its still the same.
Here is my code,
public void startTimer() {
//set a new Timer
timer = new Timer();
//initialize the TimerTask's job
initializeTimerTask();
timer.schedule(timerTask, 0, 5000);
}
private void stopTimerTask() {
//stop the timer, if it's not already null
if (timer != null) {
timer.cancel();
timer = null;
}
}
public void initializeTimerTask() {
timerTask = new TimerTask() {
public void run() {
runOnUiThread(new Runnable() {
#Override
public void run() {
final AcceptCars Cars = (AcceptCars) getIntent().getSerializableExtra("cars");
renterLat.setText(Cars.renterLat);
renterLng.setText(Cars.renterLng);
Log.d(TAG,renterLat.getText().toString());
Log.d(TAG,renterLng.getText().toString());
}
});
}
};
}
And here is where I get the Cars.renterLat and Cars.renterLng,
public class AcceptCars implements Serializable {
#SerializedName("renterLat")
public String renterLat;
#SerializedName("renterLng")
public String renterLng;
}
This is the logic you should be following. I used a Handler instead of a Timer. Inside the run method you need to call your webservice and get the updated value from the db. Use runOnUiThread to update the value to the UI from a Thread.
See the code below,
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Handler taskHandler = new Handler();
taskHandler.postDelayed(myTask, 0);
}
private Runnable myTask = new Runnable(){
public void run() {
queryDb();
// repeat the task
taskHandler.postDelayed(this, 1000);
}
};
private void queryDb(){
new Thread(new Runnable() {
#Override
public void run() {
// call you webservice
String data = callWebservice();
// parse the data in to AcceptCars pojo class
AcceptCars Cars = parseData(data);
//update the UI
runOnUiThread(new Runnable() {
#Override
public void run() {
renterLat.setText(Cars.renterLat);
renterLng.setText(Cars.renterLng);
}
});
}
}).start();
}
You can even use countdown timer.
Here is the link https://developer.android.com/reference/android/os/CountDownTimer.html
TimerTasks are really hard to deal with IMO. You should use a Handler and call postDelayed to do something after a certain amount of time.
Alternatively, you can try out this timer class I wrote:
import android.os.Handler;
public class Timer {
private Handler handler;
private boolean paused;
private int interval;
private Runnable task = new Runnable () {
#Override
public void run() {
if (!paused) {
runnable.run ();
Timer.this.handler.postDelayed (this, interval);
}
}
};
private Runnable runnable;
public int getInterval() {
return interval;
}
public void setInterval(int interval) {
this.interval = interval;
}
public void startTimer () {
paused = false;
handler.postDelayed (task, interval);
}
public void stopTimer () {
paused = true;
}
public Timer (Runnable runnable, int interval, boolean started) {
handler = new Handler ();
this.runnable = runnable;
this.interval = interval;
if (started)
startTimer ();
}
}
It is really simple to use.
You can use it like this:
Timer timer = new Timer(new Runnable() {
public void run() {
runOnUiThread(new Runnable() {
#Override
public void run() {
final AcceptCars Cars = (AcceptCars) getIntent().getSerializableExtra("cars");
renterLat.setText(Cars.renterLat);
renterLng.setText(Cars.renterLng);
Log.d(TAG,renterLat.getText().toString());
Log.d(TAG,renterLng.getText().toString());
}
}
}
}, 5000, true);
Trying to use a Timer to do run this 4 times with intervals of 10 seconds each.
I have tried stopping it with a loop, but it keeps crashing. Have tried using the schedule() with three parameters, but I didn't know where to implement a counter variable. Any ideas?
final Handler handler = new Handler();
Timer timer2 = new Timer();
TimerTask testing = new TimerTask() {
public void run() {
handler.post(new Runnable() {
public void run() {
Toast.makeText(MainActivity.this, "test",
Toast.LENGTH_SHORT).show();
}
});
}
};
int DELAY = 10000;
for (int i = 0; i != 2 ;i++) {
timer2.schedule(testing, DELAY);
timer2.cancel();
timer2.purge();
}
private final static int DELAY = 10000;
private final Handler handler = new Handler();
private final Timer timer = new Timer();
private final TimerTask task = new TimerTask() {
private int counter = 0;
public void run() {
handler.post(new Runnable() {
public void run() {
Toast.makeText(MainActivity.this, "test", Toast.LENGTH_SHORT).show();
}
});
if(++counter == 4) {
timer.cancel();
}
}
};
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
timer.schedule(task, DELAY, DELAY);
}
Why not use an AsyncTask and just have it Thread.sleep(10000) and the publishProgress in a while loop? Here is what it would look like:
new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
int i = 0;
while(i < 4) {
Thread.sleep(10000);
//Publish because onProgressUpdate runs on the UIThread
publishProgress();
i++;
}
// TODO Auto-generated method stub
return null;
}
#Override
protected void onProgressUpdate(Void... values) {
super.onProgressUpdate(values);
//This is run on the UIThread and will actually Toast... Or update a View if you need it to!
Toast.makeText(MainActivity.this, "test", Toast.LENGTH_SHORT).show();
}
}.execute();
Also as a side note, for longer term repetitive tasks, consider using AlarmManager...
for(int i = 0 ;i<4 ; i++){
Runnable runnableforadd ;
Handler handlerforadd ;
handlerforadd = new Handler();
runnableforadd = new Runnable() {
#Override
public void run() {
//Your Code Here
handlerforadd.postDelayed(runnableforadd, 10000); }
};
handlerforadd.postDelayed(runnableforadd, i);
}
I am using an ImageSwitcher with a TouchListener to change images from an array. Its working fine but i want it to switch images every x seconds or so, so that I can add imageSwitcher.setImageResource(imageList[curIndex]); to it.
Any suggestions?
Try this,
imageSwitcher.postDelayed(new Runnable() {
int i = 0;
public void run() {
imageSwitcher.setImageResource(
i++ % 2 == 0 ?
R.drawable.image1 :
R.drawable.mage2);
imageSwitcher.postDelayed(this, 1000);
}
}, 1000);
I think it is possible via TimerTask and Timer. please Try this code. I think It help you.
private Handler mHandler;
private Runnable mUpdateResults;
private Timer timerAnimate;
private TimerTask timerTask;
mHandler = new Handler();
mUpdateResults = new Runnable() {
public void run() {
AnimateandSlideShow();
}
};
int delay = 0;
int period = 15000;
timerAnimate = new Timer();
timerTask = new TimerTask() {
public void run() {
mHandler.post(mUpdateResults);
}
};
timerAnimate.scheduleAtFixedRate(timerTask, delay, period);
Public void AnimateandSlideShow()
{
imageSwitcher.setImageResource(imageList[curIndex]);
///Here You need To handle curIndex position.
}