Служба Android не перезапускается в леденец
В моем приложении я использую службу на основе местоположения в фоновом режиме. Поэтому мне нужно перезапустить мою службу, когда она будет уничтожена.
Но я получил это сообщение в logcat
Ложная смерть для ProcessRecord {320afaf6 20614: com.odoo.crm: my_odoo_gps_service/u0a391}, curProc для 20614: null
Моя служба 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.
Все они ссылаются на Сервис .START_STICKY. но я уже использовал его.
Такой же перезапуск службы работает в KitKat, но с некоторой задержкой (~ 5 минут).
Любая помощь приветствуется.
Ответы
Ответ 1
Вы можете перезапустить его, используя 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>
Надеюсь, это поможет вам.
Ответ 2
Ваш код в onTaskRemoved
не позволяет системе запускать команды killProcess
. Задержка на Kitkat
вызвана использованием alarmService.set
, которое неточно из API 19. Используйте setExact.
Если у вас есть service
, который вы хотите сохранить, рекомендуется прикрепить к нему notification
и сделать его foreground
. Таким образом, вероятность его убийства будет снижена.
Ответ 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;
}
}
Вы можете изменить этот код, чтобы удовлетворить ваши потребности, но это базовая структура для запуска обслуживания переднего плана. Что перезапускается, если его убили.
Ответ 4
как вы проверяете isocketalive, что сокет подключен или нет?
если генерируется генерация sockettimeoutception, тогда попробуйте установить getinputstream и getoutputstream.
другая проблема, которая может быть неправильно закрыта.
Поэтому, если возможно, введите здесь код сокета
Ответ 5
это сработало для меня
Добавьте этот атрибут в android: allowBackup = "false" в файле манифеста в теге приложения.
<?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>
Ответ 6
Идея иметь сервис ВСЕГДА работает в фоновом режиме на Android, просто ошибается в 99% случаев.
Системе необходимо "выключить" процессор и переключиться на низкий уровень использования аккумулятора.
Вы говорите, что у вас есть служба, основанная на местоположении. Я предполагаю, что вы используете Google Play Services FusedLocationProvider
, если не , вы должны.
FusedLocationProvider
позволяет зарегистрировать изменения местоположения с помощью PendingIntent
. Это означает, что ваши службы не должны запускаться все время, просто нужно зарегистрироваться для изменения местоположения, а затем отреагировать, когда придет новое местоположение и сделайте все.
См. официальную документацию FusedLocationProviderApi
.
Чтобы начать прослушивание обновлений местоположения
- подключиться к
GoogleClient
с помощью LocationServices.API
API
- Создайте свой
LocationRequest
в соответствии с вашими потребностями (см. документ)
- Вызов
requestLocationUpdates()
с помощью версии PendingIntent
Чтобы остановить прослушивание
- подключиться к
GoogleClient
с помощью LocationServices.API
API
- Вызовите
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()
в нем. Ознакомьтесь с этим о том, как это сделать.
Вы можете спросить, почему не запрашивать обновления местоположения непосредственно в 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 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");
}
}
}
Но также может быть трансляция или что-то, что вам подходит.