I'm trying to update my digital clock using timertask. I have created a function called updateClock() which sets the hours and minutes to the current time but I haven't been able to get it to run periodically. From what I've read in other answers one of the best options is to use timertask however I haven't been able to make any example I found online work inside an Android activity.
This is what I've written so far:
public class MainActivity extends Activity {
TextView hours;
TextView minutes;
Calendar c;
int cur_hours;
int cur_minutes;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.clock_home);
hours = (TextView) findViewById(R.id.hours);
minutes = (TextView) findViewById(R.id.minutes);
updateClock();
}
public void updateClock() {
c = Calendar.getInstance();
hours.setText("" + c.get(Calendar.HOUR));
minutes.setText("" + c.get(Calendar.MINUTE));
}
public static void init() throws Exception {
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
updateClock(); // ERROR
}
}, 0, 1 * 5000);
}
}
How can I make it work?
Use runOnUiThread for updating Ui from Timer Thread
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
MainActivity.this.runOnUiThread (new Runnable() {
public void run() {
updateClock(); // call UI update method here
}
}));
}
}, 0, 1 * 5000);
}
if you just need updates every minute, you can also listen to the ACTION_TIME_TICK broadcast event.
private boolean timeReceiverAttached;
private final BroadcastReceiver timeReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
updateClock();
}
};
private Handler handler = new Handler();
#Override
protected void onResume() {
super.onResume();
updateClock();
if (!timeReceiverAttached) {
timeReceiverAttached = true;
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_TIME_TICK);
filter.addAction(Intent.ACTION_TIME_CHANGED);
filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
registerReceiver(timeReceiver, filter, null, handler);
}
}
#Override
protected void onPause() {
super.onPause();
if (timeReceiverAttached) {
unregisterReceiver(timeReceiver);
timeReceiverAttached = false;
}
}
OR, periodically post the Runnable to the Handler of UI thread. Also, pause and resume tasks to save battery.
public class MyActivity extends Activity {
private final Handler mHandler = new Handler();
private final Timer mTimer = new Timer();
#Override
protected void onResume() {
super.onResume();
mTimer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
mHandler.post(new Runnable() {
#Override
public void run() {
//---update UI---
}
});
}
},0,5000);
}
#Override
protected void onPause() {
super.onPause();
mTimer.cancel();
}
}
Related
I am trying to create an AsyncTask for following function:
private void updateStreamImageRequest() {
countDownTimer = new CountDownTimer(10000, 2000) {
#Override
public void onTick(long millisUntilFinished) {
imageRequest();
}
#Override
public void onFinish() {
countDownTimer.start();
}
};
}
I do not have much knowledge in AsyncTaskand I am struggling to make it work. The AsyncTask shall continueally run a get request.
So far I have done this so far but it does not work:
public void getImgAsync() {
new requestAsyncTask();
}
public class requestAsyncTask extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) {
countDownTimer = new CountDownTimer(10000, 2000) {
#Override
public void onTick(long millisUntilFinished) {
API_StreamImage_Request();
}
#Override
public void onFinish() {
countDownTimer.start();
}
};
return null;
}
}
So do it this way -
Create your Countdown timer that runs for 10 seconds. So it will finish after 10 seconds. Then in finish method call your Asynctask to fetch in background.
countDownTimer = new CountDownTimer(10000, 5000) {
#Override
public void onTick(long millisUntilFinished) {
}
#Override
public void onFinish() {
new requestAsyncTask().execute();
}
};
countDownTimer.start();
class requestAsyncTask extends AsyncTask<Void, Void, Void> {
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
countDownTimer.cancel();
countDownTimer.start();
}
#Override
protected Void doInBackground(Void... params) {
API_StreamImage_Request();
return null;
}
}
You might have to create a global variable of your countdown timer so that you can access it inside your asynctask class. Or you can even pass it as well if you want.
You can also use a Handler for this.
private int mInterval = 10000;
private Handler mHandler = new Handler();
Runnable requestCaller = new Runnable() {
#Override
public void run() {
try {
new requestAsyncTask().execute();
} finally {
mHandler.postDelayed(requestCaller, mInterval);
}
}
};
Or a Timer
new Timer().scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
new requestAsyncTask().execute();
}
},0, 10000);
I am a begineer in android app development, i have stoptimertask function in my mainactivity, and a button stop in another activity. What i want to do is when i press this stop button from my 2nd activity(which is maps.class), i want the stoptimertask to stop i.e. stop the tasks. However the app crashes.
Here is my code of mainactivity.java
public class MainActivity extends FragmentActivity{
protected static final int CONTACT_PICKER_RESULT = 0;
int count=0;
Timer timer;
TimerTask timerTask;
final Handler handler = new Handler();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
sendBtn.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
startTimer();
sendSMSMessage();
Intent toAnotherActivity = new Intent(MainActivity.this, maps.class);
startActivityForResult(toAnotherActivity, 0);
}
});
}
public void startTimer() {
timer = new Timer();
initializeTimerTask();
if(radioBtnten.isChecked()==true)
timer.schedule(timerTask, 5000, 10000);
// if(radioBtn2.isSelected()==true)
else if(radioBtnone.isChecked()==true)
timer.schedule(timerTask, 5000, 1000);
}
public void initializeTimerTask() {
timerTask = new TimerTask() {
public void run() {
handler.post(new Runnable() {
public void run() {
Toast.makeText(getApplicationContext(), "your message has been sent, the message(s) sent are:-"+count++,Toast.LENGTH_LONG).show();
sendSMSMessage();
}
});
}
};
}
public void stoptimertask(View v)
{
//stop the timer, if it's not already null
Toast.makeText(getApplicationContext(), "Stop button pressed",Toast.LENGTH_LONG).show();
if (timer != null)
{
timer.cancel();
timer = null;
count = 0;
}
MainActivity.this.finish();
}
}
Here is the maps.java(2nd activity)
public class maps extends FragmentActivity implements LocationListener {
MainActivity call=new MainActivity();
GoogleMap googleMap;
Button stop;
Timer timer;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//show error dialog if GoolglePlayServices not available
if (!isGooglePlayServicesAvailable()) {
finish();
}
setContentView(R.layout.maps);
stop = (Button)findViewById(R.id.stop);
stop.setOnClickListener(new View.OnClickListener()
{
public void onClick(View aView)
{
Intent toAnotherActivity = new Intent(aView.getContext(), MainActivity.class);
startActivityForResult(toAnotherActivity, 0);
Toast.makeText(getApplicationContext(), "Stop button pressed",Toast.LENGTH_LONG).show();
maps.this.finish();
call.stoptimertask(aView);
}
});
here is the logcat
FATAL EXCEPTION: main
Process: com.example.textmessage, PID: 19869
java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.Context android.content.Context.getApplicationContext()' on a null object reference
at android.content.ContextWrapper.getApplicationContext(ContextWrapper.java:105)
at com.example.textmessage.MainActivity.stoptimertask(MainActivity.java:167)
at com.example.textmessage.maps$1.onClick(maps.java:49)
at android.view.View.performClick(View.java:4756)
at android.view.View$PerformClick.run(View.java:19749)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5221)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
Best use for this kind of scenario is Singleton pattern.
MainActivity.java
public class MainActivity extends FragmentActivity
{
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initializeTools();
// Find reference of "sendBtn" with "findViewById" or other stuff
sendBtn.setOnClickListener(
new View.OnClickListener()
{
#Override
public void onClick(View v)
{
startTimer();
}
});
// Rest of your code
}
private void initializeTools()
{
// Give context to Timers instance
Timers.getInstance().giveContext(this);
}
private void startTimer()
{
// Starts the timer when you click on "sendBtn"
Timers.getInstance().startTimers();
}
}
Timers.java
public class Timers
{
private final ScheduledExecutorService scheduledExecutorService;
private final Runnable myTask;
private ScheduledFuture<?> futureTask;
private int count = 0;
private Context _context;
private static volatile Timers _timers;
private Timers()
{
super();
// Your "futureTask manager"
scheduledExecutorService = Executors.newScheduledThreadPool(5);
// Good use is to instanciate task since it won't change on runtime
myTask = new Runnable()
{
#Override
public void run()
{
// Your code to run after the delay has expired
Toast.makeText(_context, "your message has been sent, the message(s) sent are:-" + count++, Toast.LENGTH_LONG).show();
// Same as the whole example, you should use the Singleton pattern to handle communications thanks to the Singleton class "Communicator"
Communicator.getInstance().sendSMSMessage();
}
};
}
// Allow only one instance of the class running. Anyone can get reference of the class with the static function Timers.getInstance();
public static Timers getInstance()
{
if (Timers._timers == null)
{
synchronized (Timers.class)
{
if (Timers._timers == null)
{
Timers._timers = new Timers();
}
}
}
return Timers._timers;
}
// For Toasts and other useful stuff
public void giveContext(Context context)
{
this._context = context;
}
// Stop the timer
public void stopTimer()
{
if (futureTask != null)
{
futureTask.cancel(true);
}
}
// Starts the task to happen in 10 seconds
public void startTimers()
{
futureTask = scheduledExecutorService.schedule(myTask, 10, TimeUnit.SECONDS);
}
}
And inside any class of your application, use Timers.getInstance().stopTimer(); to stop the timer and Timers.getInstance().startTimer(); to start it again.
Did you try?
mTimer = new Runnable() {
#Override
public void run() {
**return;**
When i play the app and then close after sometimes the apps Music again starts in background
Any help will be appreciated
Thanks
I have an activity class having Code
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.mygame);
final Handler mHandler = new Handler();
Intent svc=new Intent(this, MusicService.class);
startService(svc);
// Create runnable for posting
final Runnable mUpdateResults = new Runnable() {
public void run() {
AnimateandSlideShow();
}
};
int delay = 500; // delay for 1 sec.
int period = 6000; // repeat every 4 sec.
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
mHandler.post(mUpdateResults);}
}, delay, period);}
public void onClick(View v) {
finish();
android.os.Process.killProcess(android.os.Process.myPid());
Intent srv=new Intent(SliderActivity.this, MusicService.class);
stopService(srv); }
Try Removing Callbacks of your handler in the onStop Method in your activity class :
#Override
protected void onStop() {
super.onStop();
mHandler.removeCallbacksAndMessages(null);
timer = null;
mHandler= null;
}
Hope it helps.
I am trying to develop an application, that uses threads to implement slideshow. I am retrieving the image path from SQLite and displaying them on the ImageView. The problem, where I got struck is, I got confused and so I am unable to understand, from which thread I am calling images() method, where I am actually implementing the slideshow.
I got the Logcat as follows -
09-03 13:47:00.248: E/AndroidRuntime(10642): FATAL EXCEPTION: Thread-151
09-03 13:47:00.248: E/AndroidRuntime(10642): android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
09-03 13:47:00.248: E/AndroidRuntime(10642): at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:5908)
09-03 13:47:00.248: E/AndroidRuntime(10642): at com.example.fromstart.MainActivity.images(MainActivity.java:90)
09-03 13:47:00.248: E/AndroidRuntime(10642): at com.example.fromstart.MainActivity$2.run(MainActivity.java:59)
09-03 13:47:00.248: E/AndroidRuntime(10642): at java.lang.Thread.run(Thread.java:841)
MainActivity.java:
public class MainActivity extends Activity
{
ImageView jpgView;
TextView tv;
//adapter mDbAdapter;
adapter info = new adapter(this);
String path;
Handler smHandler = new Handler()
{
public void handleMessage(Message msg)
{
TextView myTextView =
(TextView)findViewById(R.id.textView1);
myTextView.setText("Button Pressed");
}
};
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
jpgView = (ImageView)findViewById(R.id.imageView1);
tv = (TextView) findViewById(R.id.textView1);
}
#Override
public boolean onCreateOptionsMenu(Menu menu)
{
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
final Runnable runnable = new Runnable()
{
public void run()
{
images();
}
};
int delay = 1000; // delay for 1 sec.
int period = 15000; // repeat every 4 sec.
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask()
{
public void run()
{
smHandler.post(runnable);
}
}, delay, period);
Thread mythread = new Thread(runnable);
mythread.start();
return true;
}
public void handleMessage(Message msg)
{
String string = "sample";
TextView myTextView = (TextView)findViewById(R.id.textView1);
myTextView.setText(string);
}
public void images()
{
try
{
for(int i=0;i<=20;i++)
{
path = info.getpath();
Bitmap bitmap = BitmapFactory.decodeFile(path);
jpgView.setImageBitmap(bitmap);
}
}
catch(NullPointerException er)
{
String ht=er.toString();
Toast.makeText(getApplicationContext(), ht, Toast.LENGTH_LONG).show();
}
}
}
I am a newbie to android, just now started working on Threads. If you find any mistakes in my code, please point out those and please suggest me, the right way to deal with this problem.
Thanks in advance.
UPDATE:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final Handler mHandler = new Handler();
// Create runnable for posting
runOnUiThread(new Runnable()
{
public void run()
{
images();
}
});
int delay = 1000; // delay for 1 sec.
int period = 15000; // repeat every 4 sec.
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask()
{
public void run()
{
images();
}
}, delay, period);
}
public void images()
{
try
{
Toast.makeText(getApplicationContext(), "1", Toast.LENGTH_LONG).show();
path = info.getpath();
Toast.makeText(getApplicationContext(), "2", Toast.LENGTH_LONG).show();
Bitmap bitmap = BitmapFactory.decodeFile(path);
Toast.makeText(getApplicationContext(), "3", Toast.LENGTH_LONG).show();
jpgView.setImageBitmap(bitmap);
Toast.makeText(getApplicationContext(), "4", Toast.LENGTH_LONG).show();
}
catch(NullPointerException er)
{
String ht=er.toString();
Toast.makeText(getApplicationContext(), ht, Toast.LENGTH_LONG).show();
}
}
}
You cannot update/access ui from from a thread.
You have this
public void run()
{
images();
}
And in images you have
jpgView.setImageBitmap(bitmap);
You need to use runOnUiThread for updating ui.
runOnUiThread(new Runnable() {
#Override
public void run() {
// do something
}
});
TimerTask also runs on a different thread. So you have use a Handler for updati ui.
You can use a handler.
Edit:
Handler m_handler;
Runnable m_handlerTask ;
m_handler = new Handler();
m_handlerTask = new Runnable()
{
#Override
public void run() {
// do something. call images()
m_handler.postDelayed(m_handlerTask, 1000);
}
};
m_handlerTask.run();
If you still wish to use a timer task use runOnUiThread
timer.scheduleAtFixedRate(new TimerTask()
{
public void run()
{
runOnUiThread(new Runnable() {
#Override
public void run() {
images();
}
});
}
}, delay, period);
To update UI from any other Thread you must use
runOnUiThread(<Runnable>);
which will update your UI.
Example:
runOnUiThread(
new Runnable()
{
// do something on UI thread Update UI
});
public class MainActivity extends Activity
{
int min, sec;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
min = 5;
sec = 0;
final TextView timer1 = (TextView) findViewById(R.id.timer1);
timer1.setText(min + ":" + sec);
Thread t = new Thread() {
public void run() {
sec-=1;
if (sec<0) {
min-=1;
sec=59;
}
timer1.setText(min + ":" + sec);
try
{
sleep(1000);
}
catch (InterruptedException e)
{}
}
};
t.start();
}
}
This is a code for a Thread in Java but it doesn't work. Can you help me?
Its a Timer that counts down from 5 Minutes to 0:00.
In your case you are using threads. So you cannot update ui from the thread other than the ui thread. SO you use runOnUithread. I would suggest you to use a countdown timer or a Handler.
1.CountDownTimer
http://developer.android.com/reference/android/os/CountDownTimer.html
Here's a link to another example. Suggest you to check the link for the count down timer.
Countdowntimer in minutes and seconds
Example:
public class MainActivity extends Activity {
Button b;
TextView tv;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = (TextView) findViewById(R.id.textView1);
b= (Button) findViewById(R.id.button1);
b.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
startTimer(200000);
}
});
}
private void startTimer(long time){
CountDownTimer counter = new CountDownTimer(30000, 1000){
public void onTick(long millisUntilDone){
Log.d("counter_label", "Counter text should be changed");
tv.setText("You have " + millisUntilDone + "ms");
}
public void onFinish() {
tv.setText("DONE!");
}
}.start();
}
}
2.You can use a Handler
Example :
Handler m_handler;
Runnable m_handlerTask ;
int timeleft=100;
m_handler = new Handler();
m_handlerTask = new Runnable()
{
#Override
public void run() {
if(timeleft>=0)
{
// do stuff
Log.i("timeleft",""+timeleft);
timeleft--;
}
else
{
m_handler.removeCallbacks(m_handlerTask); // cancel run
}
m_handler.postDelayed(m_handlerTask, 1000);
}
};
m_handlerTask.run();
3.Timer
Timer runs on a different thread. You should update ui on the ui thread. use runOnUiThread
Example :
int timeleft=100;
Timer _t = new Timer();
_t.scheduleAtFixedRate( new TimerTask() {
#Override
public void run() {
runOnUiThread(new Runnable() //run on ui thread
{
public void run()
{
Log.i("timeleft",""+timeleft);
//update ui
}
});
if(timeleft>==0)
{
timeleft--;
}
else
{
_t.cancel();
}
}
}, 1000, 1000 );
You are trying to update the UI Thread from a background Thread with
timer1.setText(
which you can't do. You need to use runOnUiThread(), AsyncTask, CountDownTimer, or something similar.
See this answer for an example of runOnUiThread()
But CountDownTimer is nice for things like this.
Also, when posting a question on SO, statements like "it doesn't work." are very vague and often unhelpful. Please indicate the expected results compared to actual results of your code and logcat if the app is crashing.