I have a requirement to get data from server by sending a call after specified interval like 5 minutes. So app would keep checking for new data after 5 minutes. It is just like gmail or facebook. Which automatically get new feeds or emails after some time and show in list. I am using service for this like following:
public class MessagesLoaderService extends Service {
// constant
// run on another Thread to avoid crash
private Handler mHandler = new Handler();
// timer handling
private Timer mTimer = null;
//********************************************************************************************************************************/
#Override
public IBinder onBind(Intent intent) {
return null;
}
//********************************************************************************************************************************/
#Override
public void onCreate() {
// cancel if already existed
if (mTimer != null)
{
mTimer.cancel();
}
else
{
// recreate new
mTimer = new Timer();
}
// schedule task
mTimer.scheduleAtFixedRate(new MessageLoaderTask(), 0, Commons.TIME_INTERVAL_REFRESH_MESSAGES);
}
//********************************************************************************************************************************/
class MessageLoaderTask extends TimerTask
{
#Override
public void run() {
// run on another thread
mHandler.post(new Runnable()
{
#Override
public void run() {
//Get Data from Server and store in local db
}
});
}
}
#Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
Utils.showToast_msg(getApplicationContext(), "Service Destroyed");
}
//********************************************************************************************************************************/
}
//////////////////////////////////////////////////////////////////
Starting service from main activity MainActivity:
startService(new Intent(this, MessagesLoaderService.class));
I want service to run (send calls after 5 minutes) only when the app is running or in foreground/background. But the problem is that it keeps running even if I exit from the application. I want service to stop when Application is closed. Any solution for this?
Shouldn't you stop your timer in "OnDestroy" with mTimer.cancel() if you want it to stop ?
This method works when you enter the activity which actually queries the server. Call the method in onCreate. If value returned is true, then fetch data from server, if false, do whatever is in youf flow.
This Example below uses Singleton class. The current system time, plus five minutes is stored in singleton class variable, while local variable stores the current time. If current time exceeds the time of Singleton variable, then true is returned and it is time to call server.
SingletonClass app;
app = (SingletonClass ) getApplication();
public boolean serverQueryFrequency() {
boolean isTimeElapsed;
Calendar cal = Calendar.getInstance();
long time = cal.getTimeInMillis();
// If No Time is set, only then Set the Current time + 10 into
// application variable. This should fire only once, until 10 minutes
// have passed
if (app.getServerCallTime() == 0) {
Calendar cal2 = Calendar.getInstance();
// updating calendar to get current time + 10
cal2.add(Calendar.MINUTE, 5);
long timeTen = cal2.getTimeInMillis();
app.setServerCallTime(timeTen);
// returning true, to enable server check
return true;
}
// Log.v("******", "Current : " + time);
// Log.v("******", "App Time : " + app.getServerCallTime());
// Comparing current time with SeverCalltime which is set 10 minutes
// ahead. Code below fires conditionally as stated
if (time == app.getServerCallTime() || time > app.getServerCallTime()) {
isTimeElapsed = true;
// Once true fired from here, reset serverCallTime
app.setServerCallTime(0);
} else {
// 5 minutes have not passed
isTimeElapsed = false;
}
// returning the related value
return isTimeElapsed;
}
you can stop service by using this line
stopService(new Intent(this, MessagesLoaderService.class));
so your service get stopped
you need to identify in your app from where your exiting the app at that point you need to call above code also OS automatically kill the service in certain circumstances like low battery and so on but this is not good solution so you can stop it by above line in your exit point of application
I have learned when the app is closed the service get closed also because they are in a one thread, so the service should be on another thread in order fot it not to be closed, look into that and look into keeping the service alive with alarm manager here an example http://www.vogella.com/articles/AndroidServices/article.html this way your service won't be shown in notification.
lastly, after all the research I've done I'm coming to realize that the best use of a long running service is start foreground(); because it is made for that and the system actually deals with your service well.
when the user presses back button on the first page of your app..means they want out.
override the onbackpressed and put the stopService call there.
else..
use an exit button..give it an onclick and inside it put the stopService there
Related
How can I make a certain function execute after every 10 seconds for an infinite time?
What I have done till now: I am getting the location values of the user from the App and storing them on the server. I am using a service, so that, the code keeps running for an infinite time, I am using a Broadcast receiver, so that, if the phone is booted, the service should start again and starts sending me the location.
The issue Everything works perfectly fine for about first 10-15 minutes, but, after this, the service gets stopped by itself. Also, when the user signs up for the App, authorized tokens are generated. These tokens are also sent in the POST call as one of the parameters, for security purposes. Even these tokens are lost, despite working perfectly fine for the initial 10 minutes. I am storing these tokens in SharedPreferences. Any help in this regard would be highly appreciated.
Code for SharedPreferences
Log.i("onCreate", "onCreate");
Log.i("atoken value", ConfirmToken.avalue);
Log.i("utoken value", ConfirmToken.uvalue);
atoken = ConfirmToken.avalue;
utoken = ConfirmToken.uvalue;
Log.i("atoken value", atoken);
Log.i("utoken value", utoken);
Log.i("Starting SharedPref", "Starting SharedPref");
SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
SharedPreferences.Editor editor = settings.edit();
editor.putString("atoken", atoken);
editor.putString("utoken", utoken);
editor.commit();
if (settings.contains("atoken")) {
atoken = settings.getString("atoken", "nulll");
Log.i("Inside SharedPref", atoken);
}
if(settings.contains("utoken")) {
utoken = settings.getString("utoken", "nulll");
Log.i("Inside Sharedprefs", utoken);
}
//Calling UpdateData here so that values of lat, lng get updated, before they are used by MyService.java
UpdateData();
startService(new Intent(this, MyService.class));
Now, the update data function simple makes a POST call, using these tokens and Location values as parameters.
This is how I run a task every few seconds. Note that it runs in another thread, so accessing UI elements needs runOnUiThread call, but since you are in a service, you will not have any issues with that.
private ScheduledThreadPoolExecutor taskExecutor;
private void stopTimerTask() {
if (taskExecutor != null)
taskExecutor.shutdownNow();
// keep one task at any given time
taskExecutor = new ScheduledThreadPoolExecutor(1);
}
private void startTimerTask() {
stopTimerTask();
taskExecutor.scheduleWithFixedDelay(Timer_Tick, TIMER_INITIAL_DELAY, TIMER_PERIOD, TimeUnit.MILLISECONDS);
Log.d("Pool", "Timer Task Running");
}
private Runnable Timer_Tick = new Runnable() {
#Override
public void run() {
// Do something
}
};
You should however be aware that Android OS may terminate your service at any time when running low on resources or it feels like the service is doing too much work. You should start focusing on how to restore it's state, just like every one else does.
I think the following is the easiest way.
Also remember if you are making a network call, make an asynchronous request so that your app doesn't stop working while your app waits for the response.
for(long startTime = new Date().getTime();new Date().getTime() - startTime ==10000; startTime++)
{ /*your code goes here*/ };
No matter what you do, if the system is low on resources, it will terminate your app.Please let me know weather this works for you or not :)
i currently work on an app that needs a lot of battery in order to support background gps tracking. my experience shows that people just forget about the app runnning in the background when they dont really need the tracking anymore. therefore i setup some code that should close the application after 4 hours.
public class SelfDestructor {
private static SelfDestructor instance;
private final long IDLE_TIME_UNTIL_AUTO_DESTRUCT = 4 * 60 * 60 * 1000; // 4 hours
private Handler handler;
private Runnable closeApp = new Runnable() {
#Override
public void run() {
System.exit(0);
}
};
public static SelfDestructor getInstance() {
if (SelfDestructor.instance == null) {
SelfDestructor.instance = new SelfDestructor();
}
return SelfDestructor.instance;
}
public void keepAlive() {
if (handler == null) {
handler = new Handler();
}
handler.removeCallbacks(closeApp);
handler.postDelayed(closeApp, IDLE_TIME_UNTIL_AUTO_DESTRUCT);
}
}
now in my main activity i call keepAlive().
#Override
protected void onResume() {
super.onResume();
SelfDestructor.getInstance().keepAlive();
}
#Override
protected void onStart() {
super.onStart();
SelfDestructor.getInstance().keepAlive();
}
now if i set the time to an hours or so and debug the that functionality everything works fine. if i set the time to 4 hours the System.exit(0); is never called. i am assuming the app thread with the close callback is just put on hold by the android system after a while and therefore will not be executed anymore while gps will continue to run. any ideas how to properly get this to work?
handler and postDelayed are not suited for long timers. At most they should be used within a few seconds and personally I think I never used one for anything more than 2 seconds.
Said all that, Android have an appropriate class for "stuff that should happen after a long time", it's called AlarmManager: http://developer.android.com/reference/android/app/AlarmManager.html
you can get the references to the system service AlarmManager by calling Context.getSystemService(Context.ALARM_SERVICE)
and then set it by calling am.set(AlarmManager.ELAPSED_REALTIME, IDLE_TIME_UNTIL_AUTO_DESTRUCT, operation)
the operation is a PendingIntent to a BroadcastReceiver that you register in the AndroidManifest.xml via the <receiver> tag. Then you do the close application code inside this broadcast receiver.
Also I should add that it's NEVER good to call System.exit(0);, as this just destroy the VM without much of a warning. It's a better, more organised/structured shut down if you pass a command to the Service that is holding the GPS (I believe you're running a service), then this service will cancel the GPS request, and call stopSelf();
in my app next to the splash screen i need to show an activity called Tips Page. This activity to be shown once in a day. When the user opens the app again within 24 hrs it should not be shown.
First i tried to show based on the current date, when the first the activity shown i will store the current date in shared preference and next time when the app gets opened i will check whether the current date and date in shared preference are equal or not. If equal i will not show the activity if not i will show the activity.
But here there is a logic mistake, if the user opens the app first in midnight of 11 PM in a date, and again opens the app after t hour the Tips activity will be shown, but i need to show it after 24 hrs, how can it be done. pls help me in this ligic
I think you need such a flow, see this the implementation of Jason Hessley's Answer
SharedPreferences settings = getSharedPreferences("Preferences",
MODE_PRIVATE);
long timeFromPrefs = settings.getLong("time", System.currentTimeMillis());
final long TIME_DIFF = 24*60*60*1000;
if ((System.currentTimeMillis()-timeFromPrefs)>TIME_DIFF) {
// show Activity...........
Editor editor = settings.edit();
editor.putLong("time", System.currentTimeMillis());
editor.commit();
}
Android applications can run periodic timers using android.os.Handler & java.lang.Runnable classes. As simple example is shown below.
Key Points
1. Service classes extending android.app.Service should implement onBind, onCreate & onDestroy, life cycle methods.
2. periodicTask is an instance of Runnable implementation, that runs a Thread. Execution of run() will print the message "Awake".
3. mHandler is an instance of Handler, that is attached the periodicTask thread.
4. The Handler is informed to execute the thread every minute, by postDelayed.
5. When the service is destroyed, the periodicTask instance is removed from the Handler, by invoking removeCallbacks.
Sample Code
public class PeriodicTimerService extends Service {
private Handler mHandler = new Handler();
public static final int ONE_DAY = 86400000;
private Runnable periodicTask = new Runnable() {
public void run() {
Log.v("PeriodicTimerService","Awake");
mHandler.postDelayed(periodicTask, ONE_DAY );
}
};
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
mHandler.postDelayed(periodicTask, ONE_DAY );
}
#Override
public void onDestroy() {
super.onDestroy();
mHandler.removeCallbacks(periodicTask);
Toast.makeText(this, "Service onDestroy() ", Toast.LENGTH_LONG).show();
}
}
Save the last time the activity was started in a shared pref as you stated in your question. Then subtract the last time from the current time. If it is greater then 24 hours, show your tips.
I am having 10 different buttons in my application for different task to perform. I want to develop one service which continuously check (listens) and if user is not clicking any button for particular time let say for 5sec than i wish to perform some other task. How can I check that user has not clicked any button? If anyone having any idea please kindly let me know.
You could simply set a Timer to the desired length. When a button is clicked, just reset the timer. Start the timer in onResume so it starts even if the user is coming back from a phone call or other activity. You should probably stop the timer in onPause of the activity too.
In each of your click listeners save off the time the last button was clicked:
private long lastClickTimestamp;
private Handler handler = new Handler();
public void onCreate( Bundle saved ) {
BackgroundJob job = new BackgroundJob();
handler.postDelayed( job, SECONDS_TO_WAIT * 1000 );
button1.setClickListener( new OnClickListener() {
public void onClick( View view ) {
lastClickTimestamp = System.currentTimeInMillis();
// do the listener logic for button 1 here.
}
});
button2.setClickListner( new OnClickListener() {
public void onClick( View view ) {
lastClickTimestamp = System.currentTimeInMillis();
// do the listener logic for button 2 here.
}
});
// repeat that for all 10 buttons.
}
Now the smarter developer would create a reusable base class that handled setting the timestamp once, then reuse that base class in each of the 10 buttons. But, that's left up to you. Then the background job would look like:
public class BackgroundJob implements Runnable {
private boolean done = false;
// meanwhile in job:
public void run() {
if( lastClickTimestamp > 0 && System.currentTimeInMillis() - lastClickTimestamp > SECONDS_TO_WAIT * 1000 ) {
// let's do that job!
}
if( !done ) {
// reschedule us to continue working
handler.postDelayed( this, SECONDS_TO_WAIT * 1000 );
}
}
}
If you have to use a service you can send a notification to the service saying a button was clicked, then the service can keep track of the time when that occurred. I wouldn't use a service for this because playing an animation or sound doesn't need to survive if the app is put into the background or killed. Services are meant for things like playing music when someone is doing something else, chat applications, or things that need to run in the background when the user isn't interacting with the application. What you're describing could be done as I've shown because when the user gets a phone call or text message they'll leave your application, and the animation or sound you're playing probably should stop too. Pretty easy to do with the Handler option I showed. More difficult, but doable, with a service.
On each button click, update some Calendar object to a new Calendar instance and then you can check what the time is of that Calendar and see if it's more than 5 minutes ago.
//this is a field
Calendar calendar;
public void onClick(View v) {
calendar = Calendar.getInstance();
//etc
switch(v.getId()) {
}
}
I have a timer that counts up from the time a user encounters that activity
I am currently using a Chronometer set during onCreate (initially started only when certain conditions are met). But I need the chronometer to keep counting upward until the app and all its views are closed (I have an "Exit" function to do that).
The problem is that the Chronometer gets reset to zero on every time I look at another tab and come back to its activity. (This has to do with the oncreate, but I dont know the way around it)
I didn't find an intuitive way to save the chronometer's state or countup in the background on its own (or to perhaps keep track of the time on my own and update the chronometer visually at a different point in time)
One idea I had was to start the Chronometer with a service and let the service keep counting , while having a textview in the existing activity update using the chronometer's current time tally as a string
any insight on a known approach to this problem be appreciated!
This is further complicated because this is an activity in a tabhost, and tabhosts call both onPause and onResume every time you load a view, so this breaks lifecycle functions.
There are a number of ways to persist the time. The easiest one I have found is to store the time in the Intent that was used to create the original activity via getIntent().putExtra("START_TIME", floatvalue). You may retrieve the value with getIntent().getFloatExtra("START_TIME", 0f). Doing it this way has a number of benefits:
It doesn't break the Activity LifeCycle and does not require a Context.
It can be passed easily between other Activities and Applicaitons.
It persists among Pauses and Stops.
It doesn't require special listeners.
It doesn't create any new objects (the Intent is the one used to create the Activity the first time).
This solution is great for persisting in a Tabbed Activity, or across Dialogs, etc. It has some limitations if leaving the Application to a more memory intensive one, but only if your Activity is destroyed (due to memory).
Because of my Tabhost, the lifecycle functions could not be relied on.
What I did was make the chronometer a static global in a central class, and added a ontabchangedlistener within my tabhost that checked to see if the tab being changed to was the tab with the chronometer. If this was true then it stores the Long value of the chronometer's current time.
tabHost.setOnTabChangedListener(new OnTabChangeListener(){
#Override
public void onTabChanged(String arg0) {
// TODO Auto-generated method stub
if(arg0.contentEquals("homeGroup"))
{
//store time in centralhelper.java
//stopWatch is of type Chronometer
//stopWatchLastTime is of type Long and is initially set to zero. Chronometer uses milliseconds to determine time, will never be zero after set
CentralHelper.stopWatchLastTime = CentralHelper.stopWatch.getBase();
}
}
});
When my homeGroup view loads, the onResume() function is called, there is a condition here to retrieve the time for the chronometer to resume counting from. Despite the fact that a tabhost will call both onPause() and onResume() in EVERY load outside of normal lifecycle functions, they still get called before onCreate()
public void onResume(){
super.onResume();
//update Chronometer with time stored in tabchangelistener
if(CentralHelper.stopWatchLastTime!=0)
CentralHelper.stopWatch.setBase(CentralHelper.stopWatchLastTime);
}
this allowed me to do a similar check in onCreate()
if(CentralHelper.stopWatchLastTime!=0)
{
CentralHelper.stopWatch.start(); //this is where it resumes counting from the base set in onResume()
}
else
{
CentralHelper.stopWatch.start();
CentralHelper.stopWatch.setBase(SystemClock.elapsedRealtime());
}
When you switch to a different activity the previous one is paused (onPause, asand so on, in attached image) when you came back to the activity it is resumed, but occasionaly when dalvik runs out of memory your Activity object can be deleted when ton showing.
If you keep your application data in the Activity instance you might loose it accidentally, please read this Activity Lifecycle http://developer.android.com/reference/android/app/Activity.html
This approach is tested and it works really well.
Try this:
Take a boolean volatile variable which will control your thread(start/stop). Take three text views, hour, min and sec text views, and remove chronometer completely. Update your UI using a Handler Write the following code.
public void timeUpdate()
{
timerThread = new Thread(new Runnable() {
#Override
public void run() {
while(continueThread){
Date newDate = new Date();
if(((newDate.getTime()) - date.getTime()) > 1000){
secondCounter = secondCounter+1;
mHandlerUpdateSec.post(mUpdateSec);
System.out.println("Inside the Theread ..."+secondCounter);
if(secondCounter > 59){
minuteCounter = minuteCounter + 1;
mHandlerUpdateMinute.post(mUpdateMinute);
secondCounter = 0;
if(minuteCounter > 59){
hourCounter = hourCounter + 1;
mHandlerUpdateHour.post(mUpdateHour);
minuteCounter = 0;
}
}
}
try{
timerThread.sleep(1000);
}catch (Exception e) {
// TODO: handle exception
}
}
}
});
timerThread.start();
}
The continueThread is a boolean volatile variable. Setting it to false will stop the thread. The timerThread is an instance of thread. There are three counters, hour, min and sec counters which will give you the latest time values. The handlers are updated as follows.
final Handler mHandlerUpdateSec = new Handler();
final Runnable mUpdateSec = new Runnable() {
public void run() {
String temp = "" + secondCounter;
System.out.println("Temp second counter length: " + temp.length());
if(temp.length() == 1)
secTextView.setText("0" + secondCounter);
else
secTextView.setText("" + secondCounter);
}
};
final Handler mHandlerUpdateMinute = new Handler();
final Runnable mUpdateMinute= new Runnable() {
public void run() {
String temp = "" + minuteCounter;
System.out.println("Temp second counter length: " + temp.length());
if(temp.length() == 1)
minTextView.setText("0" + minuteCounter);
else
minTextView.setText("" + minuteCounter);
}
};
final Handler mHandlerUpdateHour = new Handler();
final Runnable mUpdateHour = new Runnable() {
public void run() {
String temp = "" + hourCounter;
System.out.println("Temp second counter length: " + temp.length());
if(temp.length() == 1)
hourTextView.setText("0" + hourCounter);
else
hourTextView.setText("" + hourCounter);
}
};
Now, whenever you want to start the timer, set continueThread to true and call timeUpdate(). To stop it, just do continueThread = false. To start the thread again, set continueThread to true and call timeUpdate() again. Make sure you update the counters accordingly while you start/stop the timer.
You could save the start time in a sharedpreferences (or file, etc.) and establish your count-up from that (rather than starting at 0) in onResume().
Your UI may need some changes to handle the fact that you will have to reset the start time, since it could theoretically count forever.