gpt4 book ai didi

android - 报警管理器和 onStartCommand

转载 作者:行者123 更新时间:2023-11-30 04:38:43 24 4
gpt4 key购买 nike

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

错误事件的日志在这里:

@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*/
}

最佳答案

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

首先,onStart(Intent intent, int startId) 已弃用,您不需要实现此方法(尤其是如果您只做super.onStart(intent, startId);)。

其次,您无需在设置重复闹钟之前取消它,因为闹钟管理器会为您做这件事。

最重要的是,您应该只在 onStartCommand 方法执行期间获取唤醒锁。在开始时获取它,然后在结束时释放它 - 最好在 finally block 内,以便在发生异常时仍然释放锁。在第一次收到 Intent 时获取锁,然后一直持有直到服务终止,防止 CPU 在无事时休眠 - 这会影响电池生命周期。

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

如果 Android 认为它已变得无响应,则它可能正在终止您的服务。您已经进行了相当多的处理,您可能想考虑将其分解为单独的类 - 这样会更容易理解服务在做什么以及哪里出了问题。

关于android - 报警管理器和 onStartCommand,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6385523/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com