AlarmManager& onStartCommand

时间:2011-06-17 12:08:08

标签: android gps location alarmmanager

我在Android上开发了GPS跟踪应用程序。 我每隔5分钟使用AlarmManager唤醒设备。 我开发了一个日志文件,显示应用程序工作正常,直到我收到  public int onStartCommand(Intent intent,int flags,int startId)再次使用startId = 1 ....在这种情况下,我注意到所有变量都被重置,所以我再次初始化所有变量..问题是,一旦发生这种情况,我会继续同样的事件,startID = 1再次,在几次调用后,应用程序停止,直到我打开ActivityForm并再次与服务绑定!!!

这里记录的是坏事件:

@Jun 17, 2011 3:29:31 AM onStartCommand:flags:0:startId:3:intent:Intent { cmp=com.usegps2_1/.LocationService }
@Jun 17, 2011 3:34:10 AM onStartCommand:flags:0:startId:1:intent:Intent { cmp=com.usegps2_1/.LocationService }
@Jun 17, 2011 3:34:10 AM StartService with mbServiceStarted=TRUE
@Jun 17, 2011 3:34:11 AM call InitGPS
@Jun 17, 2011 3:34:11 AM lastKnownLocation: Location[mProvider=gps,mTime=1308274198000,mLatitude=30.10493179906883,mLongitude=31.379563305705755,mHasAltitude=true,mAltitude=85.0,mHasSpeed=true,mSpeed=0.0,mHasBearing=true,mBearing=313.8908,mHasAccuracy=true,mAccuracy=10.0,mExtras=Bundle[mParcelledData.dataSize=4]]
@Jun 17, 2011 4:48:17 AM onStartCommand:flags:0:startId:1:intent:Intent { cmp=com.usegps2_1/.LocationService }
@Jun 17, 2011 4:48:17 AM StartService with mbServiceStarted=TRUE
@Jun 17, 2011 4:48:17 AM call InitGPS
@Jun 17, 2011 4:48:17 AM lastKnownLocation: Location[mProvider=gps,mTime=1308274198000,mLatitude=30.10493179906883,mLongitude=31.379563305705755,mHasAltitude=true,mAltitude=85.0,mHasSpeed=true,mSpeed=0.0,mHasBearing=true,mBearing=313.8908,mHasAccuracy=true,mAccuracy=10.0,mExtras=Bundle[mParcelledData.dataSize=4]]

GPS服务代码在这里:

import java.text.DateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.TimeUnit;
import android.app.AlarmManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.location.Location;
import android.location.LocationManager;
import android.os.Binder;
import android.os.IBinder;
import android.os.PowerManager;
import android.os.SystemClock;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.widget.Toast;
import android.media.*;

public class LocationService extends Service {

    /* ------------------------------------- Attributes */
    int NOTIFICATION_ID = 11283;
    private NotificationManager mNotificationManager; 
    public MainActivity mMainActivity = null;
    protected PowerManager.WakeLock mWakeLock;
    protected AlarmManager mAlarMgr;
    protected PendingIntent AlarmIntent ;

    protected Notification mNotification;
    protected PendingIntent mContentIntent;

    protected static final double d2r = Math.PI / 180.0;

    // Location Variables
    protected static final int mAlarmRepeatRate = 5 * 60 * 1000;
    protected static final int mLocationTimeMinUpdate = 20000;      // minimum time for wait between signals.
    protected static final int mLocationDistanceMinUpdate =  25;    // minimum meters before call back
    protected static final int TWO_MINUTES =  2 * 60 * 1000;        // used to define old readings

    // TODO : This should be a function in speed. with min & max value.
    protected static final int MIN_MapRefreshRate= 10000 ; // rate used to send to webservice.

    protected long mLocationNextSentTime; 
    public String mDeviceID=null;
    public String mBatteryLevel=null;
    protected String mMobileServiceURL = "http://locationbook.net/Tracking.asmx";
    public Boolean mUseGPSOnly;
    public Boolean mEnableBeeps ;
    public Boolean mEnableDebug;
    public String mSpeedText="0";
    public boolean mbBeepStarted = false;
    public boolean mbStarted = false;


    public boolean mbServiceStarted = false;

