Как сделать чтобы сервис работал постоянно?
Доброго времени суток! Я написал сервис, который показывает FPS. Однако, при закрытии приложения сервис удаляется, и FPS перестает отображаться. Как это исправить?
import android.app.Service import android.content.Intent import android.graphics.Color import android.graphics.PixelFormat import android.os.Handler import android.os.IBinder import android.util.Log import android.view.Choreographer import android.view.LayoutInflater import android.view.View import android.view.WindowManager import android.widget.ImageButton import android.widget.TextView class FPS : Service(), Choreographer.FrameCallback { private var windowManager: WindowManager? = null private var fpsTextView: TextView? = null private var popupView: View? = null private var frameCount = 0 private var startTime: Long = 0 private val handler = Handler() private val choreographer: Choreographer by lazy { Choreographer.getInstance() } private var color: Int = 0 override fun onBind(intent: Intent): IBinder? { return null } override fun onCreate() { super.onCreate() val params = WindowManager.LayoutParams( WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY } else { WindowManager.LayoutParams.TYPE_PHONE }, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSLUCENT ) params.gravity = android.view.Gravity.TOP or android.view.Gravity.END windowManager = getSystemService(WINDOW_SERVICE) as WindowManager val inflater = getSystemService(LAYOUT_INFLATER_SERVICE) as LayoutInflater popupView = inflater.inflate(R.layout.window, null) fpsTextView = popupView?.findViewById(R.id.fps) val closeButton: ImageButton? = popupView?.findViewById(R.id.close_button) closeButton?.setOnClickListener { stopSelf() } windowManager?.addView(popupView, params) choreographer.postFrameCallback(this) } override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { intent?.let { color = intent.getIntExtra("color", Color.WHITE) } return super.onStartCommand(intent, flags, startId) } override fun onDestroy() { super.onDestroy() handler.removeCallbacksAndMessages(null) windowManager?.removeView(popupView) } override fun doFrame(frameTimeNanos: Long) { val currentTime = System.currentTimeMillis() frameCount++ choreographer.postFrameCallback(this) if (currentTime - startTime >= 1000) { val fps = frameCount.toFloat() / ((currentTime - startTime) / 1000f) val roundedFps = Math.round(fps).toInt() Log.d("FPS", "FPS: $roundedFps") fpsTextView?.setTextColor(color) fpsTextView?.text = "FPS: $roundedFps" frameCount = 0 startTime = currentTime } } } |
import android.app.Service import android.content.Intent import android.graphics.Color import android.graphics.PixelFormat import android.os.Handler import android.os.IBinder import android.util.Log import android.view.Choreographer import android.view.LayoutInflater import android.view.View import android.view.WindowManager import android.widget.ImageButton import android.widget.TextView class FPS : Service(), Choreographer.FrameCallback { private var windowManager: WindowManager? = null private var fpsTextView: TextView? = null private var popupView: View? = null private var frameCount = 0 private var startTime: Long = 0 private val handler = Handler() private val choreographer: Choreographer by lazy { Choreographer.getInstance() } private var color: Int = 0 override fun onBind(intent: Intent): IBinder? { return null } override fun onCreate() { super.onCreate() val params = WindowManager.LayoutParams( WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY } else { WindowManager.LayoutParams.TYPE_PHONE }, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSLUCENT ) params.gravity = android.view.Gravity.TOP or android.view.Gravity.END windowManager = getSystemService(WINDOW_SERVICE) as WindowManager val inflater = getSystemService(LAYOUT_INFLATER_SERVICE) as LayoutInflater popupView = inflater.inflate(R.layout.window, null) fpsTextView = popupView?.findViewById(R.id.fps) val closeButton: ImageButton? = popupView?.findViewById(R.id.close_button) closeButton?.setOnClickListener { stopSelf() } windowManager?.addView(popupView, params) choreographer.postFrameCallback(this) } override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { intent?.let { color = intent.getIntExtra("color", Color.WHITE) } return super.onStartCommand(intent, flags, startId) } override fun onDestroy() { super.onDestroy() handler.removeCallbacksAndMessages(null) windowManager?.removeView(popupView) } override fun doFrame(frameTimeNanos: Long) { val currentTime = System.currentTimeMillis() frameCount++ choreographer.postFrameCallback(this) if (currentTime - startTime >= 1000) { val fps = frameCount.toFloat() / ((currentTime - startTime) / 1000f) val roundedFps = Math.round(fps).toInt() Log.d("FPS", "FPS: $roundedFps") fpsTextView?.setTextColor(color) fpsTextView?.text = "FPS: $roundedFps" frameCount = 0 startTime = currentTime } } }
Дополнительно:
я понял, я использовал startService, а нужно было запускать как startForegraundService
Ответы:
Во первых, ценность сервиса около нулевая с точки зрения других разработчиков, так как в режиме разработчика можно просто поставить ON на против настройки "Выводить частоту кадров".
Во вторых, в том виде как сейчас он у вас написан,
fpsTextView = popupView?.findViewById(R.id.fps)
работать без вашей активности на топе не будет.
В тетьих, что же можно сделать:
а) Полупрозрачное окно активности (тема наследованная от диалога), которое будет всегда поверх других.
б) частота кадров будет выводиться в шторке на уведомлении от foreground service (тут подлянка от андроид 13, где нотифи служб теперь по умолчанию скрыты)
-
Во первых, ценность сервиса около нулевая с точки зрения других разработчиков, так как в режиме разработчика можно просто поставить ON на против настройки "Выводить частоту кадров"
я для примера написал эту программу для понимания работы Services, но проблема с тем что при закрытии приложения сервис уходит (андроид 12)
- misterKno, Да я так и подумал, что реально это будет информер для трейдовой торговли.
И поэтому штатные механизмы того как ForegroundService остается активной и выводит информацию (в шторке вещается нотифи не подойдет).
Вы же хотите постоянно поверх любых окон иметь текстовую строку ?
То есть ваша активити с прозрачным фоном (в режиме диалога) висит постоянно. - Олег, верно
- misterKno, таки вопрос у вас основной как сделать модальное окно, а не службу оставить работающей. Которая автоматически останется работать, если сбиндить ее с этим окном
- Олег, а как это сделать?
- misterKno, через слезы от воевания с пермишинсами андроида, а еще боли добавляют разные вендоры своими кастомными ограничениями. Там раздел объяснения пользователю как их дать будет больше самого приложения
Опишите проблему, и специалист поможет с настройкой, исправлением ошибки или доработкой сайта. Подберём понятный план работ без лишней переписки.
Пока нет других ответов. Будьте первым, кто поможет автору.
Ответить на вопрос
Для того чтобы сервис работал постоянно, необходимо обеспечить его непрерывную работу и отслеживать возможные проблемы, которые могут возникнуть. Вот несколько шагов, которые помогут вам добиться этого:
1. **Мониторинг и управление ресурсами**: Очень важно следить за использованием ресурсов вашего сервера (память, CPU, дисковое пространство) и оптимизировать их использование. Вы можете использовать инструменты мониторинга, такие как Nagios, Zabbix или Prometheus, чтобы отслеживать состояние сервера и сервиса.
2. **Резервное копирование и восстановление**: Регулярное создание резервных копий данных и конфигурации поможет избежать потери информации в случае сбоя. Вы можете использовать инструменты автоматического резервного копирования, такие как Bacula, Amanda или Duplicity.
3. **Обновление и обслуживание**: Регулярное обновление операционной системы, приложений и библиотек помогает устранить уязвимости и обеспечить стабильную работу сервиса. Убедитесь, что вы следите за обновлениями и применяете их вовремя.
4. **Масштабирование**: Если ваш сервис сталкивается с увеличением нагрузки, возможно, вам потребуется масштабировать его. Вы можете использовать горизонтальное или вертикальное масштабирование в зависимости от потребностей вашего сервиса.
5. **Управление ошибками и исключениями**: Необходимо предусмотреть обработку ошибок и исключений в вашем коде, чтобы сервис мог корректно реагировать на них и не прекращал работу из-за возможных проблем.
Приведенные выше шаги помогут вам обеспечить непрерывную работу вашего сервиса. Помните, что поддержание стабильной работы требует постоянного внимания и усилий, но это того стоит для обеспечения качественного обслуживания вашего сервиса.