Подтвердить что ты не робот

Служба 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 минут).

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

4b9b3361

Ответ 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");
        }

    }
}

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