2016-03-02 2 views
12

В моем приложении я использую службу на основе местоположения в фоновом режиме. Поэтому мне нужно перезагрузить службу, когда она будет уничтожена.Служба Android не перезапускается в lollipop

Но я получил это сообщение в LogCat

паразитной смерть ProcessRecord {320afaf6 20614: com.odoo.crm: my_odoo_gps_service/u0a391}, curProc для 20614: нулевой

Моей служба onTaskRemoved

@Override 
public void onTaskRemoved(Intent rootIntent) { 
    System.out.println("onTaskRemoved called"); 
    Intent restartServiceIntent = new Intent(App.getAppContext(), this.getClass()); 
    restartServiceIntent.setPackage(getPackageName()); 

    PendingIntent restartServicePendingIntent = 
     PendingIntent.getService(App.getAppContext(), 1, restartServiceIntent, 
     PendingIntent.FLAG_ONE_SHOT); 

    AlarmManager alarmService = 
     (AlarmManager) App.getAppContext().getSystemService(Context.ALARM_SERVICE); 
    alarmService.set(
      AlarmManager.ELAPSED_REALTIME, 
      SystemClock.elapsedRealtime() + 1000, 
      restartServicePendingIntent); 
} 

Моя служба OnDestroy

@Override 
public void onDestroy() { 
    System.out.println("destroy service"); 
    super.onDestroy(); 
    wakeLock.release(); 
} 

Моя служба onStartCommand

@Override 
public int onStartCommand(Intent intent, int flags, int startId) { 
     return Service.START_STICKY; 
} 

Я не знаю, что это ошибка. Я искал оба в google & stackoverflow. Все они ссылаются Service.START_STICKY. но я уже использовал его.

Тот же перезапуск службы работает в KitKat, но с некоторой задержкой (~ 5 минут).

Любая помощь приветствуется.

+1

Если бы я должен был догадаться, Google поймал этот хак и заблокировал его. – CommonsWare

+0

