我正在创建一个类似于内置短信应用的应用。
我需要:
- 一个始终在后台运行的服务
- 该服务每5分钟检查设备的当前位置并调用web服务
- 如果满足某些条件,则该服务应生成通知(就像短信应用程序一样)
- 当点击通知时,用户会进入该应用程序(就像短信应用程序一样)
- 安装该应用程序后,服务应该启动
- 当设备重新启动时,服务应该启动
我尝试过:
- 运行定期服务,在Android杀死服务之前可以正常工作
- 使用AlarmManager来实现每5分钟调用服务。但是我无法使其正常工作。
我正在创建一个类似于内置短信应用的应用。
我需要:
我尝试过:
- 运行定期服务,在Android杀死服务之前可以正常工作
- 使用AlarmManager来实现每5分钟调用服务。但是我无法使其正常工作。
一个始终在后台运行的服务
这在实际意义上是不可能的,正如您已经发现的那样。这也是糟糕的设计。
每5分钟,服务检查设备的当前位置并调用Web服务
使用AlarmManager
。
使用AlarmManager使5分钟间隔调用服务。但我无法使其工作。
这里有一个示例项目,展示了如何使用它,以及使用WakefulIntentService
来保持清醒,同时尝试完成整个Web服务的事情。
如果您在使用AlarmManager
时遇到困难,请提出新问题,讨论您所遇到的具体问题。
我的其中一个应用程序做了非常相似的事情。为了在给定时间后唤醒服务,我建议使用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));
}
}
阻止操作系统关闭服务比较棘手。此外,您的应用程序可能会出现RuntimeException
并崩溃,或者您的逻辑可能会停滞。
在我的情况下,似乎通过使用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));
然后在 onDestroy()
中注销您的服务,使用以下代码:
unregisterReceiver(screenOnReceiver);
您可以通过简单的实现方式来完成这个操作:
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();
}
}
/*--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>
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);
}
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);
}
}
}
<receiver android:name=".OwnReceiver" />
@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);
}
AlarmManager.ELAPSED_REALTIME_WAKEUP
您需要等待至少15分钟才能重新启动该服务。
请记住,您还需要使用BroadcastReceiver在重新启动时启动该服务。