I need to create a background service that starts and stops with two buttons. My service will cycle every 5 minutes and it will take data from an online database. I read somewhere that IntentService class is not used for loops. I would override onStartCommand so it will return START_STICKY. If i do that in this class my service doesn't start. How can I do this?
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void start(View view){
startService(new Intent(this, ForegroundService.class));
}
public void stop(View view){
stopService(new Intent(this, ForegroundService.class));
}
}
public class ForegroundService extends IntentService{
private boolean stato;
public ForegroundService(){
super("ForegroundService");
}
#Override
public void onCreate(){
super.onCreate();
Toast.makeText(this, "Service Started", Toast.LENGTH_SHORT).show();
}
#Override
protected void onHandleIntent(Intent i){
stato = true;
int n=0;
while(stato)
{
Log.i("PROVA SERVICE", "Evento n."+n++);
try {
Thread.sleep(1000);
}
catch (InterruptedException e)
{ }
}
}
#Override
public void onDestroy() {
stato = false;
Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
super.onDestroy();
}
}
Only have a service running when it is actively delivering value to the user. Sitting and watching the clock tick is not actively delivering value to the user.
Also, please understand that what you want ("cycle every 5 minutes and it will take data from an online database") may not be what the user wants and certainly is not what Google wants. Too many developers are doing stuff like this, and battery life is suffering as a result.
Generally speaking, your best solution (given your stated objective) is JobScheduler, perhaps falling back to AlarmManager if your minSdkVersion is below 21. Both of those allow you to schedule periodic work. Your process does not need to be running in between those bits of work. You teach JobScheduler or AlarmManager how frequently to trigger the work, and you do the work in a JobService or IntentService.
Just bear in mind that on Android 6.0+, unless the user tells Android via the Settings app to leave your app alone, your app will eventually enter Doze mode or app standby mode, and you will not be able to get control every five minutes.
Related
Using Service for achieving the Question purpose.
code :
inside manifest :
<service
android:name=".MyService"
android:enabled="true" />
service class :
public class MyService extends Service {
private MediaPlayer media;
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
media = MediaPlayer.create(this, Settings.System.DEFAULT_RINGTONE_URI);
media.setLooping(true);
media.start();
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
media.stop();
}
My Java class :
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void startMethod(View v) {
startService(new Intent(this, MyService.class));
}
public void stopMethod(View v) {
stopService(new Intent(this, MyService.class));
}
So, the issue is that, When I am killing the app, media player stops the playing music or my default ringtone. since, i am using START_STICKY, it should run in background.
What might be the issue ? I need to play the music even if app killed using service in android. Please, guide if there something wrong. Thanks.
EDIT
The above issue is working fine for lower version devices. For higher version we can use JobService.
Now, the Question is What if I want to check the specific time in background service, and at particular time I have to display a toast message. So far, I have done it inside onStartCommand() method and comparing time with .equals method. But, I think there's another way to do so..
my code inside onStartCommand():
if(currentTime.equals("Thu Mar 29 06:18:00 GMT 2018")){
Toast.makeText(this, ""+currentTime, Toast.LENGTH_SHORT).show();
}
if(currentTime.equals("Thu Mar 29 06:20:00 GMT 2018")){
Toast.makeText(this, ""+currentTime, Toast.LENGTH_SHORT).show();
}
if(currentTime.equals("Thu Mar 29 06:21:00 GMT 2018")){
Toast.makeText(this, ""+currentTime, Toast.LENGTH_SHORT).show();
}
Toast not displaying at these particular times. because it display only when the onStartCommand() method calls. So, how can I achieve this ?
If this is working in lower version android devices, then you can try and use a JobService for higher android version devices.
Follow the links below & become a pro at JobScheduling:
https://github.com/evernote/android-job
https://github.com/firebase/firebase-jobdispatcher-android
http://blog.teamtreehouse.com/scheduling-work-jobscheduler
https://blog.klinkerapps.com/android-o-background-services/
I wonder if I can keep the app service running inspite of the app is swiped out or closed. I want to send the gps data to the server all the time whether the app is opened or in the background or is closed (swiped out from the recent app list etc). I've tried 'service' but is not working. How can I do it. Can sb give me some hints on it please? Thankyou.
public class MainActivity extends AppCompatActivity{
BroadcastReceiver mReceiver;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startService(new Intent(getBaseContext(),TestService.class));
}
}
public class TestService extends Service {
#Override
public void onDestroy() {
super.onDestroy();
Log.e("service", " destroyed");
Toast.makeText(this, "Service destroyed", Toast.LENGTH_SHORT).show();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "service started", Toast.LENGTH_SHORT).show();
Log.e("service", " onStartCommand");
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
You can use
JobScheduler
This API allows you to run scheduled service and the android system
will batch all the services from different applications and run them
together in some particular timeframe
Firebase Job Dispatcher
The Firebase JobDispatcher is a library for scheduling background jobs
in your Android app. It provides a JobScheduler-compatible API that
works on all recent versions of Android (API level 9+) that have
Google Play services installed.
for reference you can use following links
reference 1
reference 2
reference 3
referennce 4
reference 5
reference 6
What is the recommended approach for checking for new data regardless if the app is in the foreground or background? I am wondering which Android API people are typically using to do this. There seems to be a few ways to achieve my goal, and I want to make sure I'm on the right path.
I have something put together which uses AlarmManager.SetInexactRepeating() to call an IntentService which does the sync and inserts/updates data in the database. This works while the app is in the foreground and background, but if I force stop the app then I keep seeing "Unfortunately, has stopped working" messages when the AlarmManager alarm would've triggered. In this case, I only care about checking for new data only when the app is running in the foreground or background.
My first thought is to detect when the app is force closed, and stop the alarm, but that does not seem possible. So I am asking here, is my approach wrong? If so, which approach is used to perform some periodic task regardless if the phone is in the foreground or background? The problem with the AlarmManager solution I am using is the alarms continue to fire even when the app is closed.
If your idea is to check if your API has new data and perform a background sync to your local database or other data storage, I think you would like to take a look at this:
Creating a Sync Adapter
Running a Sync Adapter
The Sync adapter is the recommended way of achieving this in Android. The pros of using it are multiple:
Optimisations out of the box - the OS bundles calls, uses the most appropriate windows to run the sync adapter at a minimal bandwidth and battery cost
The lifecycle of your background sync component is managed internally by the OS
Observers can be notified when data has been changed so the UI can be updated easily
Multiple ways of running the sync - at intervals, automatically with the OS message to keep TCP/IP connections open or on demand
However, implementing this requires some things, that can cause a bit of a pain at first:
It is mandatory that the adapter works with a ContentProvider
Sync Adapters use Account for authentication. If this is not needed, a Stub has to be provided
For backgrounding on Android usually you use even a Service that can run alone and independently from the App or a Bounded service that takes and returns data from the App. A complete reference on backgrounding can be found here
Using a Service is the right way to go. Have your app start the Service and it will continue running while the app is in the foreground or the background. Then, if you want to kill the Service when your app closes, you could just call stopService(yourServiceIntent); from the onDestroy() override in your app's activity. That should effectively shut down the service when the app closes.
So some sample code of how this works (taken from the Services docs)...
The Service (just Logs a message every 1 second for 60 seconds):
public class MyService extends Service {
private Looper mServiceLooper;
private ServiceHandler mServiceHandler;
// Handler that receives messages from the thread
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
#Override
public void handleMessage(Message msg) {
long endTime = System.currentTimeMillis() + 60*1000;
while (System.currentTimeMillis() < endTime) {
synchronized (this) {
try {
wait(1000);
Log.d("SERVICE", "The service is still running.");
} catch (Exception e) {
e.printStackTrace();
}
}
}
stopSelf(msg.arg1);
}
}
#Override
public void onCreate() {
HandlerThread thread = new HandlerThread("ServiceStartArguments", Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
mServiceHandler.sendMessage(msg);
return START_NOT_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onDestroy() {
}
}
And in your activity you would do something like:
public class MainActivity extends AppCompatActivity {
Intent serviceIntent;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
serviceIntent = new Intent(this, MyService.class);
startService(serviceIntent);
}
#Override
protected void onDestroy() {
stopService(serviceIntent);
super.onDestroy();
}
I am starting and stopping a service from an activity calling startSertice()/stopService() (when user select/deselect a check box and service is not bounded). Every thing is working fine even though the activity that starts the service is closed. In "Running apps" I'm able to see 1 processes, 1 service running. But when I kill the application, using Task manager kind of application, the process is getting killed and service is not working though the running apps showing 0 processes, 1 service. How to make the service working in such situations? I observed the same in some other security applications like Avast with 0 processes, 1 service, while service working properly. Please help me out on this.
Following is the activity on click method
#Override
public void onClick(View arg0) {
boolean value = checkBox.isChecked();
if(value){
// start the service
startService(new Intent(this, MyService.class));
Toast.makeText(this, "Background service started", Toast.LENGTH_SHORT).show();
} else {
stopService(new Intent(this, MyService.class));
Toast.makeText(this, "Background service stopped", Toast.LENGTH_SHORT).show();
}
}
Following is the service class:
public class MyService extends Service{
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
#Override
public void onCreate(){
super.onCreate();
Log.d("######Service","Service created successfully");
}
#Override
public int onStartCommand(Intent intent, int flags, int stardId){
Log.d("######Service","Service started successfully");
IntentFilter powerButtonIntentFilter = new IntentFilter();
powerButtonIntentFilter.addAction("android.intent.action.SCREEN_ON");
this.registerReceiver(pbReceiver, powerButtonIntentFilter);
Log.d("#######","Power button register registered");
return START_STICKY;
}
#Override
public void onDestroy(){
Log.d("######Service","Service destroyed successfully");
this.unregisterReceiver(pbReceiver);
Log.d("#######","Power button register un-registered");
super.onDestroy();
}
}
Everything is working fine in ideal case. SCREEN ON action is being listened by the broadcast receiver properly even when the activity that starts the service is closed. I am able to see the app running in settings. But when I force kill the process using Task Manager kind of applications, processes is getting killed and in running apps I am able to see 0 process, 1 service running. Though the service is running after force killing the app from Task manager, broadcast receiver is not listening to the SCREEN ON action. Please help me out on this.
Thanks, JK
I am working on an app that will relay information about its location to a remote server. I am intending to do it by doing a simple HTTP post to the web-server and all is simple and fine.
But according to the spec, the app needs to execute itself from time to time, lets say once in every 30 mins. Be independent of the interface, meaning which it needs to run even if the app is closed.
I looked around and found out that Android Services is what needs to be used. What could I use to implement such a system. Will the service (or other mechanism) restart when the phone restarts?
Thanks in advance.
Create a Service to send your information to your server. Presumably, you've got that under control.
Your Service should be started by an alarm triggered by the AlarmManager, where you can specify an interval. Unless you have to report your data exactly every 30 minutes, you probably want the inexact alarm so you can save some battery life.
Finally, you can register your app to get the bootup broadcast by setting up a BroadcastReceiver like so:
public class BootReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
// Register your reporting alarms here.
}
}
}
You'll need to add the following permission to your AndroidManifest.xml for that to work. Don't forget to register your alarms when you run the app normally, or they'll only be registered when the device boots up.
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
Here is a semi-different way to keep the service going forever. There is ways to kill it in code if you'd wish
Background Service:
package com.ex.ample;
import android.app.Service;
import android.content.*;
import android.os.*;
import android.widget.Toast;
public class BackgroundService extends Service {
public Context context = this;
public Handler handler = null;
public static Runnable runnable = null;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
Toast.makeText(this, "Service created!", Toast.LENGTH_LONG).show();
handler = new Handler();
runnable = new Runnable() {
public void run() {
Toast.makeText(context, "Service is still running", Toast.LENGTH_LONG).show();
handler.postDelayed(runnable, 10000);
}
};
handler.postDelayed(runnable, 15000);
}
#Override
public void onDestroy() {
/* IF YOU WANT THIS SERVICE KILLED WITH THE APP THEN UNCOMMENT THE FOLLOWING LINE */
//handler.removeCallbacks(runnable);
Toast.makeText(this, "Service stopped", Toast.LENGTH_LONG).show();
}
#Override
public void onStart(Intent intent, int startid) {
Toast.makeText(this, "Service started by user.", Toast.LENGTH_LONG).show();
}
}
Here is how you start it from your main activity or wherever you wish:
startService(new Intent(this, BackgroundService.class));
onDestroy() will get called when the application gets closed or killed but the runnable just starts it right back up.
I hope this helps someone out.
The reason why some people do this is because of corporate applications where in some instances the users/employees must not be able to stop certain things :)
http://i.imgur.com/1vCnYJW.png
EDIT
Since Android O (8.0) you have to use JobManager for scheduled tasks. There is a library called Android-Job by Evernote which will make periodic background work a breeze on all Android versions. I have also made a Xamarin Binding of this library.
Then all you need to do is the following:
In your application class:
public class MyApp extends Application {
#Override
public void onCreate() {
super.onCreate();
JobManager.create(this).addJobCreator(new MyJobCreator());
}
}
Create the following two classes YourJobCreator and YourSyncJob(Where all the work will be done. Android allocates time for all the background jobs to be run. For android versions < 8.0 it will still run with an Alarm manager and background service as per normal)
public class MyJobCreator implements JobCreator {
#Override
#Nullable
public Job create(#NonNull String tag) {
switch (tag) {
case MySyncJob.TAG:
return new MySyncJob();
default:
return null;
}
}
}
public class MySyncJob extends Job {
public static final String TAG = "my_job_tag";
#Override
#NonNull
protected Result onRunJob(Params params) {
//
// run your job here
//
//
return Result.SUCCESS;
}
public static void scheduleJob() {
new JobRequest.Builder(MySyncJob.TAG)
.setExecutionWindow(30_000L, 40_000L) //Every 30 seconds for 40 seconds
.build()
.schedule();
}
}
You should schedule your service with alarm manager, first create the pending intent of service:
Intent ii = new Intent(getApplicationContext(), MyService.class);
PendingIntent pii = PendingIntent.getService(getApplicationContext(), 2222, ii,
PendingIntent.FLAG_CANCEL_CURRENT);
Then schedule it using alarm manager:
//getting current time and add 5 seconds to it
Calendar cal = Calendar.getInstance();
cal.add(Calendar.SECOND, 5);
//registering our pending intent with alarmmanager
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP,cal.getTimeInMillis(), pi);
this will launch your service after 5 seconds of current time. You can make your alarm repeating.
You can use Alarm Manager to start Service at specified time and then repeat alarm in specified interval. When alarm goes on you can start service and connect to server and make what you want