8

Я создал службу для периодического выбора текущего местоположения устройства. Я хочу, чтобы служба запускалась в фоновом режиме, даже если приложение очищено от недавно открытых приложений. В настоящее время служба работает в фоновом режиме только до тех пор, пока приложение не будет присутствовать в недавно открытых приложениях, но немедленно остановится, когда приложение будет удалено (или каким-то другим образом убито). Я пробовал всякую помощь, доступную в переполнении стека, но я не могу решить эту проблему. Пожалуйста помоги. Вот мой код для службы.Как перезапустить службу после того, как приложение было убито из последних заданий

package com.packr.services; 

import android.app.AlarmManager; 
import android.app.PendingIntent; 
import android.app.Service; 
import android.content.Context; 
import android.content.Intent; 
import android.content.pm.ServiceInfo; 
import android.location.Location; 
import android.os.Bundle; 
import android.os.IBinder; 
import android.os.SystemClock; 
import android.support.annotation.Nullable; 
import android.util.Log; 
import android.widget.Toast; 

import com.google.android.gms.common.ConnectionResult; 
import com.google.android.gms.common.api.GoogleApiClient; 
import com.google.android.gms.location.LocationListener; 
import com.google.android.gms.location.LocationRequest; 
import com.google.android.gms.location.LocationServices; 

import java.text.DateFormat; 
import java.util.Date; 

