Android:保持后台服务活着(防止进程死亡)

时间:2010-10-04 15:39:49

标签: android service process alarmmanager

我有一项定义为的服务:

public class SleepAccelerometerService extends Service implements SensorEventListener

基本上,我正在制作一个应用程序,当用户在床上用他或她的手机/设备睡觉时,出于各种原因监视加速度计活动。这是一项长期服务,不得在夜间杀死。根据夜间有多少后台应用程序和定期进程,android有时会终止我的进程,从而结束我的服务。例如:

10-04 03:27:41.673: INFO/ActivityManager(1269): Process com.androsz.electricsleep (pid 16223) has died.
10-04 03:27:41.681: INFO/WindowManager(1269): WIN DEATH: Window{45509f98 com.androsz.electricsleep/com.androsz.electricsleep.ui.SleepActivity paused=false}

我不想强迫用户将“SleepActivity”或我应用中的其他活动作为前景。我不能定期运行我的服务,因为它不断拦截onSensorChanged。

任何提示?源代码在这里:http://code.google.com/p/electricsleep/

7 个答案:

答案 0 :(得分:72)

对于Android 2.0或更高版本,您可以使用startForeground() method在前台启动服务。

documentation says the following

  

已启动的服务可以使用startForeground(int, Notification) API将服务置于前台状态,系统认为该服务是用户主动了解的内容,因此在内存不足时不能进行查杀。 (从理论上讲,服务在当前前台应用程序的极端内存压力下被杀死仍然是可能的,但实际上这不应该是一个问题。)

主要用于在杀死服务时对用户造成破坏,例如杀死音乐播放器服务会阻止音乐播放。

您需要为正在执行部分的通知栏中显示的方法提供Notification

答案 1 :(得分:16)

当您使用BIND_AUTO_CREATE将服务绑定到Activity时,您的服务将在您的活动被销毁和解除绑定后被杀死。它不依赖于你如何实现你的服务unBind方法它仍将被杀死。

另一种方法是使用Activity中的startService方法启动服务。这样即使您的Activity被销毁,您的服务也不会被销毁甚至暂停,但您必须在适当时使用stopSelf / stopService自行暂停/销毁它。

答案 2 :(得分:11)

作为Dave already pointed out,您可以使用前台优先级运行Service。但是这种做法只应在绝对必要的时候使用,即如果服务被Android杀死会导致糟糕的用户体验。这就是“前景”的真正含义:你的应用程序在某种程度上处于前台,如果它被杀死,用户会立即注意到它(例如因为它播放了一首歌或一段视频)。

在大多数情况下,请求服务的前台优先级会产生反作用!

为什么?当Android决定杀死Service时,它会这样做,因为它缺少资源(通常是RAM)。基于不同的优先级类,Android决定终止哪些正在运行的进程以及这些服务,以便释放资源。这是一个您希望发生的健康过程,以便用户获得流畅的体验。如果您没有充分理由请求前台优先级,只是为了防止您的服务被杀,它很可能会导致糟糕的用户体验。或者,您能保证您的服务保持在最小的资源消耗范围内并且没有内存泄漏吗? 1

Android提供 sticky services 来标记应该在一段宽限期后重新启动的服务(如果它们被杀死)。这种重启通常会在几秒钟内完成。

您要为Android编写XMPP客户端的图像。您是否应该为包含XMPP连接的Service请求前台优先级?绝对没有,绝对没有理由这样做。但是您希望使用START_STICKY作为服务的onStartCommand方法的返回标记。因此,当有资源压力时,您的服务会停止,并在情况恢复正常后重新启动。

1 :我很确定很多Android应用都有内存泄漏。这是休闲(桌面)程序员不关心的东西。

答案 3 :(得分:5)

我有类似的问题。在某些设备上,Android会杀死我的服务,甚至startForeground()也无济于事。我的客户不喜欢这个问题。我的解决方案是使用AlarmManager类来确保服务在必要时运行。我用AlarmManager创建了一种看门狗定时器。它会不时检查服务是否应该运行并重新启动它。 此外,我使用SharedPreferences来保持标志是否应该运行服务。

创建/取消我的看门狗定时器:

void setServiceWatchdogTimer(boolean set, int timeout)
{
    Intent intent;
    PendingIntent alarmIntent;
    intent = new Intent(); // forms and creates appropriate Intent and pass it to AlarmManager
    intent.setAction(ACTION_WATCHDOG_OF_SERVICE);
    intent.setClass(this, WatchDogServiceReceiver.class);
    alarmIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
    AlarmManager am=(AlarmManager)getSystemService(Context.ALARM_SERVICE);
    if(set)
        am.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + timeout, alarmIntent);
    else
        am.cancel(alarmIntent);
}

从看门狗定时器接收和处理意图:

/** this class processes the intent and
 *  checks whether the service should be running
 */
public static class WatchDogServiceReceiver extends BroadcastReceiver
{
    @Override
    public void onReceive(Context context, Intent intent)
    {

        if(intent.getAction().equals(ACTION_WATCHDOG_OF_SERVICE))
        {
            // check your flag and 
            // restart your service if it's necessary
            setServiceWatchdogTimer(true, 60000*5); // restart the watchdogtimer
        }
    }
}

确实,我使用WakefulBroadcastReceiver代替BroadcastReceiver。我用BroadcastReceiver给你的代码只是为了简化它。

答案 4 :(得分:4)

http://developer.android.com/reference/android/content/Context.html#BIND_ABOVE_CLIENT

public static final int BIND_ABOVE_CLIENT - 在 API级别14

中添加

bindService(Intent, ServiceConnection, int)的标志:表示绑定到此服务的客户端应用程序认为该服务比应用程序本身更重要。设置后,平台将尝试让内存杀手杀死应用程序,然后再杀死它所绑定的服务,尽管不能保证这种情况。

同一组的其他标志是:BIND_ADJUST_WITH_ACTIVITY,BIND_AUTO_CREATE,BIND_IMPORTANT,BIND_NOT_FOREGROUND,BIND_WAIVE_PRIORITY。

请注意,BIND_AUTO_CREATE的含义在ICS中已更改,并且 未指定 BIND_AUTO_CREATE 的旧应用程序将自动拥有标记 BIND_WAIVE_PRIORITY BIND_ADJUST_WITH_ACTIVITY < em>为他们设置。

答案 5 :(得分:2)

保持较小的服务足迹,这降低了Android关闭应用程序的可能性。你不能阻止它被杀死,因为如果你可以,那么人们可以很容易地创建持久的间谍软件

答案 6 :(得分:2)

我正在研究一个应用程序并面临通过app kill杀死我的服务的问题。我研究谷歌,发现我必须让它前景。以下是代码:

public class UpdateLocationAndPrayerTimes extends Service {

 Context context;
@Override
public void onCreate() {
    super.onCreate();
    context = this;
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {

    StartForground();
    return START_STICKY;
}

@Override
public void onDestroy() {


    super.onDestroy();
}

@Nullable
@Override
public IBinder onBind(Intent intent) {
    return null;
}


private void StartForground() {
    LocationChangeDetector locationChangeDetector = new LocationChangeDetector(context);
    locationChangeDetector.getLatAndLong();
    Notification notification = new NotificationCompat.Builder(this)
            .setOngoing(false)
            .setSmallIcon(android.R.color.transparent)

            //.setSmallIcon(R.drawable.picture)
            .build();
    startForeground(101,  notification);

    }
}

啤酒花它可能有帮助!!!!