Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I keep a Service alive indefinitely

I'm writing an app that detects audio from the headphone jack and broadcasts Intents when certain audio conditions are met (specifically when it detects the reading of a card swipe through an auxiliary audio device).

My app has no Activities, it's just an Application and a Service.

Everything works nicely except that the Service is cleaned up by Android after a relatively short time period (~ a minute).

I'm curious what I need to do to tell Android that this is a useful Service and that it should leave it alone unless it REALLY needs its memory back. I realize that I can create an Alarm that wakes up every couple of seconds and fires up the Service if it notices that it's not there, but that seems like a kluge. Is there a more Android(y) way to keep it alive than that?

like image 483
Yevgeny Simkin Avatar asked Aug 13 '13 21:08

Yevgeny Simkin


People also ask

How do I make services run forever?

Call startService() method in Foreground Service Launcher class in your Activity to start a background service which will run forever. In order to sync something between application and server we can create a handler which run every time interval .

How do you know if a service is alive?

You can do this by making your own Interface where you declare for example " isServiceRunning() ". You can then bind your Activity to your Service, run the method isServiceRunning(), the Service will check for itself if it is running or not and returns a boolean to your Activity.

What happens to service when app is killed android?

If your Service is started by your app then actually your service is running on main process. so when app is killed service will also be stopped. So what you can do is, send broadcast from onTaskRemoved method of your service as follows: Intent intent = new Intent("com.


3 Answers

My app has no Activities, it's just an Application and a Service.

That means that your app will never run, on any Android 3.1+ device, unless you have some tie from some other application that is going to manually launch your service.

I'm writing an app that detects audio from the headphone jack and broadcasts Intents when certain audio conditions are met (specifically when it detects the reading of a card swipe through an auxiliary audio device).

Don't name your company after a geometric shape -- it's been done. :-)

I'm curious what I need to do to tell Android that this is a useful Service and that it should leave it alone unless it REALLY needs its memory back.

You are welcome to use startForeground() to declare it to be a foreground service. The tradeoff is that you will need to show a Notification, ideally one that allows the user to stop the service. Bear in mind that users may not appreciate this Notification, but you are stuck with it, particularly on Android 4.3+. You may be better served by switching from a service to an activity, so the user can launch that, swipe a card, and process whatever the transaction is.

like image 196
CommonsWare Avatar answered Oct 29 '22 16:10

CommonsWare


Use START_STICKY to keep your service around.

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
       Log.i("LocalService", "Received start id " + startId + ": " + intent);
       // We want this service to continue running until it is explicitly
       // stopped, so return sticky.
       return START_STICKY;
}

Example Use:

http://developer.android.com/reference/android/app/Service.html#LocalServiceSample

More Info:

http://developer.android.com/reference/android/app/Service.html#START_STICKY

like image 5
blackcj Avatar answered Oct 29 '22 15:10

blackcj


I tried AlarmManager. It works. I used Contex.startService() in the AlarmReceiver. And I can check if my service is running so as to decide if start the service again. So even though my service is stopped by users manually in settings or killed by some cleaning app, the service can be started again. Here is the main code below.

    package com.example.androidnetwork;

    import android.app.ActivityManager;
    import android.app.ActivityManager.RunningServiceInfo;
    import android.app.AlarmManager;
    import android.app.PendingIntent;
    import android.content.BroadcastReceiver;
    import android.content.Context;
    import android.content.Intent;
    import android.os.Bundle;
    import android.support.v7.app.ActionBarActivity;
    import android.util.Log;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.widget.Button;

public class MainActivity extends ActionBarActivity {

    private static final long INTERVAL = 5 * 1000; // unit: ms

    private Button mRegisterReceiverBtn;
    private Button mCheckNetStatusBtn;
    private Button mStopButton;
    private AlarmManager mAlarmManager;
    private PendingIntent mPendingIntent;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initData();

        initView();
    }

    private void initData() {
        mAlarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
    }

    private void initView() {
        mRegisterReceiverBtn = (Button) findViewById(R.id.activity_main_start_btn);
        mCheckNetStatusBtn = (Button) findViewById(R.id.activity_main_start_check_net_status_bnt);
        mStopButton = (Button) findViewById(R.id.activity_main_stop);
        mRegisterReceiverBtn.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                MainActivity.this.createServiceControllerPendIntent();
                mAlarmManager.setInexactRepeating(
                        AlarmManager.ELAPSED_REALTIME_WAKEUP, 0, INTERVAL,
                        mPendingIntent);
            }
        });
        mCheckNetStatusBtn.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                MainActivity.this.startActivity(new Intent(MainActivity.this,
                        NetStatusActivity.class));
            }
        });
        mStopButton.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                if (mPendingIntent != null) {
                    mAlarmManager.cancel(mPendingIntent);
                } else {
                    createServiceControllerPendIntent();
                    mAlarmManager.cancel(mPendingIntent);
                }
                // MainActivity.this.stopService(ServiceController
                // .getServiceIntent());
                Intent intent = new Intent();
                intent.setClass(getApplicationContext(),
                        NetStatusMonitorService.class);
                stopService(intent);
            }
        });

    }

    private void createServiceControllerPendIntent() {
        Intent intent = new Intent(MainActivity.this,
                ServiceController.class);
        mPendingIntent = PendingIntent.getBroadcast(MainActivity.this,
                0, intent, 0);
    }

    @Override
    protected void onDestroy() {
        deInitView();
        super.onDestroy();
    }

    private void deInitView() {

    }


    public static class ServiceController extends BroadcastReceiver {

        private static Intent sMonitorServiceIntent = null;

        @Override
        public void onReceive(Context context, Intent intent) {
            Log.d("Service Controller", "onReceiver");
            if (isServiceRunning(context, NetStatusMonitorService.class) == false) {
                String info = "starting service by AlarmManager";
                Log.d("Service Controller", info);
                sMonitorServiceIntent = new Intent(context,
                        NetStatusMonitorService.class);
                context.startService(sMonitorServiceIntent);
            }
        }

            // this method is very important
        private boolean isServiceRunning(Context context, Class<?> serviceClass) {
            ActivityManager am = (ActivityManager) context
                    .getSystemService(Context.ACTIVITY_SERVICE);
            for (RunningServiceInfo serviceInfo : am
                    .getRunningServices(Integer.MAX_VALUE)) {
                String className1 = serviceInfo.service.getClassName();
                String className2 = serviceClass.getName();
                if (className1.equals(className2)) {
                    return true;
                }
            }
            return false;
        }

        public static Intent getServiceIntent() {
            return sMonitorServiceIntent;
        }
    }

}
like image 1
peacepassion Avatar answered Oct 29 '22 16:10

peacepassion