/** 
* Created by Arindam on 11-Dec-15. 
*/ 
public class LocationService extends Service implements 
     GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener { 
    protected static final String TAG = "packrMATE"; 
    /** 
    * The desired interval for location updates. Inexact. Updates may be more or less frequent. 
    */ 
    public static final long UPDATE_INTERVAL_IN_MILLISECONDS = 10000; 

    /** 
    * The fastest rate for active location updates. Exact. Updates will never be more frequent 
    * than this value. 
    */ 
    public static final long FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS = 
      UPDATE_INTERVAL_IN_MILLISECONDS/2; 

    // Keys for storing activity state in the Bundle. 
    protected final static String REQUESTING_LOCATION_UPDATES_KEY = "requesting-location-updates-key"; 
    protected final static String LOCATION_KEY = "location-key"; 
    protected final static String LAST_UPDATED_TIME_STRING_KEY = "last-updated-time-string-key"; 

    /** 
    * Provides the entry point to Google Play services. 
    */ 
    protected GoogleApiClient mGoogleApiClient; 

    /** 
    * Stores parameters for requests to the FusedLocationProviderApi. 
    */ 
    protected LocationRequest mLocationRequest; 

    /** 
    * Represents a geographical location. 
    */ 
    protected Location mCurrentLocation; 

    /** 
    * Tracks the status of the location updates request. Value changes when the user presses the 
    * Start Updates and Stop Updates buttons. 
    */ 
    protected Boolean mRequestingLocationUpdates; 

    /** 
    * Time when the location was updated represented as a String. 
    */ 
    protected String mLastUpdateTime; 

    @Override 
    public void onCreate() { 
     Log.d(TAG,"Service started"); 
     super.onCreate(); 
     mRequestingLocationUpdates = false; 
     mLastUpdateTime = ""; 

     // Kick off the process of building a GoogleApiClient and requesting the LocationServices 
     // API. 
     buildGoogleApiClient(); 
    } 

    @Override 
    public int onStartCommand(Intent intent, int flags, int startId) { 
     Log.d(TAG,"Service fucking started"); 
     mGoogleApiClient.connect(); 
     if (mGoogleApiClient.isConnected()) { 
      startLocationUpdates(); 
     } 
     return Service.START_STICKY; 

    } 

    @Override 
    public void onDestroy() { 
     mGoogleApiClient.disconnect(); 
     super.onDestroy(); 
    } 

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

    @Override 
    public void onConnected(Bundle bundle) { 
     Log.i(TAG, "Connected to GoogleApiClient"); 

     // If the initial location was never previously requested, we use 
     // FusedLocationApi.getLastLocation() to get it. If it was previously requested, we store 
     // its value in the Bundle and check for it in onCreate(). We 
     // do not request it again unless the user specifically requests location updates by pressing 
     // the Start Updates button. 
     // 
     // Because we cache the value of the initial location in the Bundle, it means that if the 
     // user launches the activity, 
     // moves to a new location, and then changes the device orientation, the original location 
     // is displayed as the activity is re-created. 
     if (mCurrentLocation == null) { 
      mCurrentLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient); 
      mLastUpdateTime = DateFormat.getTimeInstance().format(new Date()); 
      Toast.makeText(getApplicationContext(),"Hello Babe",Toast.LENGTH_SHORT).show(); 
     } 

     // If the user presses the Start Updates button before GoogleApiClient connects, we set 
     // mRequestingLocationUpdates to true (see startUpdatesButtonHandler()). Here, we check 
     // the value of mRequestingLocationUpdates and if it is true, we start location updates. 
      startLocationUpdates(); 
    } 

    @Override 
    public void onConnectionSuspended(int i) { 
     // The connection to Google Play services was lost for some reason. We call connect() to 
     // attempt to re-establish the connection. 
     Log.i(TAG, "Connection suspended"); 
     mGoogleApiClient.connect(); 
    } 

    @Override 
    public void onLocationChanged(Location location) { 
     mCurrentLocation = location; 
     mLastUpdateTime = DateFormat.getTimeInstance().format(new Date()); 
     Toast.makeText(this, String.valueOf(location.getLatitude() + " "+ String.valueOf(location.getLongitude())), 
       Toast.LENGTH_SHORT).show(); 
     Log.e(TAG,"fuck man location found"); 
    } 

    @Override 
    public void onConnectionFailed(ConnectionResult connectionResult) { 
     // Refer to the javadoc for ConnectionResult to see what error codes might be returned in 
     // onConnectionFailed. 
     Log.i(TAG, "Connection failed: ConnectionResult.getErrorCode() = " + connectionResult.getErrorCode()); 
    } 

    protected synchronized void buildGoogleApiClient() { 
     Log.i(TAG, "Building GoogleApiClient"); 
     mGoogleApiClient = new GoogleApiClient.Builder(this) 
       .addConnectionCallbacks(this) 
       .addOnConnectionFailedListener(this) 
       .addApi(LocationServices.API) 
       .build(); 
     createLocationRequest(); 

    } 
    /** 
    * Sets up the location request. Android has two location request settings: 
    * {@code ACCESS_COARSE_LOCATION} and {@code ACCESS_FINE_LOCATION}. These settings control 
    * the accuracy of the current location. This sample uses ACCESS_FINE_LOCATION, as defined in 
    * the AndroidManifest.xml. 
    * <p/> 
    * When the ACCESS_FINE_LOCATION setting is specified, combined with a fast update 
    * interval (5 seconds), the Fused Location Provider API returns location updates that are 
    * accurate to within a few feet. 
    * <p/> 
    * These settings are appropriate for mapping applications that show real-time location 
    * updates. 
    */ 
    protected void createLocationRequest() { 
     mLocationRequest = new LocationRequest(); 

     // Sets the desired interval for active location updates. This interval is 
     // inexact. You may not receive updates at all if no location sources are available, or 
     // you may receive them slower than requested. You may also receive updates faster than 
     // requested if other applications are requesting location at a faster interval. 
     mLocationRequest.setInterval(UPDATE_INTERVAL_IN_MILLISECONDS); 

     // Sets the fastest rate for active location updates. This interval is exact, and your 
     // application will never receive updates faster than this value. 
     mLocationRequest.setFastestInterval(FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS); 

     mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); 
    } 

    /** 
    * Requests location updates from the FusedLocationApi. 
    */ 
    protected void startLocationUpdates() { 
     // The final argument to {@code requestLocationUpdates()} is a LocationListener 
     // (http://developer.android.com/reference/com/google/android/gms/location/LocationListener.html). 
     LocationServices.FusedLocationApi.requestLocationUpdates(
       mGoogleApiClient, mLocationRequest, this); 
    } 
    /** 
    * Removes location updates from the FusedLocationApi. 
    */ 
    protected void stopLocationUpdates() { 
     // It is a good practice to remove location requests when the activity is in a paused or 
     // stopped state. Doing so helps battery performance and is especially 
     // recommended in applications that request frequent location updates. 

     // The final argument to {@code requestLocationUpdates()} is a LocationListener 
     // (http://developer.android.com/reference/com/google/android/gms/location/LocationListener.html). 
     LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this); 
    } 
    @Override 
    public void onTaskRemoved(Intent rootIntent) { 
     Log.e("FLAGX : ", ServiceInfo.FLAG_STOP_WITH_TASK + ""); 
     Intent restartServiceIntent = new Intent(getApplicationContext(), 
       this.getClass()); 
     restartServiceIntent.setPackage(getPackageName()); 

     PendingIntent restartServicePendingIntent = PendingIntent.getService(
       getApplicationContext(), 1, restartServiceIntent, 
       PendingIntent.FLAG_ONE_SHOT); 
     AlarmManager alarmService = (AlarmManager) getApplicationContext() 
       .getSystemService(Context.ALARM_SERVICE); 
     alarmService.set(AlarmManager.ELAPSED_REALTIME, 
       SystemClock.elapsedRealtime() + 1000, 
       restartServicePendingIntent); 

     super.onTaskRemoved(rootIntent); 
    } 
} 

