#android #service #boot #notifications
В основные задачи программы входит выполнение методов в фоновом режиме, для чего используется Android Services. Необходимо запустить Service таким образом, чтобы после закрытия MainActivity сервис оставался в рабочем состоянии и мог создавать уведомления, а также, в случае закрытия системой или же перезагрузки, самостоятельно восстанавливался. На данный момент основная проблема состоит в поддержании жизни в MyService после закрытия пользовательского интерфейса. AutoStart: В AndroidManifest.xml были прописаныВ BootReceiver.java: @Override public void onReceive(Context context, Intent intent) { Intent serviceIntent = new Intent(context, MyService.class); context.startService(serviceIntent); } Service: В AndroidManifest.xml прописано: В MyService.java находится следующий код, за исключением некоторых частей (описаны наиболее важные элементы, в которых могут находиться ошибки, не позволяющие решить поставленную задачу): public void onCreate() { super.onCreate(); notificationManager = (NotificationManager) this.getSystemService(this.NOTIFICATION_SERVICE); } public int onStartCommand(Intent intent, int flags, int startId) { sendNotification("Service started", "Service", "started"); return Service.START_STICKY; } public void sendNotification(String Ticker,String Title,String Text) { Intent notificationIntent = new Intent(this, MainActivity.class); notificationIntent.setAction(Intent.ACTION_MAIN); notificationIntent.addCategory(Intent.CATEGORY_LAUNCHER); PendingIntent contentIntent = PendingIntent.getActivity(getApplicationContext(), 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT); NotificationCompat.Builder builder = new NotificationCompat.Builder(this); builder.setContentIntent(contentIntent) .setOngoing(true) //invulnerable .setTicker(Ticker) .setContentTitle(Title) .setContentText(Text) .setWhen(System.currentTimeMillis()); Notification notification; if (android.os.Build.VERSION.SDK_INT<=15) { notification = builder.getNotification(); // API 15 and lower }else { notification = builder.build(); } startForeground(DEFAULT_NOTIFICATION_ID,notification); @Override public IBinder onBind(Intent intent) { return new Binder(); } @Override public void onRebind(Intent intent) { super.onRebind(intent); } @Override public boolean onUnbind(Intent intent) { return super.onUnbind(intent); } @Override public void onDestroy() { //Removing any notifications notificationManager.cancel(DEFAULT_NOTIFICATION_ID); //Disabling service stopSelf(); super.onDestroy(); } Запускается MyService из MainActivity следующим образом: Intent intentService; @Override protected void onCreate(Bundle savedInstanceState) { intentService = new Intent(this,MyService.class); } public void runService() { boolean working = isMyServiceRunning(MyService.class); if (!working) { startService(intentService); } else { stopService(intentService); } } public boolean isMyServiceRunning(Class serviceClass) { ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) { if (serviceClass.getName().equals(service.service.getClassName())) { return true; } } return false; } Просьба указать на допущенные в ходе программирования ошибки, дополнив их сторонними материалами (примерами) или ключевыми словами для поиска.
Ответы
Ответ 1
Для адекватной работы всех предъявленных к "бессмертному" сервису требований потребовалось деинсталлировать нерабочую версию с устройства, после чего загрузить свежую сборку. Вызвано это было, вероятнее всего, именно разрешениями. Построение своей программы я начал практически с нуля, поэтому после первой установки приложению было выдано недостаточное для реализации функций "бессмертного" сервиса количество разрешений. На данный момент приложением используется всего два разрешения: Notifications и Autostart. На эту мысль меня натолкнула полная работоспособность приложения на всех прочих устройствах. Я постараюсь отразить в этом ответе все элементы кода, необходимые для работы "бессмертного" сервиса. Android Manifest:MainActivity: public class MainActivity extends AppCompatActivity { Intent intentService; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); intentService = new Intent(this,MyService.class); } public void click_Service(View v) { if (!isMyServiceRunning(MyService.class)) { startService(intentService); } else { stopService(intentService); } } private boolean isMyServiceRunning(Class serviceClass) { ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) { if (serviceClass.getName().equals(service.service.getClassName())) { return true; } } return false; } } MyService: public class MyService extends Service { private NotificationManager notificationManager; public static final int DEFAULT_NOTIFICATION_ID = 101; public void onCreate() { super.onCreate(); notificationManager = (NotificationManager) this.getSystemService(this.NOTIFICATION_SERVICE); } public int onStartCommand(Intent intent, int flags, int startId) { //Send Foreground Notification sendNotification("Ticker","Title","Text"); //Task doTask(); //return Service.START_STICKY; return START_REDELIVER_INTENT; } //Send custom notification public void sendNotification(String Ticker,String Title,String Text) { //These three lines makes Notification to open main activity after clicking on it Intent notificationIntent = new Intent(this, MainActivity.class); notificationIntent.setAction(Intent.ACTION_MAIN); notificationIntent.addCategory(Intent.CATEGORY_LAUNCHER); PendingIntent contentIntent = PendingIntent.getActivity(getApplicationContext(), 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT); NotificationCompat.Builder builder = new NotificationCompat.Builder(this); builder.setContentIntent(contentIntent) .setOngoing(true) //Can't be swiped out .setSmallIcon(R.mipmap.ic_launcher) //.setLargeIcon(BitmapFactory.decodeResource(res, R.drawable.large)) // большая картинка .setTicker(Ticker) .setContentTitle(Title) //Заголовок .setContentText(Text) // Текст уведомления .setWhen(System.currentTimeMillis()); Notification notification; if (android.os.Build.VERSION.SDK_INT<=15) { notification = builder.getNotification(); // API-15 and lower }else{ notification = builder.build(); } startForeground(DEFAULT_NOTIFICATION_ID, notification); } @Override public IBinder onBind(Intent intent) { return null; } @Override public void onDestroy() { super.onDestroy(); //Removing any notifications notificationManager.cancel(DEFAULT_NOTIFICATION_ID); //Disabling service stopSelf(); } } MyReceiver: public class MyReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Intent intentService = new Intent(context, MyService.class); context.startService(intentService); } } Таким образом, мы получаем сервис, который автоматически запускается после старта системы. Пользовательский интерфейс может быть вызван нажатием на уведомление, которое невозможно убрать из панели уведомлений. После открытия пользовательского интерфейса сервис может быть отключён или включён вручную нажатием на соответствующую кнопку. В случае закрытия приложения, включая свайп приложения из Recent Task Bar'а, сервис останется включённым и продолжит свою работу. Единственным возможным способом закончить работу MyService без использования пользовательского интерфейса является закрытие процесса Application при помощи Force Stop в списке приложений или же остановка самого процесса вручную в меню настроек системы.
Комментариев нет:
Отправить комментарий