    public Location mLastLocation =null;


    protected LocationManager mlocManager ;
    protected MainGpsListener mMainGpsListener;
    protected MainLocationListener mlocListenerGPS; 
    protected MainLocationListener mlocListenerNW;

    protected ToneGenerator mTG;
    protected float mSpeed;
    // This is the object that receives interactions from clients.  See
    // RemoteService for a more complete example.
    private final IBinder mBinder = new LocalBinder();

    /* EOF Attributes */


     /**
     * Class for clients to access.  Because we know this service always
     * runs in the same process as its clients, we don't need to deal with
     * IPC.
     */
    public class LocalBinder extends Binder {
        LocationService getService() {
            return LocationService.this;
        }
    }

    /**
     * @see android.app.Service#onBind(Intent)
     */
    @Override
    public IBinder onBind(Intent intent) {
        // TODO Put your code here
        return mBinder;
    }

    /**
     * @see android.app.Service#onCreate()
     */
    @Override
    public void onCreate() {
        super.onCreate();


        // TODO: Input this here to re-create when alarm calls.
        mbServiceStarted = false;
        com.usegps2_1.Logger.Log(getBaseContext(), "onCreate");

    }

    /**
     * @see android.app.Service#onStart(Intent,int)
     */
    @Override
    public void onStart(Intent intent, int startId) {
        // TODO Put your code here
        super.onStart(intent, startId);

    }


    @Override
    public void onDestroy() {

        if (mEnableDebug)Logger.Log(getBaseContext(), "onDestroy");

        mAlarMgr.cancel(AlarmIntent);

        if (mEnableBeeps) mTG.startTone(android.media.ToneGenerator.TONE_DTMF_0,1500);
        if (mEnableBeeps) mTG.startTone(android.media.ToneGenerator.TONE_DTMF_2,2500);

        // Cancel the persistent notification.
        mNotificationManager.cancel(NOTIFICATION_ID); // Remove Notification

        if (mbStarted == true)
        {
            mlocListenerNW.mLocationService=null;
            mlocListenerGPS.mLocationService=null;
            mMainGpsListener.mLocationService=null;
            mlocManager.removeUpdates(mlocListenerNW);
            mlocManager.removeUpdates(mlocListenerGPS);
            mlocManager=null;
        }


        /** I assume that this function will not be called except when I want to close
        * as mWakeLock prevent it from closing. so we can allow closing the screen here.
        */
        mWakeLock.release();

        // Tell the user we stopped.
        Toast.makeText(this, "Service Exit", Toast.LENGTH_SHORT).show();


        super.onDestroy();
    }


     public int onStartCommand(Intent intent, int flags, int startId) {
           // We want this service to continue running until it is explicitly
           // stopped, so return sticky.

            /**
             * http://android-developers.blogspot.com/2010/02/service-api-changes-starting-with.html
             * 1- An application calls startService().
             * 2- That service gets onCreate(), onStart(), and then spawns a background thread to do some work.
             * 3- The system is tight on memory, so has to kill the currently running service.
             * 4- Later when memory is free, the service is restarted, and gets onCreate() called but not onStart() 
             * because there has not been another call to startService() with a new Intent command to send it.
             * START_STICKY is basically the same as the previous behavior,
             *  
             * where the service is left "started" and will later be restarted by the system. 
             * The only difference from previous versions of the platform is that 
             * it if it gets restarted because its process is killed, 
             * onStartCommand() will be called on the next instance of the service with a null Intent instead of not being called at all. 
             * Services that use this mode should always check for this case and deal with it appropriately.
             * 
             * from Android Book.
             * [2] The flag parameter can be used to discover how the Service was started. In particular you can use the
             * code snippet shown in Listing 9-2 to determine if either of the following cases is true:
             * ? START_FLAG_REDELIVERY Indicates that the Intent parameter is a redelivery caused by the
             * system run time’s having terminated the Service before it was explicitly stopped by a call to stopSelf.
             * ? START_FLAG_RETRY Indicates that the Service has been restarted after an abnormal termination.
             * Passed in when the Service was previously set to START_STICKY.
             */


            com.usegps2_1.Logger.Log(getBaseContext(), "onStartCommand:flags:" + String.valueOf(flags) + ":startId:" + String.valueOf(startId)+ ":intent:" + intent.toString());

            if (intent == null)
            {
                // TODO If it’s a restart, do something.
                updateNotification("Restarted");
                if (mTG != null)
                {
                    if (mEnableBeeps) mTG.startTone(android.media.ToneGenerator.TONE_DTMF_5,2000);
                }
            }



            //mAlarMgr.cancel(null);

            // see [2]
            if ((flags & START_FLAG_RETRY) == 0) {
                // FROM DEBUGGING the above condition is wrong it should be != 0.
                // PLease check and review before writing code here.
            }
            else {
                // TODO Alternative background process.
            }

            StartService();

           return  START_STICKY;
         }

