Страницы

Поиск по вопросам

воскресенье, 15 декабря 2019 г.

Неубиваемый Service Android (Boot,Foreground,Sticky)

#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 в списке приложений или же остановка самого процесса вручную в меню настроек системы.

Комментариев нет:

Отправить комментарий