Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/224.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 即使应用程序已从最近的应用程序中清除,仍继续服务_Android_Android Service - Fatal编程技术网

Android 即使应用程序已从最近的应用程序中清除,仍继续服务

Android 即使应用程序已从最近的应用程序中清除,仍继续服务,android,android-service,Android,Android Service,我有点小问题 在我的应用程序中,服务在用户成功登录后启动。以前,如果应用程序被终止,服务需要停止。(比如说,通过滑动从最近的应用程序列表中删除。)所以我们使用了android:stopWithTask=“true”。现在我们需要服务按原样运行,即使启动它的任务已从最近的应用程序列表中删除。因此,我将服务更改为包含android:stopWithTask=“false”。但这似乎不起作用 相关代码: 以下是与服务相关的清单部分: <service android:enabled="t

我有点小问题

在我的应用程序中,服务在用户成功登录后启动。以前,如果应用程序被终止,服务需要停止。(比如说,通过滑动从最近的应用程序列表中删除。)所以我们使用了
android:stopWithTask=“true”
。现在我们需要服务按原样运行,即使启动它的任务已从最近的应用程序列表中删除。因此,我将服务更改为包含
android:stopWithTask=“false”
。但这似乎不起作用

相关代码:

以下是与服务相关的清单部分:

<service
    android:enabled="true"
    android:name=".MyService"
    android:exported="false"
    android:stopWithTask="false" />
AbstractService.java是扩展
Sevrice
的自定义类:

public abstract class AbstractService extends Service {

    protected final String TAG = this.getClass().getName();

    @Override
    public void onCreate() {
        super.onCreate();
        onStartService();
        Log.i(TAG, "onCreate(): Service Started.");
    }

    @Override
    public final int onStartCommand(Intent intent, int flags, int startId) {
        Log.i(TAG, "onStarCommand(): Received id " + startId + ": " + intent);
        return START_STICKY; // run until explicitly stopped.
    }

    @Override
    public final IBinder onBind(Intent intent) {
        return m_messenger.getBinder();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        onStopService();
        Log.i(TAG, "Service Stopped.");
    }    

    public abstract void onStartService();
    public abstract void onStopService();
    public abstract void onReceiveMessage(Message msg);

    @Override
    public void onTaskRemoved(Intent rootIntent) {
        Toast.makeText(getApplicationContext(), "AS onTaskRemoved called", Toast.LENGTH_LONG).show();
        super.onTaskRemoved(rootIntent);
    }
}
现在,如果我登录应用程序,MyService就会启动。之后,我按下Home按钮,所以应用程序被移到后台。现在,我从最近的应用程序列表中删除该应用程序。当时,我应该会看到Toast和console消息,按照此方法的描述:

公共void onTaskRemoved(Intent rootIntent)

在API级别14中添加

如果服务当前正在运行且用户已 已删除来自服务应用程序的任务。如果你有 使用任务设置ServiceInfo.FLAG\u STOP\u,则不会收到此消息 回调;相反,服务将简单地停止

参数rootIntent用于 启动要删除的任务

但我没有看到这些。服务正在
onStartCommand
中返回START\u STICKY,因此我认为
onTaskRemoved
应该与标志
android:stopWithTask=“false”
一起启动

我遗漏了什么吗

让我知道,如果我需要添加一些代码,这可能是重要的,以找出什么是错误的

p.S.:到目前为止,我在4.2.2上测试了这个

p.S.:我刚刚在4.1.2中测试了相同的代码,服务一直在运行,我在日志中也得到了消息“onTaskRemoved called”


我应该怎么做才能使它在所有版本中都起作用?

写下我在服务类的
oncreate()
中添加的5行代码

像这样:

public class AlarmService extends Service {

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

    @Override
    public void onCreate() {
        super.onCreate();
        Intent iHeartBeatService = new Intent(AlarmService.this,
                AlarmService.class);
        PendingIntent piHeartBeatService = PendingIntent.getService(this, 0,
                iHeartBeatService, PendingIntent.FLAG_UPDATE_CURRENT);
        AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
        alarmManager.cancel(piHeartBeatService);
        alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,
                System.currentTimeMillis(), 1000, piHeartBeatService);

    }
}

试试这个

public class MyService extends Service{


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

    @Override
    public void onCreate() {
        // TODO Auto-generated method stub
        super.onCreate();
        System.out.println("service created");
    }

    @SuppressLint("NewApi")
    @Override
    public void onTaskRemoved(Intent rootIntent) {
        // TODO Auto-generated method stub
        System.out.println("onTaskRemoved");
        super.onTaskRemoved(rootIntent);

    }