ответ

12

Override onTaskRemoved() в службы и использование сигнализации менеджера запустить службу снова. Ниже код из нашего приложения, который делает то же самое и работает отлично:

@Override 
public void onTaskRemoved(Intent rootIntent) { 
    super.onTaskRemoved(rootIntent); 

    Log.d(TAG, "TASK REMOVED"); 

    PendingIntent service = PendingIntent.getService(
      getApplicationContext(), 
      1001, 
      new Intent(getApplicationContext(), MyService.class), 
      PendingIntent.FLAG_ONE_SHOT); 

    AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE); 
    alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 1000, service); 
} 

Как вы можете отправить местоположение периодически даже в том случае, если служба погибает на низкой памяти (или по какой-либо причине), я предлагаю вы должны обработать исключение uncaughtException, чтобы перезапустить его через N секунд. Это, как мы сделали в нашем приложении, которое работает отлично:

private Thread.UncaughtExceptionHandler defaultUEH; 
private Thread.UncaughtExceptionHandler uncaughtExceptionHandler = new Thread.UncaughtExceptionHandler() { 

    @Override 
    public void uncaughtException(Thread thread, Throwable ex) { 
     Log.d(TAG, "Uncaught exception start!"); 
     ex.printStackTrace(); 

     //Same as done in onTaskRemoved() 
     PendingIntent service = PendingIntent.getService(
       getApplicationContext(), 
       1001, 
       new Intent(getApplicationContext(), MyService.class), 
       PendingIntent.FLAG_ONE_SHOT); 

     AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE); 
     alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 1000, service); 
     System.exit(2); 
     } 
    }; 

Примечание: Я ДУМАЮ, и я помню, что я проверил это на KitKat, что START_STICKY не работает на KitKat и более высоких уровнях API. Пожалуйста, подтвердите это сами.

MORE:
Как вы LOC отправка периодически, возможно, придется рассмотреть режим глубокого сна. Чтобы заставить вещи работать в глубоком сне, используйте WakefulBroadcastReceiver в сочетании с AlarmManager. Взгляните на мой другой пост How to use http in deep sleep mode.

UPDATE:
Это решение не работает (на самом деле нужно не работать), если пользователь «FORCE STOP» приложения из настроек. Это на самом деле хорошо, поскольку перезапуск службы не является хорошим способом, если пользователь сам хочет остановить приложение. Так, это прекрасно.

+0

Удивительный человек. Большое спасибо. –

+0

Спасибо рассвет, у меня красивое кодирование;) – cgr

+1

Я добавил БОЛЬШЕ ответа, касающегося глубокого спящего режима. Посмотрите, если вы должны позаботиться об этом. – cgr

0

заменить return Service.START_NOT_STICKY; с return START_STICKY;

+0

это была опечатка сюда мой конец. Но это тоже не работает. Я в основном пробовал только START_STICKY. –

0

Если вы ТОЛЬКО хотите перезапустить службу после того, как он убил из Recent задачи, простое использование

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

Если вы используете START_STICKY, когда вы убиваете приложение из недавней задачи, ваша служба будет убит (onTaskRemoved уволен , onDestroyНЕ уволен) ТОГДА он будет автоматически начать снова (onCreate уволят, onStartComand уволен)

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

  • Нет связанных вопросов^_^