     /**
      * Read preference settings and apply them.
      */
     public void ApplyPreferenceSttings()
     {
        mMobileServiceURL = CustomPreferenceManager.GetServiceURL(getApplication());
        mUseGPSOnly= CustomPreferenceManager.GetGPSOnly(getApplication());
        mEnableBeeps= CustomPreferenceManager.GetBeepsEnabled(getApplication()) ;
        mEnableDebug =  CustomPreferenceManager.GetDebugEnabled(getApplication());
     }

     /**
      * Called from outside to start service.
      */
     public void StartService ()
     {


         if (mbServiceStarted == false)
         {
             mbServiceStarted = true;

            // TODO: please remember to use PARTIAL_WAKE_LOCK instead of .SCREEN_DIM_WAKE_LOCK
            PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
            mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "My Tag");
            mWakeLock.acquire();

            ApplyPreferenceSttings();

            if (mEnableDebug)Logger.Log(getBaseContext(), "StartService re-initialize=TRUE");


            TelephonyManager telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
            mDeviceID = telephonyManager.getDeviceId();


            showNotification();

            mTG = new ToneGenerator (1,80);

            if (mAlarMgr != null)
            if (mEnableDebug)Logger.Log(getBaseContext(), "mAlarMgr is true");

            mAlarMgr = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
            Intent intentToFire = new Intent (GPSBroadcastReceiver.ReceiverName);
            AlarmIntent = PendingIntent.getBroadcast(this, 0, intentToFire, 0);
            mAlarMgr.cancel(AlarmIntent); //Remove any alarms with a matching Intent. [BUG] avoid creating many alarms ... caused multipl alarm call with mbServiceStarted=False when check debugging files.
            mAlarMgr.setRepeating(AlarmManager.RTC_WAKEUP, SystemClock.elapsedRealtime() + mAlarmRepeatRate , mAlarmRepeatRate, AlarmIntent);

            // Register in Battery
            this.registerReceiver(this.mBatInfoReceiver,new IntentFilter(Intent.ACTION_BATTERY_CHANGED));

             StartLocation();
         }
         else
         {

             //updateNotification("called again while running");
         }

