我正在每隔20秒启动一个基于报警管理器
的服务,它将GPS
数据发送到我的服务器。问题是我的堆和分配的堆大小继续增加。在分析堆转储时,我发现服务实例的数量等于对startservice()
的调用数量。如何避免这个问题?
public class SystemBootListener extends BroadcastReceiver { // Restart service every 30 seconds private static final long REPEAT_TIME = 1000 * 10; @Override public void onReceive(Context context, Intent intent) { Intent i = new Intent(context, StartLocationServiceAfterReboot.class); PendingIntent pending = PendingIntent.getBroadcast(context, 0, PendingIntent.FLAG_UPDATE_CURRENT); // Start 20 seconds after boot completed - so that all providers are initialized by then Calendar cal = Calendar.getInstance(); cal.add(Calendar.SECOND, 20); // Trigger every 10 seconds // InexactRepeating allows Android to optimize the energy consumption AlarmManager service = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); service.setInexactRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), REPEAT_TIME, pending); } }
public class StartLocationServiceAfterReboot extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if(AppSettings.isRouteConfigured(context)){ AppSettings.setServiceRunning(context, Boolean.TRUE); Intent service = new Intent(context, GPSComputationService.class); context.startService(service); } } }
public class GPSComputationService extends Service {
private static final int MAX_TIME_TO_FETCH_NEW_LOCATION = 8000;
private final IBinder mBinder = new ServiceBinder();
private Timer timerToFetchLocInfoFromProviders = null;
private LocationManager locationManager = null;
private boolean gpsProviderEnabled=false;
private boolean networkProviderEnabled=false;
private int numberOfSatellites = 0;
private GPSData bestKnownLocation = new GPSData();
private TCPWriter tcpWriter ;
@Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
tcpWriter= new TCPWriter(this);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
/*tcpWriter= new TCPWriter(this);*/
computeBestLocation();
return Service.START_STICKY;
}
private void stopGPSComputationService(){
stopSelf();
}
@Override
public IBinder onBind(Intent arg0) {
return mBinder;
}
public class ServiceBinder extends Binder {
public GPSComputationService getService() {
return GPSComputationService.this;
}
}
public GPSData getBestKnownLocation() {
return bestKnownLocation;
}
public void publishBestKnownLocation(GPSData bestKnownLocation) {
this.bestKnownLocation = bestKnownLocation;
sendBestKnownLocationToNMEAServer();
}
public void sendBestKnownLocationToNMEAServer(){
if(getBestKnownLocation() == null){
stopGPSComputationService();
return;
}
TelephonyManager telephonyManager = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
telephonyManager.getDeviceId();
NMEAData dataPacketToWrite = new NMEAData(
telephonyManager.getDeviceId(),
getBestKnownLocation().getLatitude(),
getBestKnownLocation().getLongitude(),
getBestKnownLocation().getTimeStamp(),
getBestKnownLocation().getSpeed(),
getBestKnownLocation().getNumberOfSatellites()
);
tcpWriter.sendMessage(NMEAServerTypes.MVT600,
dataPacketToWrite);
stopGPSComputationService();
}
public GPSData computeBestLocation() {
Log.d("#############GPSComputation Status", "Running.......");
try{
if(locationManager==null)
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
//Add status listener for satellite count
locationManager.addGpsStatusListener(gpsStatusListener);
Criteria criteria = new Criteria();
criteria.setSpeedRequired(true);
criteria.setBearingRequired(true);
List<String> providers = locationManager.getProviders(criteria, false);
//Capture if the GPS/Network providers have been disabled.
try{
gpsProviderEnabled=providers.contains(LocationManager.GPS_PROVIDER) &&
locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
}catch(Exception e){
}
try{
networkProviderEnabled=providers.contains(LocationManager.NETWORK_PROVIDER) &&
locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
}catch(Exception e){
}
if(!gpsProviderEnabled && !networkProviderEnabled)
return null;
if(gpsProviderEnabled)
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListenerGps);
if(networkProviderEnabled)
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListenerNetwork);
timerToFetchLocInfoFromProviders=new Timer();
timerToFetchLocInfoFromProviders.schedule(new GetLastKnownGoodLocation(), MAX_TIME_TO_FETCH_NEW_LOCATION);
locationManager.removeGpsStatusListener(gpsStatusListener);
//Finally store the data in backend Service
return getBestKnownLocation() ;
}catch(Exception e){
return null;
}
}
LocationListener locationListenerGps = new LocationListener() {
public void onLocationChanged(Location location) {
timerToFetchLocInfoFromProviders.cancel();
publishBestKnownLocation(extractAllGeoInfFromLocation(location));
locationManager.removeUpdates(this);
locationManager.removeUpdates(locationListenerNetwork);
locationManager.removeGpsStatusListener(gpsStatusListener);
gpsStatusListener = null;
}
public void onProviderDisabled(String provider) {
}
public void onProviderEnabled(String provider) {
}
public void onStatusChanged(String provider, int status, Bundle extras) {
}
};
//listen for gps status changes to capture number of satellites.
GpsStatus.Listener gpsStatusListener = new GpsStatus.Listener() {
@Override
public void onGpsStatusChanged(int event) {
if (event == GpsStatus.GPS_EVENT_SATELLITE_STATUS || event == GpsStatus.GPS_EVENT_FIRST_FIX) {
GpsStatus status = locationManager.getGpsStatus(null);
Iterable<GpsSatellite> sats = status.getSatellites();
// Check number of satellites in list to determine fix state
int tempNumberOfSatellites = 0;
for (GpsSatellite sat : sats) {
if(sat.usedInFix())
tempNumberOfSatellites++;
}
numberOfSatellites = tempNumberOfSatellites;
}
}
};
LocationListener locationListenerNetwork = new LocationListener() {
public void onLocationChanged(Location location) {
timerToFetchLocInfoFromProviders.cancel();
publishBestKnownLocation(extractAllGeoInfFromLocation(location));
locationManager.removeUpdates(this);
locationManager.removeUpdates(locationListenerGps);
}
public void onProviderDisabled(String provider) {
}
public void onProviderEnabled(String provider) {
}
public void onStatusChanged(String provider, int status, Bundle extras) {
}
};
class GetLastKnownGoodLocation extends TimerTask {
@Override
public void run() {
locationManager.removeUpdates(locationListenerGps);
locationManager.removeUpdates(locationListenerNetwork);
Location bestKnownNetworkLocation = null, bestKnownGPSLocation=null;
if(gpsProviderEnabled)
bestKnownGPSLocation=locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if(networkProviderEnabled)
bestKnownNetworkLocation=locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
if(bestKnownGPSLocation!=null && bestKnownNetworkLocation!=null){
if(bestKnownGPSLocation.getTime()>bestKnownNetworkLocation.getTime())
publishBestKnownLocation(extractAllGeoInfFromLocation(bestKnownGPSLocation));
else
publishBestKnownLocation(extractAllGeoInfFromLocation(bestKnownNetworkLocation));
return;
}
if(bestKnownGPSLocation!=null){
publishBestKnownLocation(extractAllGeoInfFromLocation(bestKnownGPSLocation));
return;
}
if(bestKnownNetworkLocation!=null){
publishBestKnownLocation(extractAllGeoInfFromLocation(bestKnownNetworkLocation));
return;
}
AppLog.logWarningMsg("Bad luck-NO BEST LOCATION AVAILABLE");
publishBestKnownLocation(null);
}
}
private GPSData extractAllGeoInfFromLocation(Location location){
bestKnownLocation = new GPSData();
bestKnownLocation.setLatitude(location.getLatitude());
bestKnownLocation.setLongitude(location.getLongitude());
bestKnownLocation.setTimeStamp(location.getTime());
bestKnownLocation.setSpeed(location.getSpeed()*3.8);
bestKnownLocation.setNumberOfSatellites(numberOfSatellites);
return bestKnownLocation;
}
}
改进和简化代码的一些提示:
>
您希望使用one shot服务报告GPS坐标。为此,intentservice
要好得多,它在后台线程中运行。https://developer.android.com/training/run-background-service/create-service
使用PendingIntent.getService()
而不是调用StartLocationServiceAfterReboot
来启动其他Android组件。你可以马上做那件事。你省了一步。https://developer.android.com/reference/android/app/pendingintent.html#GetService(android.content.context,%2520int,%2520android.content.intent,%2520int)
每次使用资源时(如GPS、传感器等)您还必须编写发布部分。正如我所看到的,您将监听器注册到GPS服务,但从不释放(取消注册)它们。
AppSettings.SetServiceRunning(context,Boolean.true);
是什么?我猜您将此保存到sharedpreference
中。当应用程序强制停止、设备重新启动或突然关闭时,这可能会受到影响。可能更好的方法是https://stackoverflow.com/A/5921190/5823014
避免在上下文、activity、服务、BroadcastReceiver、应用程序实例上使用static
。我没有在您的代码片段中看到,只是一个防止内存泄漏的一般性建议。
唯一能够创建这种场景的是您存在某种内存泄漏。您的服务完成了它的工作并停止,但没有垃圾收集。它可能发生的次数很少,这就是为什么你会看到很多这样的例子。
很难发现内存泄漏,但我建议您从监听器开始。检查您是否在正确的时间取消了它们的注册。
这个链接可以帮助您检测泄漏:https://developer.android.com/studio/profile/am-memory.html
只有一个Service实例。按文件规定
对context.startService()的多次调用确实会导致对onStartCommand())的多次相应调用,但只能存在一个服务实例。
在startService()上,Android系统调用服务的onStartCommand()方法。如果服务尚未运行,系统首先调用onCreate(),然后调用onStartCommand()。
今天在更新根文件夹中的play服务后,我面临以下问题。我不知道如何解决这个问题。 有人能帮我解决这个问题吗? 这个错误让人很恼火。我不知道冲突在哪里。顺便说一下,为什么它显示冲突,而没有版本是相互关联的。 错误: 库com.google.android.gms: play-services-metaming-base正在被[[15.0.0,15.0.0]、[15.0.2,15.0.2]]的其他库请
我和Jetty一起使用“Spring-Boot-Starter-Web”。在我启动应用程序之后,我能够调用rest函数。有没有什么方法可以直接访问Jetty实例,或者在Jetty启动后连接服务器/servlet上下文?
我使用的是Selenium3.9.0+Geckodriver0.24+Firefox58.0.2。 当webdriver想要在我的目标站点上单击导航树中的元素时->script crashing with selenium异常:“selenium.Common.Exceptions.ElementClickInterceptedException:Message:element is not cl
我们在服务器和客户机模式下使用Ignite 2.7.6:两个服务器和六个客户机。 正如我们所看到的,现在所有服务器节点的CPU负载都很高,约为250%(更新前为20%),而长G1 Young Gen的停顿时间高达5毫秒(更新前为300微秒)。 服务器配置为: 在Ignite服务器节点的内存转储中,我们看到大量,大小为21MB
我正在使用功能区客户端进行客户端负载平衡。我正在实施微服务Spring启动 2.2.6.发布。我有CHAT-BOOK和USER-APP两个微服务。我在 CHAT-BOOK 中添加了所需的依赖项(spring-boot-starter-web,spring-cloud-starter-netflix-ribbon)中的 USER-APP 微服务.xml。 参考网址: https://www.yout