I'm doing an app that checks the live scores. I don't know if it's the best way, but I created a Timertask, a Service and and Activity to notify.
The Timertask checks every x seconds if the score changes and if it changes, informs the Service.
If the Service is informed, it calls the Activity that will notify the user. My problem is I failed at calling the activity to Notify from the Service.
Here is my code (For the example, I didn't take the score but a variable i.
//import ...
public class MyService extends Service{
Notif notif = new Notif();
private static final String TAG = "MyService";
#Override
public IBinder onBind(Intent arg0) {
return null;
}
#Override
public void onCreate() {
Toast.makeText(this, "Congrats! MyService Created", Toast.LENGTH_LONG).show();
Log.d(TAG, "onCreate");
}
#Override
public void onStart(Intent intent, int startId) {
Toast.makeText(this, "My Service Started", Toast.LENGTH_LONG).show();
Log.d(TAG, "onStart");
Timer time = new Timer(); // Instantiate Timer Object
final ScheduleTask st = new ScheduleTask(); // Instantiate SheduledTask class
time.schedule(st, 0, 5000); // Create Repetitively task for every 1 secs
}
#Override
public void onDestroy() {
Toast.makeText(this, "MyService Stopped", Toast.LENGTH_LONG).show();
Log.d(TAG, "onDestroy");
}
public void checkI(int i){
if (i==3){
notif.initializeUIElements();
}
}
}
TimerTask
import ...
// Create a class extends with TimerTask
public class ScheduleTask extends TimerTask {
MyService myService = new MyService();
Notif notif = new Notif();
int i = 0;
// Add your task here
public void run() {
i++;
System.out.println("affichage numero " + i );
myService.checkI(i);
}
public int getI() {
return i;
}
}
Notif
import ...
public class Notif extends Activity {
private static final int NOTIFY_ME_ID = 1987;
private NotificationManager mgr = null;
ScheduleTask scheduleTask = new ScheduleTask();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mgr = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
}
void initializeUIElements() {
Notification note = new Notification(R.drawable.ic_launcher,
"Welcome to MyDoople.com", System.currentTimeMillis());
PendingIntent i = PendingIntent.getActivity(this, 0, new Intent(
this, MainActivity.class), Notification.FLAG_ONGOING_EVENT);
note.setLatestEventInfo(this, "MyDoople.com", "An Android Portal for Development",
i);
// note.number = ++count;
note.flags |= Notification.FLAG_ONGOING_EVENT;
mgr.notify(NOTIFY_ME_ID, note);
}
}
Services may be terminated by the system if resources are needed. For your requirement, it's best to use AlarmManager to periodically do something.
Here are more references: [1], [2]
Related
In our android webview app, we start a foreground service (RingtonePlayingservice.class) from our firebase.class on notification action. The foreground service in turn starts playing the ringtone vide mediaplayer. The ringtone runs to like 10 seconds and stops, so we implemented setloop parameter, but still the mediaplayer just stops without looping at all. We are at loss as where we are going wrong. The codes are as given below
Firebase.Class (summarized)
public class Firebase extends FirebaseMessagingService {
public static Ringtone ringtone;
Intent i = new Intent(this, RingtonePlayingService.class);
this.startForegroundService(i);
}
Ringtoneplayingservice class
public class RingtonePlayingService extends Service {
private static final String TAG = RingtonePlayingService.class.getSimpleName();
private static final String URI_BASE = RingtonePlayingService.class.getName() + ".";
public static final String ACTION_DISMISS = URI_BASE + "ACTION_DISMISS";
public static final String ACTION_START = URI_BASE + "ACTION_START";
private MediaPlayer mp;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand");
if (intent == null) {
Log.d(TAG, "The intent is null.");
return START_REDELIVER_INTENT;
}
String action = intent.getAction();
if (ACTION_DISMISS.equals(action)) {
int notificationId = intent.getIntExtra("notificationId", 0);
dismissRingtone();
NotificationManager notificationManager =
(NotificationManager) getSystemService(getApplicationContext().NOTIFICATION_SERVICE);
notificationManager.cancel(notificationId);
}
else {
mp = MediaPlayer.create(this, Settings.System.DEFAULT_RINGTONE_URI);
mp.setlooping (true);
mp.start();
}
return START_STICKY;
}
public void dismissRingtone() {
// stop the alarm rigntone
Intent i = new Intent(this, RingtonePlayingService.class);
this.stopService(i);
}
#Override
public void onDestroy() {
super.onDestroy();
if(mp.isPlaying())
{
mp.reset();
}
else {
}
}}
Any help would be deeply appreciated
I'm developing an app that is going to require 2 services:
HostService - A foreground service that manages music playback using the Spotify app-remote SDK. It is necessary to run this service in the foreground as I need to detect playState changes and manage playback constantly. However, this service ONLY needs to run if a condition is met, we'll call that condition isHost. This service will be bound to a SessionActivity that displays the music playing and manages playback.
ApiService - A service that continuously polls a separate web API for updates. This must also run in the foreground if the isHost condition is met as the updates may influence the music playback. However, if the user is not a host, this can be a background process that only needs to poll while the user is actively using a particular Activity. I'm not sure if this service should also be bound to the activity or not.
My question is, how should I go about setting up the ApiService differently depending on this condition? I've started to implement these services below but I'm not entirely sure what I have done makes sense. Additionally, am I doing the right thing by using an event handler the way I am? I don't fully understand Intents and I'm not sure if I should be using broadcast messages and such instead.
SessionActivity.java
class SessionActivity extends AppCompatActivity implements HostEventHandler, ApiEventHandler {
private boolean isHost;
private String data;
private String UID;
private ApiService api;
private HostService host;
private boolean hostBound;
private boolean apiBound;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_session);
isHost = getIntent().getBooleanExtra("isHost", false);
data = getIntent().getStringExtra("data");
UID = Settings.Secure.getString(getContentResolver(), Settings.Secure.ANDROID_ID);
}
private ServiceConnection hostConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className, IBinder service) {
Log.d(Constants.TAG, "Bound to HostService");
HostService.LocalBinder binder = (HostService.LocalBinder) service;
host = (HostService) binder.getService()
host.registerEventHandler(this);
hostBound = true;
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
Log.e(Constants.TAG, "onServiceDisconnected");
hostService = null;
}
};
private ServiceConnection apiConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className, IBinder service) {
Log.d(Constants.TAG, "Bound to ApiService");
HostService.LocalBinder binder = (ApiService.LocalBinder) service;
api = (ApiService) binder.getService()
api.registerEventHandler(this);
apiBound = true;
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
Log.e(Constants.TAG, "onServiceDisconnected");
apiService = null;
}
};
protected void onStart() {
super.onStart();
Log.d(Constants.TAG, "Binding to services...");
Intent intent = new Intent(this, ApiService.class);
intent.putExtra("data", data);
intent.putExtra("user", Constants.UID);
bindService(intent, connection, Context.BIND_AUTO_CREATE);
if (isHost) {
Intent intent = new Intent(this, HostService.class);
bindService(intent, connection, Context.BIND_AUTO_CREATE);
{
}
#Override
protected void onStop() {
super.onStop();
unbindService(apiConnection);
apiBound = false;
if (isHost) {
unbindService(hostService);
hostBound = false;
}
}
// HostEventHandler and ApiEventHandler methods...
}
HostService.java
public class HostService extends Service {
private final IBinder binder = new LocalBinder();
private HostEventHandler handler;
public class LocalBinder extends Binder {
HostService getService() {
return HostService.this;
}
}
#Override
public IBinder onBind(Intent intent) {
Log.d(Constants.TAG, "onBind");
return binder;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
createNotificationChannel();
Intent notificationIntent = new Intent(this, SessionActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("Foreground Service")
.setContentText("Foreground service is running...")
.setSmallIcon(R.drawable.logo)
.setContentIntent(pendingIntent)
.build();
startForeground(1, notification);
connect(); // This connects to spotify
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
disconnect();
}
public registerEventHandler(HostEventHandler handler) {
this.handler = handler;
}
private void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel serviceChannel = new NotificationChannel(
CHANNEL_ID,
"Foreground Service Channel",
NotificationManager.IMPORTANCE_DEFAULT
);
NotificationManager manager = getSystemService(NotificationManager.class);
manager.createNotificationChannel(serviceChannel);
}
}
}
ApiService.java
public class ApiService extends Service {
private final IBinder binder = new LocalBinder();
private ApiEventHandler handler;
private final Timer timer;
private boolean connected = false;
private String data;
private String UID;
private ApiState state;
public class LocalBinder extends Binder {
HostService getService() {
return ApiService.this;
}
}
#Override
public IBinder onBind(Intent intent) {
Log.d(Constants.TAG, "onBind");
return binder;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (!connected) {
data = intent.getStringExtra("data");
UID = intent.getStringExtra("user");
connect();
}
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
disconnect();
}
public void registerEventHandler(ApiEventHandler handler) {
this.handler = handler;
}
public ApiState getState() {
return state;
}
private void connect() {
if (connected) return;
class Updater extends TimerTask {
#Override
public void run() {
state = fetchUpdatedState(); // This will implement the web request
handler.onStateUpdate(state);
Log.d(Constants.TAG, "Polling API...");
timer.schedule(new Updater(), Constants.REFRESH_DELAY);
}
}
timer.schedule(new Updater(), Constants.REFRESH_DELAY);
connected = true;
}
}
I have an app that records the time of the job, i mean that calculates the job time for that purpose i used chronometer to run the time. Since the job is 9 hours long so user can't open the app for that long. For that purpose i am using the Service which indicate the time. Since i cannot use Chronometer because
Chronometer is a UI widget (actually a TextView) in Android. So, i can't use it for non-UI purposes. So i have to use timer to do the job. But i do not know how can i achieve this. Any code or help is appreciated. Thanks
When i hit the start button the chronometer starts like this
and my service also started but i get the time as 00:00:00 like this
i just want that timer should run in the service and i can see the time in service and i do not want to deal or use the time that is running in service, the time in service will show user that how much time they spend on job.
Service Class
public class ServiceTimer extends Service {
// Chronometer chronometer ;
//String valueOfTime ;
#Override
public void onCreate() {
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
String input = intent.getStringExtra("inputExtra");
// chronometer = new Chronometer(this);
//chronometer.setText("00:00:00");
//chronometer.setOnChronometerTickListener(new //Chronometer.OnChronometerTickListener() {
// #Override
// public void onChronometerTick(Chronometer chronometer) {
// CharSequence text = chronometer.getText();
// if (text.length() == 5) {
// chronometer.setText("00:"+text);
// } else if (text.length() == 7) {
// chronometer.setText("0"+text);
// }
//}
// });
// chronometer.start();
//before i know about chronometer that i cannot use it in service
// this is what i have so for with chronometer to achieve
// but failed ...
Intent notificationIntent = new Intent(this, Timer_FullTime.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this,
0, notificationIntent, 0);
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle(chronometer.getText().toString())
.setSmallIcon(R.mipmap.logoback)
.setContentText(input)
.setContentIntent(pendingIntent)
.build();
startForeground(1, notification);
//do heavy work on a background thread
//stopSelf();
return START_NOT_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
UPDATE this is how i get what i wanted or asked in the question
public class ServiceTimer extends Service {
private int THE_ID_TO_UPDATE = 1;
private static Timer timer = new Timer();
private Context ctx;
private int second = 0 ;
NotificationManager notificationManager ;
private int minute = 0 ;
private int hour = 0 ;
//we are going to use a handler to be able to run in our TimerTask
final Handler handler = new Handler();
NotificationCompat.Builder notification ;
#Override
public void onCreate() {
super.onCreate();
super.onCreate();
ctx = this;
}
private class mainTask extends TimerTask
{
public void run()
{
second = second + 1 ;
if (second == 60){
minute++ ;
second = 0 ;
}
if (minute == 60){
hour++;
minute = 0 ;
second = 0 ;
}
notification.setContentText( hour + "h " + minute + "m " + second+"s");
notificationManager.notify(THE_ID_TO_UPDATE , notification.build());
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
String input = intent.getStringExtra("inputExtra");
Intent notificationIntent = new Intent(this, Timer_FullTime.class) ;
PendingIntent pendingIntent = PendingIntent.getActivity(this,
0, notificationIntent, 0) ;
notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
notification = new NotificationCompat.Builder(this, CHANNEL_ID);
notification.setContentTitle(input);
notification.setSmallIcon(R.mipmap.logoback);
notification.setOnlyAlertOnce(true);
notification.setWhen(System.currentTimeMillis());
notification.setContentIntent(pendingIntent);
notification.setLights(Color.RED, 1000, 1000);
notification.setVibrate(new long[]{0, 400, 250, 400});
notification.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION));
notification.build();
notificationManager.notify(THE_ID_TO_UPDATE , notification.build());
startForeground(THE_ID_TO_UPDATE, notification.build());
timer.scheduleAtFixedRate(new mainTask(), 0, 1000);
return START_NOT_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
timer.cancel();
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
You could try to use a Timer with a TimerTask:
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
// Update your counter/notification each second
}
}, 0, 1000);
Link to official documentation: https://developer.android.com/reference/java/util/Timer
I need to create a service that allow my application to work also when I close it, I’ve tried with STICKY_SERVICE but it doesn’t work... if anyone can decribe me how I can do this please answer this question.
It works with android 7.1 and it doesn’t with other versions
Here is my code...
public class SensorService extends Service {
public int counter=0;
public SensorService(Context applicationContext) {
super();
Log.i("HERE", "here I am!");
}
public SensorService() {
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
startTimer();
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
Log.i("EXIT", "ondestroy!");
stoptimertask();
Intent broadcastIntent = new Intent("RestartSensor");
sendBroadcast(broadcastIntent);
}
private Timer timer;
private TimerTask timerTask;
long oldTime=0;
public void startTimer() {
//set a new Timer
timer = new Timer();
//initialize the TimerTask's job
initializeTimerTask();
//schedule the timer, to wake up every 1 second
timer.schedule(timerTask, 1000, 1000); //
}
/**
* it sets the timer to print the counter every x seconds
*/
public void initializeTimerTask() {
timerTask = new TimerTask() {
public void run() {
Log.i("in timer", "in timer ++++ "+ (counter++));
}
};
}
/**
* not needed
*/
public void stoptimertask() {
//stop the timer, if it's not already null
if (timer != null) {
timer.cancel();
timer = null;
}
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
This is my service Restarter...
public class SensorRestarterBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.i(SensorRestarterBroadcastReceiver.class.getSimpleName(), "Service Stops");
context.startService(new Intent(context, SensorService.class));
}
}
And the mainClass
public class MainActivity extends AppCompatActivity {
Intent mServiceIntent;
private SensorService mSensorService;
Context ctx;
public Context getCtx() {
return ctx;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ctx = this;
setContentView(R.layout.activity_main);
mSensorService = new SensorService(getCtx());
mServiceIntent = new Intent(getCtx(), mSensorService.getClass());
if (!isMyServiceRunning(mSensorService.getClass())) {
startService(mServiceIntent);
}
}
private boolean isMyServiceRunning(Class<?> serviceClass) {
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (serviceClass.getName().equals(service.service.getClassName())) {
Log.i ("isMyServiceRunning?", true+"");
return true;
}
}
Log.i ("isMyServiceRunning?", false+"");
return false;
}
#Override
protected void onDestroy() {
stopService(mServiceIntent);
Log.i("MAINACT", "onDestroy!");
super.onDestroy();
}
}
This restartthe service correctly but after 3/4 seconds it die.
I've added this to my manifest
<service
android:name=".SensorService"
android:enabled="true" >
</service>
<receiver
android:name=".SensorRestarterBroadcastReceiver"
android:enabled="true"
android:exported="true"
android:label="RestartServiceWhenStopped">
<intent-filter>
<action android:name="RestartSensor"/>
</intent-filter>
</receiver>
Add the following code to your sensor service and edit as per your need. You need to bind the sticky service to a notification to keep the service alive and start in the foreground.
#Override
public void onCreate() {
super.onCreate();
Intent notifIntent = new Intent(this, SensorService.class);
PendingIntent pi = PendingIntent.getActivity(this, 0, notifIntent, 0);
Notification notification = new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.smslogo_100x100)
.setColor(ContextCompat.getColor(this, R.color.colorAccent))
.setContentTitle(getResources().getString(R.string.app_name))
.setContentText("Running")
.setContentIntent(pi)
.build();
startForeground(101010, notification);
}
This will rectify the issue you are facing and the service will run forever.
Please guide me in this. Appreciate all your help.
My background service is toasting ABC
//-------------------String displayingText = "ABC";-----------------
And I have two strings, ABC and DEF declared in mainactivity.java
How do I pass the value displayingText from main activity to this service.
How do I change the displayingText to DEF after the toast ABC finished.
MyService.Java
public class MyService extends Service {
public static final long INTERVAL=3000;//variable to execute services every 5 second
private Handler mHandler=new Handler(); // run on another Thread to avoid crash
private Timer mTimer=null; // timer handling
//the get intent dont work. where or how should i put it?
Intent myIntent = getIntent();
if (myIntent !=null && myIntent.getExtras()!=null)
String value = myIntent.getExtras().getString(PassToService);
#Nullable
#Override
public IBinder onBind(Intent intent) {
throw new UnsupportedOperationException("unsupported Operation");
}
#Override
public void onCreate() {
// cancel if service is already existed
if(mTimer!=null)
mTimer.cancel();
else
mTimer=new Timer(); // recreate new timer
mTimer.scheduleAtFixedRate(new TimeDisplayTimerTask(),0,INTERVAL);// schedule task
}
#Override
public void onTaskRemoved(Intent rootIntent) {
stopSelf();///its will stop service
super.onTaskRemoved(rootIntent);
}
#Override
public void onDestroy() {
Toast.makeText(this, "In Destroy", Toast.LENGTH_SHORT).show();//display toast when method called
mTimer.cancel();//cancel the timer
super.onDestroy();
}
//inner class of TimeDisplayTimerTask
private class TimeDisplayTimerTask extends TimerTask {
#Override
public void run() {
// run on another thread
mHandler.post(new Runnable() {
#Override
public void run() {
// display toast at every 10 second
//String displayingText = "ABC";
String displayingText = myIntent.getStringExtra("PassToService");
final Toast Notify = Toast.makeText(getApplicationContext(), displayingText, Toast.LENGTH_SHORT);
Notify.setGravity(Gravity.CENTER, 0, 0);
Notify.show();
Handler cancelToast = new Handler();
cancelToast.postDelayed(new Runnable() {
#Override
public void run() {
Notify.cancel();
}
}, 1000);
}
});
}
}
}
You can do it by passing value from activity to service-
startService(new Intent(YourActivity.Service.class).putExtra("key","value"));