Ziyan Junaideen
Ziyan Junaideen

Reputation: 3300

Android - Periodic Background Service - Advice

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.

Upvotes: 33

Views: 41976

Answers (4)

Pierre
Pierre

Reputation: 9052

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 :)

https://i.sstatic.net/vOp3q.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();
    }
}

Upvotes: 19

SohailAziz
SohailAziz

Reputation: 8034

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.

Upvotes: 8

Martin Vandzura
Martin Vandzura

Reputation: 3127

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

Upvotes: 0

Argyle
Argyle

Reputation: 3394

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"/>

Upvotes: 33

Related Questions