如何每 5 分钟运行 10 秒的前台服务?
Posted
技术标签:
【中文标题】如何每 5 分钟运行 10 秒的前台服务?【英文标题】:How to run a foreground service for 10 seconds, every 5 minutes? 【发布时间】:2020-03-06 22:04:35 【问题描述】:我想运行Foreground Service
,无论应用程序是关闭还是打开,例如 10 秒。在这 10 秒过去后,Foreground Service
应该被销毁并在 5 分钟后再次调用。 Foreground Service
我找到了用户的位置,然后将其保存到 SQLite
数据库中。所以基本上我想每 5 分钟存储一次新坐标,这样我可以提高电池消耗。
我的服务等级:
public class LocationService extends Service
private final static int UPDATE_TIME = 10000;
private final static int UPDATE_DISTANCE = 0;
private LocationListener locationListener;
private LocationManager locationManager;
private PowerManager.WakeLock mWakeLock;
private String latitude, longitude;
private DatabaseHelper myDb;
@Override
public void onCreate()
super.onCreate();
myDb = new DatabaseHelper(this);
locationManager = (LocationManager) getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
createWakeLock(); //Creates a wakelock
createNotification(); //Creates a notification if SDK version is > 26
@SuppressLint("MissingPermission")
@Override
public int onStartCommand(Intent intent, int flags, int startId)
mWakeLock.acquire(10*60*500L /*5 minutes*/);
locationListener = new LocationListener()
@Override
public void onLocationChanged(Location location)
Log.d("Location", "Updated");
getCoordinates(location); //Gets coordinates
insertCoordinates(latitude, longitude); //Sends coordinates to SQLite database
sendDataToMainActivity(latitude, longitude); //Sends coordinates to MainActivity
@Override
public void onStatusChanged(String provider, int status, Bundle extras)
@Override
public void onProviderEnabled(String provider)
@Override
public void onProviderDisabled(String provider)
Intent i = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(i);
;
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, UPDATE_TIME, UPDATE_DISTANCE, locationListener);
return START_NOT_STICKY;
@Override
public void onDestroy()
super.onDestroy();
Log.d("Service", "Destroyed");
if(locationManager != null)
locationManager.removeUpdates(locationListener);
mWakeLock.release();
private void createWakeLock()
PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE);
if(pm != null)
mWakeLock = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE, "myApp:myWakeLock");
private void createNotification()
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this,0, notificationIntent, 0);
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("Service")
.setContentText("Coordinates Location Running")
.setContentIntent(pendingIntent)
.build();
startForeground(1, notification);
private void getCoordinates(Location location)
this.latitude = String.valueOf(location.getLatitude());
this.longitude = String.valueOf(location.getLongitude());
private void insertCoordinates(String latitude, String longitude)
boolean inserted = myDb.insertData(latitude, longitude); //Insert coordinates
//Check if insertion is completed
if(inserted)
Toast.makeText(LocationService.this, "Coordinates Inserted", Toast.LENGTH_SHORT).show();
else
Toast.makeText(LocationService.this, "Coordinates Not Inserted", Toast.LENGTH_SHORT).show();
private void sendDataToMainActivity(String latitude, String longitude)
Intent i = new Intent("location_update");
i.putExtra("latitude", latitude);
i.putExtra("longitude",longitude);
sendBroadcast(i);
@Nullable
@Override
public IBinder onBind(Intent intent)
return null;
【问题讨论】:
【参考方案1】:使用 Fused Location Api 请求位置更新,这将在指定的重复间隔(给定 5 分钟)内触发待处理的意图(假设启动一个意图服务)。因此 Fused Location Api 每 5 分钟读取一次位置并发送它到意图服务,您可以在其中进行处理。
详情请参考this。
【讨论】:
【参考方案2】:您可以使用警报管理器设置准确的警报,在警报的接收功能中启动服务运行前台服务 5 分钟,然后再设置下一个警报
【讨论】:
【参考方案3】:由于电源管理限制,“Fused Location Api”可能无法在后台运行。 您应该使用警报管理器,但在最新的 android 版本中有一些 limitations。更多关于打瞌睡here
AlarmManager alarm =
(AlarmManager)getSystemService(Context.ALARM_SERVICE);
if (alarm == null) return; // for instant apps
Intent intent = new Intent(this, MyBroadcastReceiver.class)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
alarm.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, triggerInMillis,
PendingIntent.getBroadcast(this, intent, PendingIntent.FLAG_UPDATE_CURRENT));
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
AlarmManager.AlarmClockInfo ac=
new AlarmManager.AlarmClockInfo(triggerInMillis, null);
alarm.setAlarmClock(ac, PendingIntent.getBroadcast(this, intent, PendingIntent.FLAG_UPDATE_CURRENT));
else
alarm.setExact(AlarmManager.RTC_WAKEUP, triggerInMillis,
PendingIntent.getBroadcast(this, intent, PendingIntent.FLAG_UPDATE_CURRENT));
【讨论】:
上下文指的是什么?当我输入AlarmManager alarm = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
时出现错误,但是当我将其更改为 AlarmManager alarm = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
时它可以工作。我不确定在上下文中放置什么变量。请注意,我没有BroadcastReceiver
课程,我只有Service Class
我在上面的问题中包含。
context 表示 Context 类的任何实例(Activity、Service、Application - 它们都扩展了 Context)。您必须将您的 MyBroadcastReceiver 声明为单独的文件公共类 MyBroadcastReceiver 扩展 BaseBroadcastReceiver 并添加到 AndroidManifest MyBroadcastReceiver
将在方法onReceive
中启动您的服务
我创建了一个MyBroadcastReceiver
类并在onReceive
方法上写了这个Intent serviceIntent = new Intent(context, LocationService.class); ContextCompat.startForegroundService(context, serviceIntent);
所以我得到了AlarmManager
的工作。我想要的是在我将坐标插入我的SQLite
数据库后销毁Service
。目前该服务无限期运行。所以基本上我希望我的AlarmManager
触发我的Service
10 秒来完成所有任务,销毁它,然后在 5 分钟内再次调用它。以上是关于如何每 5 分钟运行 10 秒的前台服务?的主要内容,如果未能解决你的问题,请参考以下文章
在前台服务中运行的 ScheduledThreadPoolExecutor 的 poolsize
应用程序进入前台后停止调用 setKeepAliveTimeout 处理程序?