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

オーバーライド()でreturn Service.START_NOT_STICKY;を交換して、再度サービスを開始するアラームマネージャを使用します。以下は同じことを行い、正常に動作我々のアプリからのコードです:

@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); 
} 

あなたはサービスが低メモリ上(または何らかの理由で)殺されている場合でも場合には、定期的に位置を送信することと、私がお勧めN秒後に再起動するためにuncaughtExceptionを処理する必要があります。これは、我々は完璧に動作我々のアプリで行っている方法です。

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); 
     } 
    }; 

注:と思うと私はSTART_STICKYはキットカットと高いAPIレベルでは動作しないことキットカットでそれを検証覚えています。これをあなた自身で確認してください。

MORE:
あなたが定期的に送信LOCがそうであるように、あなたはディープスリープモードを検討する必要があります。深い眠りの中で作業するには、WakefulBroadcastReceiverとAlarmManagerを組み合わせて使用​​してください。私の他のポストHow to use http in deep sleep modeを見てください。

UPDATE:
このソリューションでは、ユーザ「強制停止」設定からアプリケーション場合(実際に作業する必要はない)動作しません。実際には、サービスを再開することは、ユーザー自身がアプリケーションを停止したい場合には適していません。だから、大丈夫です。それはあなたが最近タスクからアプリを殺す最近のタスク、あなたがSTART_STICKYを使用している場合は、簡単な使用

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

から殺すの後にあなたがONLYサービスを再起動する場合

+0

恐ろしい男。どうもありがとう。 –

+0

ありがとう、いいコーディングあり;) – cgr

+1

深いスリープモードを扱う答えにMOREを追加しました。あなたもそれを世話しなければならないかどうかを見てください。 – cgr

0

あなたのサービスでonTaskRemoved return START_STICKY;

+0

onCreateonStartComandは解雇、解雇)を再び開始しますこれは、あちこちにタイプミスでした私の終わり。しかし、それはどちらもうまくいかない。私は基本的にSTART_STICKYだけを試みました。 –

0

、あなたのサービスが殺される(onTaskRemovedは解雇します、onDestroy解雇ませTHENそれは自動

関連する問題