Android服务:START_STICKY不适用于Kitkat

时间:2013-12-19 04:21:17

标签: android android-service android-broadcast

我在应用程序中使用服务来监听用户按下他/她的电源按钮的次数。实施在所有设备上都运行良好。但是当我在Android Kitkat上测试应用程序时,我注意到了一些错误。

只要我将应用程序从最新应用程序中移开,应用程序就不再会监听电源按钮。

以下是我正在使用的代码:

public class Receiver extends Service {

    Notification notification;
    private static final int NOTIFICATION_ID = 0;
    NotificationManager manager;
    PendingIntent toOpen;
    Intent intent;
    private BroadcastReceiver POWER_BUTTON = new Powerbuttonrecceiver();

    @Override
    public IBinder onBind(Intent intent) {
        // TODO Auto-generated method stub
        return null;
    }

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

        IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
        filter.addAction(Intent.ACTION_SCREEN_OFF);
        registerReceiver(POWER_BUTTON, filter);
        startNotify();
        return START_STICKY;
    }

    @Override
    public void onDestroy() {
        // TODO Auto-generated method stub
        unregisterReceiver(POWER_BUTTON);
        dismissNotification();
        super.onDestroy();
    }

    public void startNotify(){
        manager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
        int icon = R.drawable.ic_launcher_drop;
        CharSequence tickerText = "Service activated";
        CharSequence tickerContent = "Service is now on. You can press your power button and the app will listen to it. Tap to turn this feature off";
        intent = new Intent(Receiver.this, Options.class);
        toOpen = PendingIntent.getActivity(getApplicationContext(), 0, intent, 0);

        notification = new NotificationCompat.Builder(getApplicationContext())
        .setContentTitle(tickerText)
        .setContentText(tickerContent)
        .setSmallIcon(icon)
        .setOngoing(true)
        .setContentIntent(toOpen)
        .build();
        manager.notify(NOTIFICATION_ID, notification);
    }

    public void dismissNotification(){
        manager.cancel(NOTIFICATION_ID);
    }

}

正如人们可以注意到我正在使用通知来表示该服务处于活动状态。令我困惑的是,在从最新应用程序轻扫后,通知仍然存在,什么是无效的BroadcastReceiver?或者是假的。

在应用程序onDestroy中,我没有调用任何函数来注册或取消注册以及停止服务。再一次,这个问题只出现在Android KitKat中。如果你们知道发生了什么事,请。请帮忙:)

更新:我也注意到了Kitkat上的Play Music,当我将它从最近的应用程序中移开时音乐会停止。这是Kitkat的错误吗?但是SoundCloud上的声音/媒体播放器服务即使从最近的应用程序中滑落也能正常工作。

更新 在android问题跟踪器上记录为Issue 63618。 阅读问题评论以获取更多详细信息。

5 个答案:

答案 0 :(得分:7)

似乎这是Android 4.4中出现的错误,并通过以下方式解决了这个错误:

@Override
public void onTaskRemoved(Intent rootIntent) {
    // TODO Auto-generated method stub
    Intent restartService = new Intent(getApplicationContext(),
            this.getClass());
    restartService.setPackage(getPackageName());
    PendingIntent restartServicePI = PendingIntent.getService(
            getApplicationContext(), 1, restartService,
            PendingIntent.FLAG_ONE_SHOT);
    AlarmManager alarmService = (AlarmManager)getApplicationContext().getSystemService(Context.ALARM_SERVICE);
    alarmService.set(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() +1000, restartServicePI);

}

所以这是一个在Service类本身中重写的方法。我使用AlarmManager的原因是Kitkat不会终止我的服务。

答案 1 :(得分:1)

我有完美的解决方案。

@Override
public void onDestroy() {
     startService(new Intent(yourcontext, YourService.class));
}

答案 2 :(得分:0)

对于KK来说,这仍然是一个开放的错误,

https://code.google.com/p/android/issues/detail?id=63793

答案 3 :(得分:0)

尝试我的解决方案:this

这个技巧会在每次用户从任务管理器关闭服务并强制关闭设置时重启你的服务,我希望这对你也有帮助

答案 4 :(得分:0)

如果您无法重新启动该服务,请致电alam manger以启动此类接收器,

清单是,

         <service
            android:name=".BackgroundService"
            android:description="@string/app_name"
            android:enabled="true"
            android:label="Notification" />
        <receiver android:name="AlarmReceiver">
            <intent-filter>
                <action android:name="REFRESH_THIS" />
            </intent-filter>
        </receiver>

IN Main Activty以这种方式启动报警管理器,

String alarm = Context.ALARM_SERVICE;
        AlarmManager am = (AlarmManager) getSystemService(alarm);

        Intent intent = new Intent("REFRESH_THIS");
        PendingIntent pi = PendingIntent.getBroadcast(this, 123456789, intent, 0);

        int type = AlarmManager.RTC_WAKEUP;
        long interval = 1000 * 50;

        am.setInexactRepeating(type, System.currentTimeMillis(), interval, pi);

这将调用reciver和reciver,

public class AlarmReceiver extends BroadcastReceiver {
    Context context;

    @Override
    public void onReceive(Context context, Intent intent) {
        this.context = context;

        System.out.println("Alarma Reciver Called");

        if (isMyServiceRunning(this.context, BackgroundService.class)) {
            System.out.println("alredy running no need to start again");
        } else {
            Intent background = new Intent(context, BackgroundService.class);
            context.startService(background);
        }
    }

    public static boolean isMyServiceRunning(Context context, Class<?> serviceClass) {
        ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
        List<ActivityManager.RunningServiceInfo> services = activityManager.getRunningServices(Integer.MAX_VALUE);

        if (services != null) {
            for (int i = 0; i < services.size(); i++) {
                if ((serviceClass.getName()).equals(services.get(i).service.getClassName()) && services.get(i).pid != 0) {
                    return true;
                }
            }
        }
        return false;
    }
}

当打开Android应用程序并关闭应用程序时,这个Alaram会调用一次。服务是这样的,

public class BackgroundService extends Service {
    private String LOG_TAG = null;

    @Override
    public void onCreate() {
        super.onCreate();
        LOG_TAG = "app_name";
        Log.i(LOG_TAG, "service created");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i(LOG_TAG, "In onStartCommand");
        //ur actual code
        return START_STICKY;
    }

    @Override
    public IBinder onBind(Intent intent) {
        // Wont be called as service is not bound
        Log.i(LOG_TAG, "In onBind");
        return null;
    }

    @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
    @Override
    public void onTaskRemoved(Intent rootIntent) {
        super.onTaskRemoved(rootIntent);
        Log.i(LOG_TAG, "In onTaskRemoved");
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.i(LOG_TAG, "In onDestroyed");
    }
}