I used postDelayed for delaying dynamic duration.
And I found it did not work correctly.
Here is my source code.
public Runnable service = new Runnable() {
public void run() {
endTimeHere = System.currentTimeMillis();
Log.d("Time",(endTimeHere-startTimeHere)/1000);
switch (step)
{
case 0:
delay = 0;
step = 1;
break;
case 1:
delay = 600; //delay 10 min = 600 sec
step = 2;
break;
case 2:
delay = 1200; //delay 20 min = 1200 sec
step = 3;
break;
case 3:
delay = 1800; //delay 30 min = 1800 secs
step = 0;
break;
default:
break;
}
startTimeHere = System.currentTimeMillis();
handler.postDelayed(service, delay*1000);
}
};
And I start and stop the handler in a BroadcastLintener.
public Handler handler = new Handler();
private BroadcastReceiver screenReceiver = new BroadcastReceiver()
{
public void onReceive(Context context, Intent intent)
{
String action = intent.getAction();
if(Intent.ACTION_SCREEN_ON.equals(action))
{
handler.removeCallbacks(service);
}
else if(Intent.ACTION_SCREEN_OFF.equals(action))
{
handler.post(service);
}
}
}
I'm sure that postDelayed is added in queue because the return value is true.
However, the time duration I recorded is not matching with the delay value I set.
For example, I set delay = 600 secs and the recorded duration = 958 secs.
Does anyone know why this happened?
Handlers are not perfect at firing exactly when they should. Other threads (like the UI thread) may take priority. Additionally, Android has overhead for processing the Intent. In other words, the handler may fire at 650ms due to delays in thread monitoring from the OS, but then the intent needs to be handled, the receiver instantiated, the intent processed, etc.
You may be better off sending the intent with the delay data and then have the service setup a queue and poll it frequently based on the expected delay. e.g. an event scheduled for 500ms in the future maybe should be polled every 50ms to see if the delay time has expired. While an event 10,000ms in the future can be polled at 5,000ms or 9,000ms and then increase the polling frequency as the time approaches.
Related
I want to call a thread in android activity after a time interval like 5 or 10 mins. after that i want to send an automatic SMS in android, to any number. Please help me. I have idea about thread that we can do with this but the problem with that function is, it is calling over and over again. Thanks in advance
Its just that code. But it once calls, then sends sms repeatedly until we stop application. Please help me.
Thread timer = new Thread()
{
#Override
public void run()
{
try
{
sleep(1000*60*2);
}
catch (InterruptedException ex)
{
ex.printStackTrace();
}
finally
{
String phone_number = "123456789"; // some phone number here
String text =
"Hello this is an automatic SMS service informing you about the current status: \n" +
" City :" +cityName +"\n"
+"State :" +stateName+"\n"
+"Country :" +countryName +"\n";
SmsManager smsMgr = SmsManager.getDefault();
smsMgr.sendTextMessage(phone_number, "Hussnain Muavia", text, null, null);
txtLat.setText("SMS Sent");
}
}
};
timer.start();
I would use a Timer with a TimerTask:
TimerTask myTimerTask = new TimerTask() {
public void run() {
//do your code here
}
};
Timer myTimer = new Timer();
myTimer.schedule(myTimerTask, when you want to start?[im milliseconds for example], 300000[5mins]);
And if you don't want to execute the TimerTask again simply call. myTimer.cancel();
Notice Don't Forget to call myTimer.cancel(); in your onPause because otherwise the timer will continue executing and this Drains battery!
Update regarding your comment
myTimer.schedule can take various Parameters. Interesting for you are this one:
myTimer.schedule(Runnable r, When to first execute, In which Interval);
Runnable r is your TimerTask which will be executed after
When to first execute expired. If you want to start immediatly, simply pass 0.
In which Interval if you put in there 50, then your TimerTask will be execute every 50ms, after When to first execute expired.
This should do the trick.
Hope it helps! ;)
Do it in Android way. Use AlarmManager to set repeated actions, then create custom BroadcastReceiver to perform specific action. This is example how to implement. It is more complex but it is more reliable and android nature way.
You want to use AlarmManager, that's the Android way. Everything else you will run into trouble. Do not use Handler.postDelayed because the callback will be dropped if the Looper exits before the timer is up:
Returns true if the Runnable was successfully placed in to the message queue. Returns false on failure, usually because the looper processing the message queue is exiting. Note that a result of true does not mean the Runnable will be processed -- if the looper is quit before the delivery time of the message occurs then the message will be dropped
Creating an alarm is easy.
AlarmManager am = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(context, Alarm.class);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
long FIVE_MINS_IN_MILLIS = 1000 * 60 * 5;
am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), FIVE_MINS_IN_MILLIS , pi);
My app needs to do some background task after boot completed and also in sleep mode.
So I'm using WakefulIntentService to avoid flow problem in sleep mode and it works well.
But when I'm trying to use the boot receiver for continuing data flow after boot completed it gives some strange error and also not working sometimes.
Here is my Boot Receiver class where I am trying to do multiple task.
public class OnBootReceiver extends BroadcastReceiver {
private static final int SERVICE_PERIOD = 300000; // 5 minutes currently
// private static final int HANDLER_PERIOD = 300000 * 12; // 1 hour
// currently
private static final String TAG = "OnBoot";
private Context mContext;
private int mInterval = 1000 * 60 * 60 * 2; // 2 hours by default, can be
// changed later
private Handler mHandler;
#Override
public void onReceive(Context context, Intent intent) {
mContext = context;
AlarmManager mgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(context, OnServiceReceiver.class);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
mgr.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime() + 60000, SERVICE_PERIOD, pi);
mHandler = new Handler();
startRepeatingTask();
}
Runnable mStatusChecker = new Runnable() {
#SuppressWarnings("unchecked")
#Override
public void run() {
SharedPreferences mSharedPreferences = mContext
.getSharedPreferences(KEY_USER_ID, 0);
String UserId = mSharedPreferences.getString(KEY_USER_ID, "0");
new SyncValidater(mContext, UserId).execute();
mHandler.postDelayed(mStatusChecker, mInterval);
}
};
void startRepeatingTask() {
mStatusChecker.run();
}
void stopRepeatingTask() {
mHandler.removeCallbacks(mStatusChecker);
}
}
In this class I have written two tasks. the first one is starting another broadcast receiver which starts the wakeful service(same as github example). And the second one starts one handler which starts one AsyncTask class to do some server transaction in every two hours. But sometimes the handler starts in random time and sometimes stop.
So here I'm confusing that is my app requires two boot receivers ?
is there any other option to do these multiple tasks in the current receiver ?
please help. Thanks
And the second one starts one handler which starts one AsyncTask class to do some server transaction in every two hours
No, your second task will run once and probably never again, because your process is terminated in the meantime.
So here I'm confusing that is my app requires two boot receivers ?
No.
is there any other option to do these multiple tasks in the current receiver ?
Use two AlarmManager events, each with their own period. One is your current AlarmManager event. The other is one you create in support of your every-two-hour work to be done.
I would like my application to do an action after a certain amount of time has elapsed (preferablely while the app isn't open or paused).
Example:
If(hours4 == elapsed){
this.close();
}
Use AlarmManager to schedule events to run at a future time.
It's quite simple. You have to start this task in background using Service. To make delay you can use AlarmManager. Here is example
or handler
new Handler().postDelayed(new Runnable() {
public void run() {
Intent intent = new Intent("INTENT_WAKEUP_B");
intent.putExtra("EXTRA_MESSAGE",message);
sendBroadcast(intent);
}
}, timeToWait * 1000); // * 1000 if timeToWait is in seconds
I'm writing an application which is continuously listening and checking the sensors (almost all available) and saving that data into the database in the device.
I need to make some calculations every X second with that data and throw a new event if the calculations check says so.
I'm thinking about requesting to have the device plugged in while using the application (regarding battery drain).
What's the best approach for the task that needs to make the calculations and throw the event? Timer? Threads? AsynkTask? AlarmManager? Another approach?
I want to keep getting sensors data and saving them to the database despite if the application is not on foreground...it should save the values as long as the application is not stopped by the user.
One option for that is wake locks (PARTIAL_WAKE_LOCK, which keeps CPU running).
I'd like to hear different opinions.
Thanks in advance! Guillermo.
You can use AlarmManager to setup the repeating tasks (this is the Android prefered way of setting future/repeating tasks). To make the calculations use a Service (if you think calculations are going to be expensive, then think about moving them to a separate worker thread or use IntentService).
Regarding the wake lock (from the AlarmManager reference):
The Alarm Manager holds a CPU wake
lock as long as the alarm receiver's
onReceive() method is executing. This
guarantees that the phone will not
sleep until you have finished handling
the broadcast. Once onReceive()
returns, the Alarm Manager releases
this wake lock. This means that the
phone will in some cases sleep as soon
as your onReceive() method completes.
If your alarm receiver called
Context.startService(), it is possible
that the phone will sleep before the
requested service is launched. To
prevent this, your BroadcastReceiver
and Service will need to implement a
separate wake lock policy to ensure
that the phone continues running until
the service becomes available.
This is a modified snippet of a service I wrote to log CPU frequency some time ago. It lacks the Application and the Activity part, but illustrates how I wrote the Service to keep logging every ten seconds. It does not log when the phone goes into deep sleep, so if you want to log without interruptions, then you will need to acquire PARTIAL_WAKE_LOCKs, but consider that battery life will be severely reduced by that.
public class YOURCLASS_Service extends Service {
private long mStartTime = 0L;
private final Handler mHandler = new Handler();
private Runnable mUpdateTimeTask;
private YOURAPP app;
#Override
public void onCreate() {
super.onCreate();
app = (YOURAPP) getApplicationContext();
}
#Override
public void onDestroy() {
Toast.makeText(this, "Service finished.", Toast.LENGTH_SHORT).show();
stopLog ();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (app.isRunning())
return START_STICKY;
try {
File file = new File(Environment.getExternalStorageDirectory(), "yourlog.csv");
OutputStreamWriter out = new OutputStreamWriter(new FileOutputStream(file, false));
out.write("Log title");
out.close();
} catch (java.io.IOException e) {
stopLog ();
Toast.makeText(this, "Error creating log file. Aborting.", Toast.LENGTH_SHORT).show();
}
mUpdateTimeTask = new Runnable() {
public void run() {
long millis = SystemClock.uptimeMillis() - mStartTime;
int seconds = (int) (millis / 1000);
int minutes = seconds / 60;
seconds = seconds % 60;
readYourSensors ();
if (!writeLog (str)) stopLog();
mHandler.postAtTime(this, mStartTime + (((minutes * 60) + seconds + 10) * 1000));
mHandler.postDelayed (mUpdateTimeTask, 10000);
}};
mStartTime = SystemClock.uptimeMillis();
mHandler.removeCallbacks(mUpdateTimeTask);
mHandler.postDelayed(mUpdateTimeTask, 100);
Notification notification = new Notification(R.drawable.notification_icon, "App title", System.currentTimeMillis());
Intent notificationIntent = new Intent(this, YOURCLASS.class);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
notification.setLatestEventInfo(getApplicationContext(), "App title", "Please see /sdcard/yourlog.csv", contentIntent);
startForeground(startId, notification);
app.isRunning(true);
return START_STICKY;
}
#Override
public IBinder onBind(Intent arg0) {
return null;
}
public void stopLog () {
mHandler.removeCallbacks(mUpdateTimeTask);
}
}
I'm writing an application which is continuously listening and checking the sensors (almost all available) and saving that data into the database in the device.
I need to make some calculations every X second with that data and throw a new event if the calculations check says so.
I'm thinking about requesting to have the device plugged in while using the application (regarding battery drain).
What's the best approach for the task that needs to make the calculations and throw the event? Timer? Threads? AsynkTask? AlarmManager? Another approach?
I want to keep getting sensors data and saving them to the database despite if the application is not on foreground...it should save the values as long as the application is not stopped by the user.
One option for that is wake locks (PARTIAL_WAKE_LOCK, which keeps CPU running).
I'd like to hear different opinions.
Thanks in advance! Guillermo.
You can use AlarmManager to setup the repeating tasks (this is the Android prefered way of setting future/repeating tasks). To make the calculations use a Service (if you think calculations are going to be expensive, then think about moving them to a separate worker thread or use IntentService).
Regarding the wake lock (from the AlarmManager reference):
The Alarm Manager holds a CPU wake
lock as long as the alarm receiver's
onReceive() method is executing. This
guarantees that the phone will not
sleep until you have finished handling
the broadcast. Once onReceive()
returns, the Alarm Manager releases
this wake lock. This means that the
phone will in some cases sleep as soon
as your onReceive() method completes.
If your alarm receiver called
Context.startService(), it is possible
that the phone will sleep before the
requested service is launched. To
prevent this, your BroadcastReceiver
and Service will need to implement a
separate wake lock policy to ensure
that the phone continues running until
the service becomes available.
This is a modified snippet of a service I wrote to log CPU frequency some time ago. It lacks the Application and the Activity part, but illustrates how I wrote the Service to keep logging every ten seconds. It does not log when the phone goes into deep sleep, so if you want to log without interruptions, then you will need to acquire PARTIAL_WAKE_LOCKs, but consider that battery life will be severely reduced by that.
public class YOURCLASS_Service extends Service {
private long mStartTime = 0L;
private final Handler mHandler = new Handler();
private Runnable mUpdateTimeTask;
private YOURAPP app;
#Override
public void onCreate() {
super.onCreate();
app = (YOURAPP) getApplicationContext();
}
#Override
public void onDestroy() {
Toast.makeText(this, "Service finished.", Toast.LENGTH_SHORT).show();
stopLog ();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (app.isRunning())
return START_STICKY;
try {
File file = new File(Environment.getExternalStorageDirectory(), "yourlog.csv");
OutputStreamWriter out = new OutputStreamWriter(new FileOutputStream(file, false));
out.write("Log title");
out.close();
} catch (java.io.IOException e) {
stopLog ();
Toast.makeText(this, "Error creating log file. Aborting.", Toast.LENGTH_SHORT).show();
}
mUpdateTimeTask = new Runnable() {
public void run() {
long millis = SystemClock.uptimeMillis() - mStartTime;
int seconds = (int) (millis / 1000);
int minutes = seconds / 60;
seconds = seconds % 60;
readYourSensors ();
if (!writeLog (str)) stopLog();
mHandler.postAtTime(this, mStartTime + (((minutes * 60) + seconds + 10) * 1000));
mHandler.postDelayed (mUpdateTimeTask, 10000);
}};
mStartTime = SystemClock.uptimeMillis();
mHandler.removeCallbacks(mUpdateTimeTask);
mHandler.postDelayed(mUpdateTimeTask, 100);
Notification notification = new Notification(R.drawable.notification_icon, "App title", System.currentTimeMillis());
Intent notificationIntent = new Intent(this, YOURCLASS.class);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
notification.setLatestEventInfo(getApplicationContext(), "App title", "Please see /sdcard/yourlog.csv", contentIntent);
startForeground(startId, notification);
app.isRunning(true);
return START_STICKY;
}
#Override
public IBinder onBind(Intent arg0) {
return null;
}
public void stopLog () {
mHandler.removeCallbacks(mUpdateTimeTask);
}
}