    @Override
    @Deprecated
    public void onStart(Intent intent, int startId) {
        // TODO Auto-generated method stub
        super.onStart(intent, startId);
        System.out.println("Service started");
        new Handler().postDelayed(new Runnable() {

            @Override
            public void run() {
                // TODO Auto-generated method stub
                System.out.println("Service is running");
            }
        }, 5000);
    }

}

似乎将应用程序从“最近的任务”中删除会杀死所有附加的内容

也许你应该看看那边,找到一种在服务停止时重新启动服务的方法:

如果您从应用程序类的子类绑定到服务,并保持IBinder连接,则即使从最近的应用程序中删除应用程序,该服务仍将保持活动状态。

在您的服务中,添加以下代码。在4.4.2中,这对我来说很好

这里是我遇到的一个变通方法,如果服务的进程在关闭应用程序时被终止,它可以很好地重新启动服务

 @Override public void onTaskRemoved(Intent rootIntent){
     Intent restartServiceIntent = new Intent(getApplicationContext(), this.getClass());

     PendingIntent restartServicePendingIntent = PendingIntent.getService(
         getApplicationContext(), 1, restartServiceIntent, PendingIntent.FLAG_ONE_SHOT);
     AlarmManager alarmService = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
     alarmService.set(ELAPSED_REALTIME, elapsedRealtime() + 1000,
         restartServicePendingIntent);

     super.onTaskRemoved(rootIntent); 
}

