如何始终在后台运行服务?

我正在创建一个应用程序,类似于内置的短信应用程序的过程中。

我需要:

  • 总是在后台运行的服务
  • 服务每5分钟检查一次设备的当前位置并调用一个 Web 服务
  • 如果满足某些条件,服务应该生成一个通知(就像 SMS 应用程序)
  • 当点击通知时,用户被带到应用程序(就像 SMS 应用程序一样)
  • when the app is installed the service should be started
  • when the device is rebooted, the service should be started

我所尝试的:
- running a regular service which worked just fine until Android kills the service
- 使用报警管理器,使5分钟。对服务的间隔调用。但我没能做到。

81944 次浏览

我的一个应用程序做了一些非常类似的事情。为了在给定时间后唤醒服务,我建议使用 postDelayed()

有一个处理器字段:

private final Handler handler = new Handler();

和复习 Runnable

private final Runnable refresher = new Runnable() {
public void run() {
// some action
}
};

您可以在可运行文件中激发通知。

关于服务构建,在每次执行之后都是这样开始的:

handler.postDelayed(refresher, /* some delay in ms*/);

onDestroy()中移除柱子

handler.removeCallbacks(refresher);

要在启动时启动服务,您需要一个自动启动器

<receiver android:name="com.example.ServiceAutoStarter">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>

ServiceAutoStarter是这样的:

public class ServiceAutoStarter extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
context.startService(new Intent(context, UpdateService.class));
}
}

Stopping the OS from killing the service is tricky. Also your application can have a RuntimeException and crash, or your logic can stall.

在我的情况下,总是用 BroadcastReceiver刷新屏幕上的服务似乎有所帮助。因此,如果更新链停滞不前,它将在用户使用手机时重新启动。

服务范围:

private BroadcastReceiver screenOnReceiver;

在你的服务 onCreate()

screenOnReceiver = new BroadcastReceiver() {


@Override
public void onReceive(Context context, Intent intent) {
// Some action
}
};


registerReceiver(screenOnReceiver, new IntentFilter(Intent.ACTION_SCREEN_ON));

Then unregister your service on onDestroy() with

unregisterReceiver(screenOnReceiver);

总是在运行的服务 背景

This is 不可能 in any real sense of the term, as you have discovered. It is also 糟糕的设计.

服务每5分钟检查一次 设备的当前位置和 调用 Web 服务

使用 AlarmManager

使用报警管理器,使5 一个服务的间隔调用。但是我 没能成功。

下面是一个 样本项目演示如何使用它,以及如何使用 WakefulIntentService,这样您在尝试使用整个 Web 服务时就会保持清醒。

如果你仍然有这方面的问题,那就打开一个新的问题,看看你在使用 AlarmManager时遇到了什么具体的问题,这些问题会给你带来痛苦。

您可以通过一些简单的实现来实现:

public class LocationTrace extends Service implements LocationListener{


// The minimum distance to change Updates in meters
private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 10; // 10 meters
private static final int TWO_MINUTES = 100 * 10;


// The minimum time between updates in milliseconds
private static final long MIN_TIME_BW_UPDATES = 1000 * 10; // 30 seconds


private Context context;


double latitude;
double longitude;


Location location = null;
boolean isGPSEnabled = false;
boolean isNetworkEnabled = false;
protected LocationManager locationManager;




@Override
public int onStartCommand(Intent intent, int flags, int startId) {


this.context = this;
get_current_location();
//      Toast.makeText(context, "Lat"+latitude+"long"+longitude,Toast.LENGTH_SHORT).show();
return START_STICKY;
}




@Override
public void onLocationChanged(Location location) {
if((location != null) && (location.getLatitude() != 0) && (location.getLongitude() != 0)){


latitude = location.getLatitude();
longitude = location.getLongitude();


if (!Utils.getuserid(context).equalsIgnoreCase("")) {
Double[] arr = { location.getLatitude(), location.getLongitude() };


// DO ASYNCTASK
}
}


}




@Override
public void onStatusChanged(String provider, int status, Bundle extras) {


}


@Override
public void onProviderEnabled(String provider) {


}


@Override
public void onProviderDisabled(String provider) {


}


/*
*  Get Current Location
*/
public Location get_current_location(){


locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);


isGPSEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);


isNetworkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);


if(!isGPSEnabled && !isNetworkEnabled){






}else{
if (isGPSEnabled) {


if (location == null) {
locationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER,
MIN_TIME_BW_UPDATES,
MIN_DISTANCE_CHANGE_FOR_UPDATES, this);


if (locationManager != null) {
location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if (location != null) {
latitude = location.getLatitude();
longitude = location.getLongitude();
//                  Toast.makeText(context, "Latgps"+latitude+"long"+longitude,Toast.LENGTH_SHORT).show();
}
}
}
}
if (isNetworkEnabled) {


locationManager.requestLocationUpdates(
LocationManager.NETWORK_PROVIDER,
MIN_TIME_BW_UPDATES,
MIN_DISTANCE_CHANGE_FOR_UPDATES, this);


if (locationManager != null) {


if (location != null) {
latitude = location.getLatitude();
longitude = location.getLongitude();
//              Toast.makeText(context, "Latgps1"+latitude+"long"+longitude,Toast.LENGTH_SHORT).show();
}
}
}
}


return location;
}




public double getLatitude() {
if(location != null){
latitude = location.getLatitude();
}
return latitude;
}


public double getLongitude() {
if(location != null){
longitude = location.getLongitude();
}


return longitude;
}




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


@Override
public void onDestroy() {
if(locationManager != null){
locationManager.removeUpdates(this);
}
super.onDestroy();
}


}

You can start service by this :

/*--Start Service--*/
startService(new Intent(Splash.this, LocationTrace.class));

清单:

 <service android:name=".LocationTrace">
<intent-filter android:priority="1000">
<action android:name="android.location.PROVIDERS_CHANGED"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</service>

通过这三个步骤,你可以每5分钟唤醒大多数 Android 设备:

1. 为不同的 API 设置备用 AlarmManager:

AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(getApplicationContext(), OwnReceiver.class);
PendingIntent pi = PendingIntent.getBroadcast(getApplicationContext(), 0, i, 0);


if (Build.VERSION.SDK_INT >= 23) {
am.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + (1000 * 60 * 5), pi);
}
else if (Build.VERSION.SDK_INT >= 19) {
am.setExact(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + (1000 * 60 * 5), pi);
} else {
am.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + (1000 * 60 * 5), pi);
}

2. build your own static BroadcastReceiver :

public static class OwnReceiver extends BroadcastReceiver {


@Override
public void onReceive(Context context, Intent intent) {


//do all of your jobs here


AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(context, OwnReceiver.class);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);


if (Build.VERSION.SDK_INT >= 23) {
am.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + (1000 * 60 * 5), pi);
}
else if (Build.VERSION.SDK_INT >= 19) {
am.setExact(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + (1000 * 60 * 5), pi);
} else {
am.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + (1000 * 60 * 5), pi);
}
}
}

3. 将 <receiver>加到 AndroidManifest.xml:

<receiver android:name=".OwnReceiver"  />

根据我的理解,当你希望你的服务运行时,总是意味着它不应该在应用程序被关闭时被停止,因为如果你的应用程序正在运行或者在后台,无论如何你的服务都会运行。当您在服务运行时关闭应用程序时,将触发 onTaskRemoved 函数。

@Override
public void onTaskRemoved(Intent rootIntent) {
Log.d(TAG, "onTaskRemoved: removed");
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis() + 10000);
((AlarmManager) getSystemService(Context.ALARM_SERVICE)).setExact(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), PendingIntent.getService(getApplicationContext(), 0, new Intent(getApplicationContext(), RegisterReceiverService.class), 0));
super.onTaskRemoved(rootIntent);
}

所以基本上,一旦你关闭应用程序,服务将在10秒后启动。 注意: 如果你想使用

AlarmManager.ELAPSED_REALTIME_WAKEUP

the minimum time after which you'll be able to restart the service will be 15 minutes.

请记住,还需要在使用 BroadcastReceiver 重新启动时启动服务。