есть. Думаю тоже такой же. Но по этой причине мой клиент заблокировал мой проект :( –

+0

вы можете использовать обратные вызовы, сделать обратный вызов и вызвать его в методе onTaskRemoved, реализация будет в действии и перезапустить службу. – Fakher

ответ

6

Вы можете перезапустить его с помощью BroadcasteReceiver, который обрабатывает широковещательную рассылку, отправленную с onDestroy() ваших услуг.

Как это сделать:

StickyService.java

public class StickyService extends Service 
{ 

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

    @Override 
    public int onStartCommand(Intent intent, int flags, int startId) { 
     return START_STICKY; 
    } 


    @Override 
    public void onTaskRemoved(Intent rootIntent) { 
     super.onTaskRemoved(rootIntent); 
     sendBroadcast(new Intent("IWillStartAuto")); 
    } 

    @Override 
    public void onDestroy() { 
     super.onDestroy(); 
     sendBroadcast(new Intent("IWillStartAuto")); 
    } 

} 

RestartServiceReceiver.java

public class RestartServiceReceiver extends BroadcastReceiver 
{ 

    @Override 
    public void onReceive(Context context, Intent intent) { 
    context.startService(new Intent(context.getApplicationContext(), StickyService.class)); 

    } 

} 

Объявите компоненты в явном файле:

<service android:name=".StickyService" > 
    </service> 

    <receiver android:name=".RestartServiceReceiver" > 
     <intent-filter> 
      <action android:name="IWillStartAuto" > 
      </action> 
     </intent-filter> 
    </receiver> 

Надеюсь, это поможет вам.

+0

Вы пробовали мое решение? –

+0

Да, я пробовал .. он работает первым время только .. следующий раз радиовещательный приемник не называется. –

+0

onDestroy не называемый m e .. Я транслирую из onTaskRemoved .. –

4

Ваш код в onTaskRemoved не позволяет системе выполнять команды killProcess. Задержка на Kitkat вызвана использованием alarmService.set, то есть inexact из API 19. Вместо этого используйте setExact.

Если у вас есть service, который вы хотите сохранить в жизни, рекомендуется прикрепить к нему notification и сделать его foreground. Таким образом, вероятность его убийства будет снижена.

+0

спасибо за ответ. Я проверяю его –

2

как вы проверяете, является ли разъем подключенным или нет? Если генерируется sockettimeoutexception, попробуйте установить getinputstream и getoutputstream. Другая проблема, которая может быть неправильно закрыта. Так что, если это возможно, то поставить код сокета здесь

3
import android.app.Notification; 
import android.app.PendingIntent; 
import android.app.Service; 
import android.content.Intent; 
import android.os.Environment; 
import android.os.IBinder; 
import android.support.v7.app.NotificationCompat; 

import java.io.File; 
import java.io.IOException; 

import activity.MainActivity; 
import activity.R; 
import fragment.MainFragment; 

public class MyService extends Service { 
    public static final int NOTIFICATION_CODE = 1; 


    @Override 
    public void onCreate() { 
     super.onCreate(); 


    } 

    @Override 
    public int onStartCommand(Intent intent, int flags, int startId) { 
     startForeground(NOTIFICATION_CODE, getNotification()); 
     return START_STICKY; 
    } 

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

    @Override 
    public void onDestroy() { 
     stopForeground(true); 
     super.onDestroy(); 
    } 

    @Override 
    public boolean stopService(Intent name) { 
     return super.stopService(name); 
    } 


    /** 
    * Create and return a simple notification. 
    */ 
    private Notification getNotification() {  
     Notification notification; 
     NotificationCompat.Builder builder = new NotificationCompat.Builder(this); 
     builder.setColor(getResources() 
         .getColor(R.color.material_deep_teal_500)) 
       .setAutoCancel(true); 

     notification = builder.build(); 
     notification.flags = Notification.FLAG_FOREGROUND_SERVICE | Notification.FLAG_AUTO_CANCEL; 

     return notification; 
    } 


} 

Вы можете изменить этот код, чтобы разместить свои потребности, но это базовая структура для начала переднего плана обслуживания. Что перезапускается, если его убивают.

+0

Мне не нужно уведомление .. это полностью фон, даже пользователь тоже не знает, что сервис –

+1

Но для обслуживания переднего плана вам нужно добавить уведомление. Вы можете сделать его прозрачным. Также вы можете set избегать вызова намерений при касании уведомления. –

+0

Можете ли вы поделиться прозрачным уведомлением и избежать уведомления о касании –

2

это работал для меня

Добавить этот атрибут в андроиде: allowBackup = «ложь» в файле манифеста в прикладном теге.

<?xml version="1.0" encoding="utf-8"?> 
<manifest xmlns:android="http://schemas.android.com/apk/res/android" 
xmlns:tools="http://schemas.android.com/tools"> 

<application 
    android:allowBackup="false" 
    tools:replace="android:allowBackup"> 

</application> 
</manifest> 
+0

Я уже использовал это. но он не работает в леденец. r u попробуйте версию Lollipop –

+0

нужно будет проверить, что .... сообщит вам об этом. –

2

Идея иметь сервис ВСЕГДА работает в фоновом режиме на Android, это просто неправильно в 99% случаев.

Система должна «выключить» CPU и переключиться на низкий уровень использования батареи.

Вы говорите, что у вас есть служба на основе местоположения. Я предполагаю, что вы используете Google Play Services FusedLocationProvider, если не , вы должны.

FusedLocationProvider позволяет зарегистрировать изменения местоположения с помощью PendingIntent. Это означает, что ваши службы не должны запускаться все время, просто нужно зарегистрироваться для изменения местоположения, а затем реагировать, когда придет новое местоположение и сделает все.

См. FusedLocationProviderApiofficial documentation.

Чтобы начать прослушивание геоданных

  1. подключения к GoogleClient с помощью LocationServices.API API
  2. Создайте свой LocationRequest в соответствии с вашими потребностями (см the doc)
  3. Вызов requestLocationUpdates() используя PendingIntent версию

Чтобы прекратить слушать

  1. подключение к GoogleClient с помощью LocationServices.API API
  2. Вызова removeLocationUpdates() используя тот же PendingIntent

Вашего PendingIntent может запустить другую службу для обработки нового местоположения.

Например, делать это от службы:

public void startMonitoringLocation(Context context) { 
    GoogleApiClient client = new GoogleApiClient.Builder(context) 
       .addApi(LocationServices.API) 
       .build() 
    ConnectionResult connectionResult = mApiClient.blockingConnect(); 
    if (connectionResult.isSuccess()) { 
     LocationServices.FusedLocationApi 
       .requestLocationUpdates(client, buildLocationRequest(), buildPendingIntent(context)); 
    } else { 
     handleConnectionFailed(context); 
    } 
} 

Затем служба может немедленно прекратить.

При первом запуске этого кода WILL терпит неудачу. Соединение с клиентом google обычно требует от пользователя выполнения некоторых действий. Метод ConnectionResult.hasResolution() вернет true, если это так. В противном случае причина - это нечто иное, и вы не можете оправиться от него. Значит, единственное, что вы можете сделать, это сообщить пользователю, что функция не будет работать или иметь хороший резерв.

ConnectionResult.getResolution() дать вам PendingIntent вам нужно использовать Activity и startIntentSenderForResult() метод на Activity разрешить это намерение. Поэтому вы должны создать Notification, начиная с Activity, чтобы решить эту проблему, и в конце звоните Service.

Обычно я просто начинаю Activity, посвященный выполнению всей работы. Это намного проще, но вы не хотите называть connectBlocking(). Отъезд this о том, как это сделать.

Вы можете спросить, почему бы не запрашивать обновления местоположения непосредственно в Activity. Это на самом деле отлично, если вам не нужен монитор местоположения для автоматического запуска с устройства, даже если пользователь явно не открыл приложение.

<receiver android:name=".BootCompletedBroadcastReceiver"> 
    <intent-filter> 
     <action android:name="android.intent.action.BOOT_COMPLETED" /> 
    </intent-filter> 
</receiver> 

Таким образом, вы можете просто запустить службу, чтобы подключаться и запрашивать обновления местоположения при перезагрузке устройства.

Пример того, как вы можете создать свой запрос местоположения:

public LocationRequest buildLocationRequest() { 
     LocationRequest locRequest = LocationRequest.create(); 
     // Use high accuracy 
     locRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); 
     // how often do you need to check for the location 
     // (this is an indication, it's not exact) 
     locRequest.setInterval(REQUIRED_INTERVAL_SEC * 1000); 
     // if others services requires the location more often 
     // you can still receive those updates, if you do not want 
     // too many consider setting this lower limit 
     locRequest.setFastestInterval(FASTEST_INTERVAL_SEC * 1000); 
     // do you care if the user moved 1 meter? or if he move 50? 1000? 
     // this is, again, an indication 
     locRequest.setSmallestDisplacement(SMALLEST_DISPLACEMENT_METERS); 
     return locRequest; 
    } 

И ожидающие рассмотрения намерения:

public PendingIntent buildPendingIntent(Context context) { 
    Intent intent = new Intent(context, LocationUpdateHandlerService.class); 
    intent.setAction(ACTION_LOCATION_UPDATE); 
    intent.setPackage(context.getPackageName()); 
    return PendingIntent.getService(context, REQUEST_CODE, intent, PendingIntent.FLAG_CANCEL_CURRENT); 
} 

Ваш LocationUpdateHandlerService может быть IntentService, если вам нужно, чтобы сделать работу в фоновом режиме:

@Override 
protected void onHandleIntent(Intent intent) { 
    if (intent != null) { 
     Bundle extras = intent.getExtras(); 
     if (extras != null && extras.containsKey(FusedLocationProviderApi.KEY_LOCATION_CHANGED)) { 
      Location location = extras.getParcelable(FusedLocationProviderApi.KEY_LOCATION_CHANGED); 
      handleLocationChanged(location); 
     } else { 
      Log.w(TAG, "Didn't receive any location update in the receiver"); 
     } 

    } 
} 

Но также может быть трансляцией o Все, что вам подходит.

Смежные вопросы