I am in quite a tough predicament here as I have an activity that starts a service which runs a countdown timer. Each time the activity is resumed, the service starts another countdown timer. I looked up services and it has method which is called on once throughout the service and is called onCreate. The only issue with that is I am receiving time values from the activity through intents which is retrieved during onStartCommand. onCreate is called before onStartCommand meaning I cannot retrieve those values and plug them into onCreate. Is there a way I can put values from onStartCommand to onCreate. The following code shows my problem.
TextView timeTextView;
int data;
public String hms;
public CountDownAct countDownAct;
public CountDownTime countDownTimer;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
//I need the CountDownTimer to start here in order to prevent a new countdown timer from being created each time the activity is resumed.`
countDownTimer = new CountDownTime(data,1000 );
countDownTimer.start();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
//the time data is being retrieved here
data = intent.getIntExtra("the", 0);
return START_STICKY;
}
#Override
public boolean stopService(Intent name) {
Log.i("CountDownService", "Stop Service");
return super.stopService(name);
}
#Override
public void onDestroy() {
countDownTimer.cancel();
}
Starting the Service
useService = new Intent(CountDownAct.this, CountDownService.class);
useService.putExtra("the", actualTimeFiniliazedInMilliSeconds);
startService(useService);
You can use SharedPreference to store actualTimeFiniliazedInMilliSeconds. This can be retrived from service class :
useService = new Intent(CountDownAct.this, CountDownService.class);
SharedPreference mShared = getApplicationContext().getSharedPreference("myShared",Context.MODE_PRIVATE);
SharedPreferences.Editor mEditor = mShared.edit();
mEditor.putInt("data",actualTimeFiniliazedInMilliSeconds).commit();
startService(useService);
Retriving :
SharedPreference mShared = getApplicationContext().getSharedPreference("myShared",Context.MODE_PRIVATE);
countDownTimer = new CountDownTime(mShared.getInt("data",0),1000);
countDownTimer.start();
Related
I've created a service that counts in the background. I'm starting the service in my MainActivity's onCreate().
Whenever i restart my app, so does my service class by setting the timer to -1. However, when I switch the orientation of my phone the timer does not reset.
As far is I know, killing an app calls the onDestroy() method and starting it up again afterwards calls the onCreate(). I've read that changing orientation calls the same two methods, so why is it that the two actions result in different behaviors, and is there any way to prevent it? My code expects the timer to reset when the app is killed, so when the orientation is changed, my timer is way off.
Here is the code of my service class:
ublic class CounterService extends Service {
private Handler handler;
private int time = -1;
private boolean isActive;
private Intent timeBroadcaster;
private Runnable counter;
private Thread serviceCounter;
private SharedPreferences.Editor editor;
public static final String EXTRA_TIME = "TIME";
#Override
public void onCreate(){
super.onCreate();
handler = new Handler();
timeBroadcaster = new Intent();
timeBroadcaster.setAction(Intent.ACTION_SEND);
SharedPreferences prefs = getSharedPreferences("SessionLogger_Preferences", MODE_PRIVATE);
editor = prefs.edit();
counter = new Runnable() {
#Override
public void run() {
isActive = ((PowerManager) getSystemService(Context.POWER_SERVICE)).isInteractive();
if (isActive) {
handler.postDelayed(this, 1000);
time += 1;
Log.i("TIME", String.valueOf(time));
} else {
editor.clear();
editor.commit();
if (time > 5) {
//log
}
time = 0;
handler.postDelayed(this, 1000);
}
timeBroadcaster.putExtra(EXTRA_TIME, time);
sendBroadcast(timeBroadcaster);
}
};
serviceCounter = new Thread(counter);
serviceCounter.start();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
#Override
public void onDestroy(){
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
Rotation doesn't kill the app. It kills the Activity. THe application still runs, but the Activity is restarted. Since the Application still runs, any Services in the app are still running, and Services are not restarted. In fact that's the entire point of a Service- to remain running even when Activities are killed.
I'm currently working on my first android app and I've run into a problem.
My app is supposed to be counting in the background using a Service and I'm creating a new thread to handle that. If I don't stop the thread in my Service's onDestroy() method, my phone gives me the message "Unfortunately, (my app) has stopped." every time I close the app. I need to stop it somehow, and I tried to do it using :
while(!Thread.currentThread().isInterrupted()){
**my code**
}:
And then interrupting it in the onDestroy() method.
It works, but it makes my app count extremely fast, so I would like to know if it can be done any other way that does not change the functionaliy of my code.
Also, since my thread gets stopped in the onDestroy method, I guess my service stops as well. Is there any way to keep my service running even when my app has been closed?
Here's my code:
public class CounterService extends Service {
private Handler handler;
private int time = -1;
private boolean isActive;
private Intent timeBroadcaster;
private Runnable counter;
private Thread serviceCounter;
#Override
public void onCreate(){
super.onCreate();
handler = new Handler();
timeBroadcaster = new Intent();
timeBroadcaster.setAction("EXAMPLE_BROADCAST");
counter = new Runnable() {
#Override
public void run() {
isActive = ((PowerManager) getSystemService(Context.POWER_SERVICE)).isInteractive();
if (isActive) {
handler.postDelayed(this, 1000);
time += 1;
} else {
if (time > 5) {
//log
}
time = 0;
handler.postDelayed(this, 1000);
}
timeBroadcaster.putExtra("counter", time);
sendBroadcast(timeBroadcaster);
}
};
serviceCounter = new Thread(counter);
serviceCounter.start();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
#Override
public void onDestroy(){
//serviceCounter.interrupt();
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
Is there any way to keep my service running even when my app has been closed?
you can use sync adapter which runs in background even app is stoped.
https://developer.android.com/training/sync-adapters/creating-sync-adapter.html
I'm writting an app that pops up notifications from time to time.
a service is running in the background, and when I kill the app the service is restarted and a notification pops up, but I don't want this to happen.
I want the service to stay there quiet and be executed at the right time.(I'm using a TimerTask)
I don't want to kill or restart the service, I want it to stay there quiet.
when i kill the app the service is restarted and a notification pops up, but i don't want this to happen
In your service's onStartCommand() method, return START_NOT_STICKY.
(and I so wish that this were the default...)
i want the service to stay there quiet and be executed at the right time.(I'm using a TimerTask)
Use AlarmManager to arrange to get executed at the right time; do not use a TimerTask in a running service. Only have a service running when it is actively delivering value to the user. Watching the clock tick is not actively delivering value to the user.
I faced the same issue and resolved after reading the documentation,dozen of stack overflows, and blog posts. I created a background service and made it foreground to prevent it from restarting if the app(process) closed or opened--to prevent the data lose from the service. but again, there was persistent notification produced which was unmovable(I hated it). I wanted to remove this notification along with service started. then started surfing on updating the notification and there I found a question directed me to the documentation of updating notification. I read that and update foreground service notification and vola it worked like charm. I'm giving the complete code here.
Main Activity
public class MainActivity extends AppCompatActivity {
TextView textView;
Context context = this;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.time);
Intent background = new Intent(context,TimeBroadCast.class);
context.startService(background);
LocalBroadcastManager.getInstance(this).registerReceiver(
new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
int message = intent.getIntExtra(UpdatTime.timUpdate,0);
textView.setText(String.valueOf(message));
}
}, new IntentFilter(UpdatTime.ACTION_LOCATION_BROADCAST)
);
}
}
Service class
public class TimeBroadCast extends Service {
private boolean isRunning;
private Context context;
UpdatTime updatTime;
Timer timer;
#Override
public void onCreate() {
this.context = this;
this.isRunning = false;
timer = new Timer();
updatTime = new UpdatTime(this);
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
StartForground();
Notification notification = new NotificationCompat.Builder(this).build();
String ns = Context.NOTIFICATION_SERVICE;
NotificationManager nMgr = (NotificationManager) getApplicationContext().getSystemService(ns);
nMgr.notify(101,notification);
nMgr.cancel(101);
return START_STICKY;
}
#Override
public void onDestroy() {
StopForgroudn();
super.onDestroy();
}
private void StartForground() {
if(!isRunning) {
isRunning = true;
timer.schedule(updatTime, 0, 1000);
}
Notification notification = new NotificationCompat.Builder(this)
.setOngoing(false)
.setSmallIcon(android.R.color.transparent)
.build();
startForeground(101, notification);
}
private void StopForgroudn()
{
timer.cancel(); // Terminates this timer, discarding any currently scheduled tasks.
timer.purge(); // Removes all cancelled tasks from this timer's task queue.
stopForeground(true);
stopSelf();
}
}
TimerTaks class
public class UpdatTime extends TimerTask {
static String timUpdate = "timecountdown", ACTION_LOCATION_BROADCAST = TimeBroadCast.class.getName() + "TimeBroadCast";
Context myContext;
int i = 0;
public UpdatTime(Context myContext) {
this.myContext = myContext;
}
#Override
public synchronized void run() {
try {
i += 1;
Log.v("Data1", ""+i);
Intent intent = new Intent(ACTION_LOCATION_BROADCAST);
intent.putExtra(timUpdate,i);
LocalBroadcastManager.getInstance(myContext).sendBroadcast(intent);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Hops this may helps.
Sorry for the improper format of the code....
public class ReadList{
private static SparseArray<Read> LIST = new SparseArray<>();
public static void add(int ID){
LIST.put(ID, new Read(ID, DateFormat.getDateTimeInstance().format(new Date())));
}
public static void remove(int ID){
if(LIST.indexOfKey(ID) >= 0 )
LIST.remove(ID);
}
}
I have some similar readlist class.. Saving data with SharedPreference correctly and normally.
But i want when onDestroy(), onStop() or onPause() method called my DataSaveService starting and saving data SharedPreference file..
public class DataSaveService extends Service {
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
MyCustomSharedSaveData.saveAllReadListtoXML();
MyCustomSharedSaveData.saveAllFavoriteListtoXML();
}
}
Is it possible? Thank you and sory for my bad english..
onDestroy() call is up to the Android OS, as it calls it when the memory is getting low, so placing your service call there might not be a good idea. onStop() will be called when an activity is hidden completely from the view that is either user minimizes the app or a new activity is opened from the from the previous one, so i suppose you can call the sevice in onStop method
Hy i have a problem to set the ServiceUpdateUIListener in the service to update the UI. It's wrong to make a new Service object and set there the listener and put it in an intent.
Code source is at http://developerlife.com/tutorials/?p=356 there i can't find how the set the listener and start the service right.
Calling:
TimerService service = new TimerService();
TimerService.setUpdateListener(new ServiceUpdateUIListener() {
#Override
public void updateUI(String time) {
clock.setText(time);
}
});
Intent i = new Intent(Timer.this,service.class); //service cannot be resolved to a type
i.putExtra("ms", ms);
startService(i);
Service:
public class TimerService extends Service{
CountDownTimer timer;
Chronometer clock;
public static ServiceUpdateUIListener UI_UPDATE_LISTENER;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onStart(Intent intent, int startId) {
// TODO Auto-generated method stub
int ms = intent.getIntExtra("ms", 0);
timer = new CountDownTimer(ms,1000){
#Override
public void onTick(long millisUntilFinished) {
int seconds = (int) (millisUntilFinished / 1000) % 60 ;
int minutes = (int) ((millisUntilFinished / (1000*60)) % 60);
int hours = (int) ((millisUntilFinished / (1000*60*60)) % 24);
clock.setText( String.format("%02d:%02d:%02d", hours,minutes,seconds));
Log.e("Timer", String.valueOf(millisUntilFinished));
}
#Override
public void onFinish() {
// TODO Auto-generated method stub
}
}.start();
super.onStart(intent, startId);
}
public static void setUpdateListener(ServiceUpdateUIListener l) {
UI_UPDATE_LISTENER = l;
}
The Service documentation has fairly complete sample code for implementing a service in your app that another part of your app can bind to and make calls on:
http://developer.android.com/reference/android/app/Service.html#LocalServiceSample
Just put your setUpdateListener() method on the Service, and call it once you get onServiceConnected() with the service.
So your code would be something like this:
public interface UpdateListener {
public void onUpdate(long value);
}
class LocalService {
// Like in the Service sample code, plus:
public static String ACTION_START = "com.mypackage.START";
private final ArrayList<UpdateListener> mListeners
= new ArrayList<UpdateListener>();
private final Handler mHandler = new Handler();
private long mTick = 0;
private final Runnable mTickRunnable = new Runnable() {
public void run() {
mTick++;
sendUpdate(mTick);
mHandler.postDelayed(mTickRunnable, 1000);
}
}
public void registerListener(UpdateListener listener) {
mListeners.add(listener);
}
public void unregisterListener(UpdateListener listener) {
mListeners.remove(listener);
}
private void sendUpdate(long value) {
for (int i=mListeners.size()-1; i>=0; i--) {
mListeners.get(i).onUpdate(value);
}
}
public int onStartCommand(Intent intent, int flags, int startId) {
if (ACTION_START.equals(intent.getAction()) {
mTick = 0;
mHandler.removeCallbacks(mTickRunnable);
mHandler.post(mTickRunnable);
}
return START_STICKY;
}
public void onDestroy() {
mHandler.removeCallbacks(mTickRunnable);
}
Now you can start the service to get it to start counting, and anyone can bind to it to register a listener to receive callbacks as it counts.
It is really hard though to answer your question very well because you aren't really saying what you actually want to accomplish. There are a lot of ways to use services, either starting or binding or mixing the two together, depending on exactly what you want to accomplish.
Now you can implement your client code again based on the sample:
public class SomeActivity extends Activity implements UpdateListener {
private LocalService mBoundService;
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
mBoundService = ((LocalService.LocalBinder)service).getService();
mBoundService.registerListener(this);
}
public void onServiceDisconnected(ComponentName className) {
mBoundService = null;
}
};
void doBindService() {
bindService(new Intent(Binding.this,
LocalService.class), mConnection, Context.BIND_AUTO_CREATE);
mIsBound = true;
}
void doUnbindService() {
if (mIsBound) {
if (mBoundService != null) {
mBoundService.unregisterListener(this);
}
unbindService(mConnection);
mIsBound = false;
}
}
protected void onDestroy() {
super.onDestroy();
doUnbindService();
}
I don't know exactly what you want, but this is not the way to do it. It seems you're mixing up a lot of things.
The tutorial itself is a bad example to my opinion, keeping a static reference to an activity in a service seems to me bad practice; you would use binding to bind your service to an activity, or if you don't want to you can pass Intents around.
As far as I know instantiating a service like you do and setting a listener on it like that doesn't work. You get an error in the startService() call because the service instance isn't a class obviously; you should use TimerService.class instead. In your service you have an onStart(); onStart() is a deprecated function, you should use onStartCommand() instead.
Now, if you have an activity in which you want to show a clock you don't need nor want the service to update its UI directly of course, but if you'd want the service to calculate a new clock tick for you, just call startService(); As long as your service is alive, sending a new start service intent will just call the onStartCommand() with the intent you're sending along.
If your clock is in an activity, setup a broadcast receiver inside your activity that and let your service broadcast an intent that can be received by the broadcast receiver you setup, with your new clock value passed along.
MrJre is correct that onStart is depreciated and that you should be using onStartCommand().
If you want to get this to work, there is a better way.
I am doing something similar, as in wanting to update a UI from results happening in a service. This was not particularly easy. (In my opinion)
Here's how to do it: (First off scrap your existing code)
In UI class add:
public Intent service;
service = new Intent(thisContext, TimerService.class);
service.putExtra("ms", ms);
startService(service);
//bind service to the UI **Important**
bindService();
IntentFilter timerFilter = new IntentFilter("TimerIntent"); // Filter that gets stuff from the service
registerReceiver(myReceiver, timerFilter);
void bindService() {
Intent newIntent = new Intent(this, TimerService.class);
bindService(newIntent, mConnection, Context.BIND_AUTO_CREATE);
mIsBound = true;
}
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className, IBinder binder) {
s = ((TimerService.MyBinder) binder).getService();
}
#Override
public void onServiceDisconnected(ComponentName className) {
s = null;
}
};
public void releaseBind() {
if (mIsBound) {
unbindService(mConnection);
mIsBound = false;
}
}
// Now in this class we need to add in the listener that will update the UI (the receiver registered above)
private BroadcastReceiver myReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
//Get Bundles
Bundle extras = intent.getExtras();
/* DO ANY UI UPDATING YOU WANT HERE (set text boxes, etc.) TAKING INFO FROM THE "extras" Bundle ie: setting the clock*/
//ie: int timerTest = extras.getInt("0");
// Now update screen with value from timerTest
}
};
Service File:
public class TimerService extends Service {
public TimerService () {
super();
}
private final IBinder mBinder = new MyBinder();
public Timer clockTimer = new Timer();
public int timer = 0;
// We return the binder class upon a call of bindService
#Override
public IBinder onBind(Intent arg0) {
return mBinder;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// After service starts this executes
Bundle extras;
extras = intent.getExtras();
/* Call a function to do stuff here. Like if you are a clock call a timer function updates every second */
// Here's an example, modify to fit your needs.
clock();
return START_STICKY;
}
public class MyBinder extends Binder {
TimerService getService() {
return TimerService.this;
}
}
public void clock() {
clockTimer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
try {
// Some function ie: Time = Time + 1 //
/* MAKE SURE YOU BROADCAST THE RECEIVER HERE. This is what you send back to the UI. IE:*/
timer = timer+ 1; // increment counter
Intent intent = new
//Bundle the timervalue with Intent
intent.putExtra("0", timer);
intent.setAction("TimerIntent");
sendBroadcast(intent); // finally broadcast to the UI
} catch(Exception ie) {
}
}
},
0, // Delay to start timer
1000); // how often this loop iterates in ms (so look runs every second)
}
There might be some syntax errors in this code as I've just modified my existing and working code to try and fit your needs. There will obviously need to also be some modifications depending on what you want to do. But follow this framework and you will be able to do what you are trying to do.
This works for me, so hopefully you can modify this to work for you. (Only thing I've left out are the imports, but you should be able to easily figure that out)
Key points:
Bind service to UI
Register listener in UI file to respond to the broadcast from inside the service.
Cheers.