         // */ 
     }



     protected void showNotification ()
        {
            mNotificationManager = (NotificationManager) getSystemService (Context.NOTIFICATION_SERVICE);
            // Define Notification
            mNotification = new Notification(R.drawable.step, "Tracking on", System.currentTimeMillis());
            mNotification.flags = Notification.FLAG_ONGOING_EVENT;
            // Define Notification Action
            Intent  intent = new Intent(getApplicationContext(), MainActivity.class);
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
            mContentIntent = PendingIntent.getActivity(LocationService.this, 0,intent, PendingIntent.FLAG_CANCEL_CURRENT);

            // Set Notification
            mNotification.setLatestEventInfo(LocationService.this,getText(R.string.app_name),"click to display main screen",mContentIntent);
            // Add it
            mNotificationManager.notify(NOTIFICATION_ID, mNotification);
        }

     protected void updateNotification (CharSequence Description)
      {
          if (mNotification ==null) return ;
          mNotification.when=System.currentTimeMillis();
            // Set Notification
          mNotification.setLatestEventInfo(LocationService.this,getText(R.string.app_name),Description,mContentIntent);
            // Add it
          mNotificationManager.notify(NOTIFICATION_ID, mNotification);
      }
     /*-------------------------------------------------GPS Methods*/

      protected void StartLocation ()
        {
            if (mbStarted == true)
            {
                Toast.makeText( getApplicationContext(),"already running",Toast.LENGTH_SHORT).show();
                return ; 
            }

            if (mEnableDebug)Logger.Log(getBaseContext(), "InitGPS true");

            mbStarted = true;
            mLocationNextSentTime = 0 ; // Send once u get data
            if (mEnableBeeps) mTG.startTone(android.media.ToneGenerator.TONE_DTMF_1,1000);




            // Use the LocationManager class to obtain GPS locations
            mlocManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
            Toast.makeText( getApplicationContext(),"Started",Toast.LENGTH_SHORT).show();


            Location loc= mlocManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);

            // try to read current position
            if(loc != null){
                mLastLocation=loc;
                if (mEnableDebug)Logger.Log(getBaseContext(), "lastKnownLocation: " + loc.toString());
            }
            else
            {
                updateNotification ("getting location");

            }

            mlocListenerGPS = new MainLocationListener(this);
            mlocListenerNW  = new MainLocationListener(this);
            mlocListenerGPS.mProvider="GPS";
            mlocListenerNW.mProvider="NW";

            mMainGpsListener = new MainGpsListener(this);
            // Define a listener that responds to location updates


            mlocManager.addGpsStatusListener(mMainGpsListener);
            mlocManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, mLocationTimeMinUpdate, mLocationDistanceMinUpdate, mlocListenerGPS);
            mlocManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, mLocationTimeMinUpdate, mLocationDistanceMinUpdate, mlocListenerNW);

            if (mEnableDebug)Logger.Log(getBaseContext(), "GPS reinitialized");

            // */
        }



        public void UpdateLocation (Location loc, String Provider)
        {

            try
            {
                if (mUseGPSOnly  && (Provider != "GPS")) return ;

                if (mbStarted == false)
                {
                    updateNotification("false");
                }


                if (mEnableBeeps) mTG.startTone(android.media.ToneGenerator.TONE_DTMF_9,200);

                String E = loc.toString();
                if (mEnableDebug)Logger.Log(getBaseContext(), "New Location");
                if (mEnableDebug)Logger.Log(getBaseContext(), loc.toString());

                if (isBetterLocation (loc,mLastLocation)==false)
                {
                    updateNotification ("location ignored");
                    return ;
                }


                mLastLocation = loc;

                mMainActivity.mtxtTime.setText(DateFormat.getDateInstance().format(new Date()));
                mMainActivity.mtxtLatitude.setText(loc.getLatitude() + " lat");
                mMainActivity.mtxtLongitude.setText(loc.getLongitude() + " lng");

                float speed = loc.getSpeed(); // value if set by GetSpeed that is called insite isBetterLocation
                mSpeedText=Float.toString(speed) ;
                mMainActivity.mtxtSpeed.setText(mSpeedText + " km/s");



                if ((loc.getTime() > mLocationNextSentTime))
                {

                    mLocationNextSentTime = (long) (loc.getTime() + MIN_MapRefreshRate * ( 140 - speed)/ 140);

                    if (mEnableDebug)Logger.Log(getBaseContext(), "Next HTTP: " + String.valueOf(mLocationNextSentTime));

                    WebMethodProxy client = new WebMethodProxy(mMobileServiceURL + "/UpdateLocation");
                    client.AddParam("guid", mDeviceID);
                    client.AddParam("latitude",Double.toString(loc.getLatitude()));
                    client.AddParam("longitude", Double.toString(loc.getLongitude()));
                    client.AddParam("speed", mSpeedText);
                    client.AddParam("battery",mBatteryLevel);       

                    //if (mEnableBeeps) mTG.startTone(android.media.ToneGenerator.TONE_DTMF_5,500);

                    try {
                        client.Execute(WebMethodProxy.RequestMethod.POST_JSON);
                    } catch (Exception e) {
                        e.printStackTrace();

                        // TODO : error message cannot connect to server
                        if (mEnableBeeps) mTG.startTone(android.media.ToneGenerator.TONE_DTMF_9,2500);
                        String err = (e.getMessage() == null)?"GPS Error":e.getMessage();

                        if (mEnableDebug)Logger.Log(getBaseContext(), "Failed: " + err);

                        Log.e("TrackGPS",err);
                        mMainActivity.mtxtMessage.setText("Cannot reach Internet to update location.");
                        return ;
                    }

                    String response = client.getResponse();
                    response = (response ==null)?"no web reply":response;

                    if (mEnableDebug)Logger.Log(getBaseContext(), "HTTP DONE: " + response );


                    Toast.makeText( getApplicationContext(),"Updated[" + Provider + "]:" + response,Toast.LENGTH_SHORT).show();
                    updateNotification ("location updated");

                }
                else
                {
                    updateNotification ("location ignored.");
                }
            }
            catch (Exception e)
            {
                if (mEnableBeeps) mTG.startTone(android.media.ToneGenerator.TONE_DTMF_2,2500);
                 String err = (e.getMessage() == null)?"GPS Error":e.getMessage();
                 Log.e("TrackGPS",err);
                 updateNotification ("DEBUG1: " + e.getMessage());
                 return ; 
            }

        }


        /**
         * Returns distance in meters between two points.
         * @param NewLocation
         * @param CurrentLocation
         * @return
         */
        protected float CalculateSpeed (Location NewLocation, Location CurrentLocation) {
            try
            {
            double dlong = (NewLocation.getLongitude() - CurrentLocation.getLongitude()) * d2r;
            double dlat = (NewLocation.getLatitude() - CurrentLocation.getLatitude()) * d2r;
            double a = Math.pow(Math.sin(dlat/2.0), 2) + Math.cos(CurrentLocation.getLatitude()*d2r) * Math.cos(NewLocation.getLatitude()*d2r) * Math.pow(Math.sin(dlong/2.0), 2);
            double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
            double d = 6367000 * c;
            double TimeDelta = NewLocation.getTime() - CurrentLocation.getTime();
            return (float) (d/TimeDelta) * 3600;
            }
            catch (Exception e)
            {
                if (mEnableBeeps) mTG.startTone(android.media.ToneGenerator.TONE_DTMF_2,2500);
                 Log.e("TrackGPS",e.getMessage());
                 updateNotification ("DEBUG2: " + e.getMessage());
                return 0;
            }

        }

        /** Determines whether one Location reading is better than the current Location fix
         * Logic:
         *  if too old return FALSE.
         *  if too new return TRUE anyway as the current is too old.
         *  if more accurate then return TRUE 
         *  if newer and same or more accurate then return TRUE.
         *  if newer and less accurate but same provider return TRUE.
         *  ------------------------------------------------------
         *  Time        Accuracy    Same Provider       Return
         *  ------------------------------------------------------
         *  Too Old         x           x               FALSE
         *  Too New         x           x               TRUE
         *  Older         Plus          x               TRUE
         *  Newer         Plus          x               TRUE
         *  Newer         Same          x               TRUE
         *  Newer         Less        TRUE              TRUE
         *  ======================================================
         * @param location  The new Location that you want to evaluate
         * @param currentBestLocation  The current Location fix, to which you want to compare the new one
        */
        protected boolean isBetterLocation(Location location, Location currentBestLocation) {
            try
            {
            location.setSpeed(0); // preset

            if (currentBestLocation == null) {
                // A new location is always better than no location
                if (mEnableDebug)Logger.Log(getBaseContext(), "Accepted: first location");
                return true;
            }

            // Check whether the new location fix is newer or older
            long timeDelta = location.getTime() - currentBestLocation.getTime();
            boolean isSignificantlyNewer = timeDelta > TWO_MINUTES;
            boolean isSignificantlyOlder = timeDelta < -TWO_MINUTES;
            boolean isNewer = timeDelta > 0;

            // If it's been more than two minutes since the current location, use the new location
            // because the user has likely moved
            if (isSignificantlyNewer) {
                if (mEnableDebug)Logger.Log(getBaseContext(), "Accepted: isSignificantlyNewer");
                return true;
            // If the new location is more than two minutes older, it must be worse
            } else if (isSignificantlyOlder) {
                if (mEnableDebug)Logger.Log(getBaseContext(), "Rejected: isSignificantlyOlder");
                return false;
            }

            // Check whether the new location fix is more or less accurate
            int accuracyDelta = (int) (location.getAccuracy() - currentBestLocation.getAccuracy());
            boolean isLessAccurate = accuracyDelta > 0;
            boolean isMoreAccurate = accuracyDelta < 0;
            boolean isSignificantlyLessAccurate = accuracyDelta > 200;

            // Check if the old and new location are from the same provider
            boolean isFromSameProvider = isSameProvider(location.getProvider(),
                    currentBestLocation.getProvider());

            // Determine location quality using a combination of timeliness and accuracy
            if (isMoreAccurate) {
                location.setSpeed(CalculateSpeed (location,currentBestLocation));
                if (mEnableDebug)Logger.Log(getBaseContext(), "Accepted: isMoreAccurate");
                return true;
            } else if (isNewer && !isLessAccurate) {
                location.setSpeed(CalculateSpeed (location,currentBestLocation));
                if (mEnableDebug)Logger.Log(getBaseContext(), "Accepted: isNewer and not isLessAccurate");
                return true;
            } else if (isNewer && !isSignificantlyLessAccurate && isFromSameProvider) {
                location.setSpeed(CalculateSpeed (location,currentBestLocation));
                if (mEnableDebug)Logger.Log(getBaseContext(), "Accepted: isNewer and LessAccurate but from same provider");

                return true;
            }

            if (mEnableDebug)Logger.Log(getBaseContext(), "Rejected: ???");

            return false;
            }
            catch (Exception e)
            {
                updateNotification ("Debug3: " + e.getMessage());
                return false;
            }
        }

        /** Checks whether two providers are the same */
        protected boolean isSameProvider(String provider1, String provider2) {
            if (provider1 == null) {
              return provider2 == null;
            }
            return provider1.equals(provider2);
        }

        /*GPS Methods:EOF*/



        /*-------------------------------------------------BAT Methods*/
        protected BroadcastReceiver mBatInfoReceiver = new BroadcastReceiver(){

            @Override

            public void onReceive(Context arg0, Intent intent) {

              int level = intent.getIntExtra("level", 0);
              double voltage= intent.getIntExtra("voltage", 0) ;
              double batteryTemperature = intent.getIntExtra("temperature", 0); 

              // update battery level.
              mBatteryLevel = String.valueOf(level);

              if (level < 31)
              {
                  mMainActivity.mtxtBatteryInfo.setText("level: " + Double.toString(level) + " pls connect to charger.");
                  mMainActivity.mtxtBatteryInfo.setTextColor(0xffff0033);
              }
              else
              {
                  mMainActivity.mtxtBatteryInfo.setText("level: " + Double.toString(level) + "% voltage: " + String.valueOf(Double.toString(voltage / 1000.0)) + " Temp: " + Double.toString(batteryTemperature /10.0) + " c");
                  mMainActivity.mtxtBatteryInfo.setTextColor(0xff99ff33);
              }
            }

          };
        /*BAT Methods:EOF*/
}

1 个答案:

答案 0 :(得分:1)

我在这里可以看到很多问题。

首先,不推荐使用onStart(Intent intent,int startId),您不需要实现此方法(特别是如果您所做的只是super.onStart(intent, startId);)。

其次,您无需在设置之前取消重复闹钟,因为闹钟管理器会为您执行此操作。

最重要的是,您应该只在onStartCommand方法的持续时间内获取唤醒锁定。在开始时获取它,然后在结束时释放它 - 理想情况下在finally块内释放它,以便在发生异常时锁仍然被释放。在第一次接收到意图时获取锁定,然后保持直到服务终止,防止CPU在无操作时休眠 - 这将影响电池寿命。

对于意图的重复传递 - 如果您的服务变量正在重新初始化,那么听起来您的服务正在由Android重新启动,因为它已经死亡。你有没有检查过logcat(运行连接时)的堆栈跟踪?也许将进程ID添加到日志输出中,以便发现这种情况何时发生。

如果Android认为它没有响应,则可能会终止您的服务。你已经进行了相当多的处理,你可能想要考虑将它分解为单独的类 - 然后更容易理解服务正在做什么以及它出错的地方。