只要遵循这些场景,您的服务和进程(在服务中运行的线程)将保持连续

  • 创建服务并在onStartCommand方法中使用START_STICKY作为返回值,如下所示:

    @Override
    public int onStartCommand(final Intent intent, 
                              final int flags,
                              final int startId) {
    
        //your code
        return START_STICKY;
    }  
    
  • 上述代码将在销毁后重新启动服务并始终保持运行,但如果从最近的应用中删除了您的应用,则从服务运行的进程(线程)将停止工作。要确保进程(线程)始终处于运行状态,必须重写onTaskRemoved()方法并添加代码以重新启动任务,如下所示

    @Override
    public void onTaskRemoved(Intent rootIntent){
        Intent restartServiceTask = new Intent(getApplicationContext(),this.getClass());
        restartServiceTask.setPackage(getPackageName());    
        PendingIntent restartPendingIntent =PendingIntent.getService(getApplicationContext(), 1,restartServiceTask, PendingIntent.FLAG_ONE_SHOT);
        AlarmManager myAlarmService = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
        myAlarmService.set(
                AlarmManager.ELAPSED_REALTIME,
                SystemClock.elapsedRealtime() + 1000,
                restartPendingIntent);
    
        super.onTaskRemoved(rootIntent);
    }
    
  • 启动如下服务
  • startService(新意图(this,YourService.class))


    如果可以在服务运行时发出通知,则可以使用startForegroundService和startForeground来完成

    有三个重要技巧:

  • 调用startForegroundService,它创建一个长时间运行的服务,不限于绑定的上下文,并承诺稍后调用startForeground
  • 返回onStartComand中的START\u粘性
  • 使用(1)中承诺的通知调用startForeground
  • 例如,如果要运行TimerService,在TimePractivity中,您将执行以下操作:

    private var timerService: TimerService? = null
    
    private val timerServiceConnection = object : ServiceConnection {
    
        override fun onServiceConnected(className: ComponentName, service: IBinder) {
            val binder = service as TimerService.Binder
            timerService = binder.getService()
        }
    
        override fun onServiceDisconnected(arg0: ComponentName) {
        }
    }
    
    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        startButton.setOnClickListener {
            timerService?.startTimer(60L, 0L)
        }
    }
    
    override fun onStart() {
        super.onStart()
    
        Intent(this, TimerService::class.java).also {
            ContextCompat.startForegroundService(this, it) // that's the first trick
            bindService(it, timerServiceConnection, Context.BIND_AUTO_CREATE)
        }
    }
    
    override fun onStop() {
        super.onStop()
        unbindService(timerServiceConnection)
        timerService?.updateNotification(secondsRemaining)
    }
    
    您的TimerService将是这样的:

    class TimerService : Service() {
    
        private val binder = Binder()
    
        private var serviceLooper: Looper? = null
    
        private var serviceHandler: ServiceHandler? = null
    
        private var timer: CountDownTimer? = null
    
        private val notificationUtil by lazy {
            NotificationUtil(this)
        }
    
        override fun onCreate() {
            HandlerThread("ServiceStartArguments", Process.THREAD_PRIORITY_BACKGROUND).apply {
                start()
                serviceLooper = looper
                serviceHandler = ServiceHandler(looper)
            }
        }
    
        override fun onBind(intent: Intent?): IBinder? = binder
    
        override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
            val timerRemaining = intent?.getLongExtra(EXTRA_REMAINING, 0) ?: 0L
            if (timerRemaining != 0L) {
                serviceHandler?.obtainMessage()?.also { msg ->
                    msg.arg1 = startId
                    msg.data.putLong(EXTRA_REMAINING, timerRemaining)
                    serviceHandler?.sendMessage(msg)
                }
            }
    
            return START_STICKY // that's the second trick
        }
    
        override fun onDestroy() {
            super.onDestroy()
            timer?.cancel()
        }
    
        fun startTimer(secondsRemaining: Long, id: Long) {
            updateNotification(secondsRemaining)
    
            Intent(this, TimerService::class.java).apply {
                putExtra(EXTRA_REMAINING, secondsRemaining)
            }.also {
                onStartCommand(it, 0, id.toInt())
            }
        }
    
        fun stopTimer() {
            timer?.cancel()
        }
    
        fun updateNotification(secondsRemaining: Long){
            val notification = NotificationCompat.Builder(this, NotificationUtil.CHANNEL_ID_TIMER)
                    .setSmallIcon(R.drawable.ic_timer)
                    .setAutoCancel(true)
                    .setDefaults(0)
                    .setContentTitle(secondsRemaining.formatSeconds())
                    .setContentText("Timer")
                    .setContentIntent(notificationUtil.getPendingIntentWithStack(this, TimerActivity::class.java))
                    .setOngoing(true)
                    .build()
            startForeground(NotificationUtil.NOTIFICATION_ID, notification) // that's the last trick
        }
    
        private fun sendMessage(remaining: Long) {
            Intent(TimerService::class.java.simpleName).apply {
                putExtra(EXTRA_REMAINING, remaining)
            }.also {
                LocalBroadcastManager.getInstance(this).sendBroadcast(it)
            }
        }
    
        private inner class ServiceHandler(looper: Looper) : Handler(looper) {
    
            override fun handleMessage(msg: Message) {
                val secondsRemaining = msg.data.getLong(EXTRA_REMAINING)
                notificationUtil.showTimerStarted(secondsRemaining)
    
                timer = object : CountDownTimer(secondsRemaining * 1000, 1000) {
    
                    override fun onTick(millisUntilFinished: Long) {
                        Log.i(this::class.java.simpleName, "tick ${(millisUntilFinished / 1000L).formatSeconds()}")
                        updateNotification(millisUntilFinished / 1000)
                        sendMessage(millisUntilFinished / 1000)
                    }
    
                    override fun onFinish() {
                        Log.i(this::class.java.simpleName, "finish")
                        notificationUtil.showTimerEnded()
                        sendMessage(0)
                        stopSelf()
                    }
                }.start()
            }
        }
    
        inner class Binder : android.os.Binder() {
            // Return this instance of LocalService so clients can call public methods
            fun getService(): TimerService = this@TimerService
        }
    
        companion object {
    
            const val EXTRA_REMAINING = "EXTRA_REMAINING"
            const val NOTIFICATION_ID = 1 // cannot be 0
    
            fun Long.formatSeconds(): String {
                val s = this % 60
                val m = this / 60 % 60
                val h = this / (60 * 60) % 24
                return if (h > 0) String.format("%d:%02d:%02d", h, m, s)
                else String.format("%02d:%02d", m, s)
            }
        }
    
    }
    

    请提供某种描述,以便于理解当应用程序从任何地方被终止时,管理员将被清除。所以这不是一个解决方案。@PankajKumar我个人用过这个,它工作得很好,试一下吧tell@UnityBeginner:如果我知道你正在应用程序中使用它,我将永远不会安装它。因为你每秒钟都在唤醒我的设备,而你就是我的电池耗尽的原因。我同意它消耗了大量电池,但它不会让服务停止以防万一,你是如何启动此服务的?如果通过
    bindService()
    ,则当客户端(例如活动)解除绑定时,服务将自动销毁,除非您也显式调用
    startService()
    。AFAIK,只有一种方法可以从其
    onStopService()
    @matiash在其他版本中工作时再次启动服务。可能在Karbonn或4.2.2中发布,谢谢。)请帮帮我谢谢,我解决了你的问题,得到了线索:)谢谢你尼玛。你能详细说明一下吗?或者更好,一些好的例子会很好。Thx@mauron,您要做的是扩展
    应用程序
    类,然后在该类中重写
    onCreate()
    ,并在其中使用
    startService()
    启动服务,然后绑定到它。不要让绑定器变量设置为null,从而使其保持活动状态。是否有人测试了此解决方案?我试着什么也没做。这听起来像是服务对内存的不必要的使用。尤其是Android文档说:~“一个启动的服务必须管理它自己的生命周期。”不确定你所说的不必要的内存使用是什么意思,这和从活动绑定到服务有什么不同?你不需要从应用子类管理服务生命周期,只需启动它就可以由子类完成
    class TimerService : Service() {
    
        private val binder = Binder()
    
        private var serviceLooper: Looper? = null
    
        private var serviceHandler: ServiceHandler? = null
    
        private var timer: CountDownTimer? = null
    
        private val notificationUtil by lazy {
            NotificationUtil(this)
        }
    
        override fun onCreate() {
            HandlerThread("ServiceStartArguments", Process.THREAD_PRIORITY_BACKGROUND).apply {
                start()
                serviceLooper = looper
                serviceHandler = ServiceHandler(looper)
            }
        }
    
        override fun onBind(intent: Intent?): IBinder? = binder
    
        override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
            val timerRemaining = intent?.getLongExtra(EXTRA_REMAINING, 0) ?: 0L
            if (timerRemaining != 0L) {
                serviceHandler?.obtainMessage()?.also { msg ->
                    msg.arg1 = startId
                    msg.data.putLong(EXTRA_REMAINING, timerRemaining)
                    serviceHandler?.sendMessage(msg)
                }
            }
    
            return START_STICKY // that's the second trick
        }
    
        override fun onDestroy() {
            super.onDestroy()
            timer?.cancel()
        }
    
        fun startTimer(secondsRemaining: Long, id: Long) {
            updateNotification(secondsRemaining)
    
            Intent(this, TimerService::class.java).apply {
                putExtra(EXTRA_REMAINING, secondsRemaining)
            }.also {
                onStartCommand(it, 0, id.toInt())
            }
        }
    
        fun stopTimer() {
            timer?.cancel()
        }
    
        fun updateNotification(secondsRemaining: Long){
            val notification = NotificationCompat.Builder(this, NotificationUtil.CHANNEL_ID_TIMER)
                    .setSmallIcon(R.drawable.ic_timer)
                    .setAutoCancel(true)
                    .setDefaults(0)
                    .setContentTitle(secondsRemaining.formatSeconds())
                    .setContentText("Timer")
                    .setContentIntent(notificationUtil.getPendingIntentWithStack(this, TimerActivity::class.java))
                    .setOngoing(true)
                    .build()
            startForeground(NotificationUtil.NOTIFICATION_ID, notification) // that's the last trick
        }
    
        private fun sendMessage(remaining: Long) {
            Intent(TimerService::class.java.simpleName).apply {
                putExtra(EXTRA_REMAINING, remaining)
            }.also {
                LocalBroadcastManager.getInstance(this).sendBroadcast(it)
            }
        }
    
        private inner class ServiceHandler(looper: Looper) : Handler(looper) {
    
            override fun handleMessage(msg: Message) {
                val secondsRemaining = msg.data.getLong(EXTRA_REMAINING)
                notificationUtil.showTimerStarted(secondsRemaining)
    
                timer = object : CountDownTimer(secondsRemaining * 1000, 1000) {
    
                    override fun onTick(millisUntilFinished: Long) {
                        Log.i(this::class.java.simpleName, "tick ${(millisUntilFinished / 1000L).formatSeconds()}")
                        updateNotification(millisUntilFinished / 1000)
                        sendMessage(millisUntilFinished / 1000)
                    }
    
                    override fun onFinish() {
                        Log.i(this::class.java.simpleName, "finish")
                        notificationUtil.showTimerEnded()
                        sendMessage(0)
                        stopSelf()
                    }
                }.start()
            }
        }
    
        inner class Binder : android.os.Binder() {
            // Return this instance of LocalService so clients can call public methods
            fun getService(): TimerService = this@TimerService
        }
    
        companion object {
    
            const val EXTRA_REMAINING = "EXTRA_REMAINING"
            const val NOTIFICATION_ID = 1 // cannot be 0
    
            fun Long.formatSeconds(): String {
                val s = this % 60
                val m = this / 60 % 60
                val h = this / (60 * 60) % 24
                return if (h > 0) String.format("%d:%02d:%02d", h, m, s)
                else String.format("%02d:%02d", m, s)
            }
        }
    
    }