从Android 8.0开始系统为实现降低功耗,对后台应用获取用户位置信息频率进行了限制,每小时只允许更新几次位置信息,详细信息请参考官方说明。按照官方指引,如果要提高位置更新频率,需要后台应用提供一个前台服务通知告知。
所以原来的单单使用locationManager获得当前位置在后台情况下无法使用了。于是打算使用一个前台服务,当app在后台时也能获得当前位置。
查了几篇博客说前台服务需要在service的onStartCommand方法中调用startForeground(int, Notification)才能开启前台服务。
但是onStartCommand需要走startservice()的生命周期才会调用。
我改用了bindservice() 正好需要activity和service交互,当然两个启动方法混用也可以。但是没有必要。
我需要的只是和控件绑定的service并且不想处理服务的结束操作。
1、activity / fragment调用 绑定服务
Intent serviceIntent = new Intent(this, ForegroundLocationService.class); bindService(serviceIntent, conn, Service.BIND_AUTO_CREATE); // 绑定服务时要求传入一个ServiceConnection实现类的对象 // 绑定服务时,会触发服务的onBind方法,此方法会返回一个Ibinder的对象给activity / fragment的onServiceConnected(),通过这个对象可以访问服务中的方法 ServiceConnection conn = new ServiceConnection() { @Override public void onServiceDisconnected(ComponentName name) { } @Override public void onServiceConnected(ComponentName name, IBinder service) { } };
2、我在onBind()方法中调用了startForeground(int, Notification)
第一个参数是一个不为0的正整数,代表通知的id,第二个参数代表需要显示的通知。
适配8.0的通知构建需要适配,不然会导致你的通知无法显示(第一次调用的时候还以为是一加拦截了通知)
3、那么这时候应该已经实现了前台服务,需要把服务获得的位置信息传递给activity。(直接调用locationmanager就可以获得,这里把位置实现隐去)
public class MyBinder extends Binder { public ForegroundLocationService getService(){ return ForegroundLocationService.this; } } //通过binder实现调用者client与Service之间的通信 private MyBinder binder = new MyBinder(); //通过service的onBind()方法返回我们实例化的MyBinder对象,该对象可以获的当前的Service @Override public IBinder onBind(Intent arg0) { NotificationUtils notificationUtils = new NotificationUtils(this); startForeground(111, notificationUtils.getNotification("Notice", "Continuous positioning",null)); return binder; }
4、然后需要进行控件和服务的交互,这里就分成了三种方法
ServiceConnection conn = new ServiceConnection() { @Override public void onServiceDisconnected(ComponentName name) { } @Override public void onServiceConnected(ComponentName name, IBinder service) { //通过这个方法可以得到service的实例,通过设置回调可以持续更新 ForegroundLocationService foregroundLocationService = ((ForegroundLocationService.MyBinder) service).getService(); foregroundLocationService.setLocationCallback(new ForegroundLocationService.LocationCallback() { @Override public void onLocation(Location location) { } }); } };
在service中编写接口,并在获得位置的回调方法中调用。
public interface LocationCallback { /** * 当前位置 */ void onLocation(Location location); } private LocationCallback mLocationCallback; private class LocationListener implements android.location.LocationListener { public LocationListener(String provider) { Logger.e(TAG, "LocationListener " + provider); } @Override public void onLocationChanged(Location location) { Log.i("location", "onLocationChanged: " + "当前坐标:" + location.getLatitude() + " : " + location.getLongitude()); if(mLocationCallback!=null){ mLocationCallback.onLocation(location); } } }
Service向Activity发送消息,可以使用广播,当然Activity要注册相应的接收器。比如Service要向多个Activity发送同样的消息的话,用这种方法就更好,这里就省略不写了。具体可以参考下面的文章。
水物理模拟器手机版 安卓版v1.3.39
水物理模拟器是一款玩法非常多样的沙盒建造类手游,玩家可以在游
创造世界2 安卓版v2.1.0
创造世界2是一款非常有趣的模拟类游戏,玩家在游戏中可以控制自
时光杂货店0.1折 安卓版v1.9.1
时光杂货店折扣版是一款模拟经营类游戏,玩家们将在游戏中重回八
TRS12火车模拟器(内置模组) 安卓版v1.3.9
TRS12火车模拟器(内置模组)是一个非常有趣的火车模拟游戏
泽塔奥特曼升华器模拟器 最新版v2.3
泽塔奥特曼升华器模拟器是根据《泽塔奥特曼》电视剧出现的变身器