// 每5秒定位一次
mLocationOption.setInterval(5 * 1000);
// 地址信息
mLocationOption.setNeedAddress(true);
mLocationClient.setLocationOption(mLocationOption);
mLocationClient.setLocationListener(locationListener);
mLocationClient.startLocation();
}
/**
- 停止定位
*/
void stopLocation() {
if (null != mLocationClient) {
mLocationClient.stopLocation();
}
}
AMapLocationListener locationListener = new AMapLocationListener() {
@Override
public void onLocationChanged(AMapLocation aMapLocation) {
//发送结果的通知
sendLocationBroadcast(aMapLocation);
if (!mIsWifiCloseable) {
return;
}
if (aMapLocation.getErrorCode() == AMapLocation.LOCATION_SUCCESS) {
mWifiAutoCloseDelegate.onLocateSuccess(getApplicationContext(), PowerManagerUtil.getInstance().isScreenOn(getApplicationContext()), NetUtil.getInstance().isMobileAva(getApplicationContext()));
} else {
mWifiAutoCloseDelegate.onLocateFail(getApplicationContext() , aMapLocation.getErrorCode() , PowerManagerUtil.getInstance().isScreenOn(getApplicationContext()), NetUtil.getInstance().isWifiCon(getApplicationContext()));
}
}
private void sendLocationBroadcast(AMapLocation aMapLocation) {
if (null != aMapLocation) {
Intent mIntent = new Intent(LocationChangBroadcastReceiver.RECEIVER_ACTION);
mIntent.putExtra(LocationChangBroadcastReceiver.RECEIVER_DATA, aMapLocation);
sendBroadcast(mIntent);
ToastUtils.show(“获取到定位信息”);
String string = System.currentTimeMillis() + “,”+aMapLocation.getLatitude() + “,” + aMapLocation.getLongitude();
Utils.saveFile(string, “backlocation.txt”, true);
}
}
};
}
定位服务的基类
/**
-
利用双service进行notification绑定,进而将Service的OOM_ADJ提高到1
-
同时利用LocationHelperService充当守护进程,在NotificationService被关闭后,重启他。
-
如果LocationHelperService被停止,NotificationService不负责唤醒
*/
public class NotificationService extends Service {
/**
- startForeground的 noti_id
*/
private static int NOTI_ID = 123321;
private Utils.CloseServiceReceiver mCloseReceiver;
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(“background location”, “远程服务调用成功”);
mCloseReceiver = new Utils.CloseServiceReceiver(this);
registerReceiver(mCloseReceiver, Utils.getCloseServiceFilter());
return START_STICKY;
}
@Override
public void onDestroy() {
if (mCloseReceiver != null) {
unregisterReceiver(mCloseReceiver);
mCloseReceiver = null;
}
super.onDestroy();
}
private final String mHelperServiceName = “com.hdsx.background.locationservice.LocationHelperService”;
/**
- 触发利用notification增加进程优先级
*/
protected void applyNotiKeepMech() {
startForeground(NOTI_ID, Utils.buildNotification(getBaseContext()));
startBindHelperService();
}
public void unApplyNotiKeepMech() {
stopForeground(true);
}
public Binder mBinder;
public class LocationServiceBinder extends ILocationServiceAIDL.Stub {
@Override
public void onFinishBind(){
}
}
private ILocationHelperServiceAIDL mHelperAIDL;
private void startBindHelperService() {
connection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
//doing nothing
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
ILocationHelperServiceAIDL l = ILocationHelperServiceAIDL.Stub.asInterface(service);
mHelperAIDL = l;
try {
l.onFinishBind(NOTI_ID);
} catch (RemoteException e) {
e.printStackTrace();
}
}
};
Intent intent = new Intent();
intent.setAction(mHelperServiceName);
bindService(Utils.getExplicitIntent(getApplicationContext(), intent), connection, Service.BIND_AUTO_CREATE);
}
private ServiceConnection connection;
@Nullable
@Override
public IBinder onBind(Intent intent) {
if (mBinder == null) {
mBinder = new LocationServiceBinder();
}
return mBinder;
}
}
另外一个服务:
public class LocationHelperService extends Service {
private Utils.CloseServiceReceiver mCloseReceiver;
@Override
public void onCreate() {
super.onCreate();
startBind();
mCloseReceiver = new Utils.CloseServiceReceiver(this);
registerReceiver(mCloseReceiver, Utils.getCloseServiceFilter());
}
@Override
public void onDestroy() {
if (mInnerConnection != null) {
unbindService(mInnerConnection);
mInnerConnection = null;
}
if (mCloseReceiver != null) {
unregisterReceiver(mCloseReceiver);
mCloseReceiver = null;
}
super.onDestroy();
}
private ServiceConnection mInnerConnection;
private void startBind() {
final String locationServiceName = “com.hdsx.background.locationservice.LocationService”;
mInnerConnection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
Intent intent = new Intent();
intent.setAction(locationServiceName);
startService(Utils.getExplicitIntent(getApplicationContext(), intent));
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
ILocationServiceAIDL l = ILocationServiceAIDL.Stub.asInterface(service);
try {
l.onFinishBind();
} catch (RemoteException e) {
e.printStackTrace();
}
}
};
Intent intent = new Intent();
intent.setAction(locationServiceName);
bindService(Utils.getExplicitIntent(getApplicationContext(), intent), mInnerConnection, Service.BIND_AUTO_CREATE);
}
private HelperBinder mBinder;
private class HelperBinder extends ILocationHelperServiceAIDL.Stub {
@Override
public void onFinishBind(int notiId) throws RemoteException {
startForeground(notiId, Utils.buildNotification(LocationHelperService.this.getApplicationContext()));
stopForeground(true);
}
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
if (mBinder == null) {
mBinder = new HelperBinder();
}
return mBinder;
}
}
双服务进行捆绑, 之前测试的过程中,发现这个powermanager配合服务他是可实现部分手机的,这边也做一个power的封装。
/**
- 获得PARTIAL_WAKE_LOCK , 保证在息屏状体下,CPU可以正常运行
*/
public class PowerManagerUtil {
private static class Holder {
public static PowerManagerUtil instance = new PowerManagerUtil();
}
private PowerManager pm = null;
private PowerManager.WakeLock pmLock = null;
/**
- 上次唤醒屏幕的触发时间
*/
private long mLastWakupTime = System.currentTimeMillis();
/**
- 最小的唤醒时间间隔,防止频繁唤醒。默认5分钟
*/
private long mMinWakupInterval = 10 * 1000;
private InnerThreadFactory mInnerThreadFactory = null;
public static PowerManagerUtil getInstance() {
return Holder.instance;
}
/**
-
判断屏幕是否处于点亮状态
-
@param context
*/
public boolean isScreenOn(final Context context) {
try {
Method isScreenMethod = PowerManager.class.getMethod(“isScreenOn”,
new Class[]{});
if (pm == null) {
pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
}
boolean screenState = (Boolean) isScreenMethod.invoke(pm);
return screenState;
} catch (Exception e) {
return true;
}
}
/**
- 唤醒屏幕
*/
public void wakeUpScreen(final Context context) {
try {
acquirePowerLock(context, PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.SCREEN_DIM_WAKE_LOCK);
String string = System.currentTimeMillis() +“唤醒”;
Utils.saveFile(string, “huanxinglocation.txt”, true);
} catch (Exception e) {
throw e;
}
}
/**
-
根据levelAndFlags,获得PowerManager的WaveLock
-
利用worker thread去获得锁,以免阻塞主线程
-
@param context
-
@param levelAndFlags
*/
private void acquirePowerLock(final Context context, final int levelAndFlags) {
if (context == null) {
throw new NullPointerException(“when invoke aquirePowerLock , context is null which is unacceptable”);
}
long currentMills = System.currentTimeMillis();
if (currentMills - mLastWakupTime < mMinWakupInterval) {
return;
}
mLastWakupTime = currentMills;
if (mInnerThreadFactory == null) {
mInnerThreadFactory = new InnerThreadFactory();
}
mInnerThreadFactory.newThread(new Runnable() {
@Override
public void run() {
if (pm == null) {
pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
}
if (pmLock != null) {
// release
pmLock.release();
pmLock = null;
}
pmLock = pm.newWakeLock(levelAndFlags, “MyTag”);
pmLock.acquire();
pmLock.release();
}
}).start();
}
private class InnerThreadFactory implements ThreadFactory {
@Override
public Thread newThread(Runnable runnable) {
return new Thread(runnable);
}
}
}
整体的逻辑呢就是说, 启动LocationService开启定位,定位成功后在手机添加一个前台的通知,让通知的优先级尽可能的提高。在锁屏后,powermanager判断获取如果定位失败唤醒服务。
public void onLocateFail(Context context, int errorCode, boolean isScreenOn, boolean isWifiable) {
//如果屏幕点亮情况下,因为断网失败,则表示不是屏幕点亮造成的断网失败,并修改参照值
if (isScreenOn && errorCode == AMapLocation.ERROR_CODE_FAILURE_CONNECTION && !isWifiable) {
LocationStatusManager.getInstance().resetToInit(context);
return;
}
if (!LocationStatusManager.getInstance().isFailOnScreenOff(context, errorCode, isScreenOn, isWifiable)) {
return;
}
PowerManagerUtil.getInstance().wakeUpScreen(context);
}
代码有点多,就不一一介绍了,下面把我包含的工具类都发出来。
- LocationStatusManager
/**
-
在定位失败的情况下,用于判断当前定位错误是否是由于息屏导致的网络关闭引起的。
-
判断逻辑仅限于处理设备仅有wifi信号的情况下
*/
public class LocationStatusManager {
/**
- 上一次的定位是否成功
*/
private boolean mPriorSuccLocated = false;
/**
- 屏幕亮时可以定位
*/
private boolean mPirorLocatableOnScreen = false;
static class Holder {
public static LocationStatusManager instance = new LocationStatusManager();
}
public static LocationStatusManager getInstance() {
return Holder.instance;
}
/**
-
由于仅仅处理只有wifi连接的情况下,如果用户手机网络可连接,那么忽略。
-
定位成功时,重置为定位成功的状态
-
@param isScreenOn 当前屏幕是否为点亮状态
-
@param isMobileable 是否有手机信号
*/
public void onLocationSuccess(Context context, boolean isScreenOn, boolean isMobileable) {
if (isMobileable) {
return;
}
mPriorSuccLocated = true;
if (isScreenOn) {
mPirorLocatableOnScreen = true;
saveStateInner(context, true);
}
}
/**
-
reset到默认状态
-
@param context
*/
public void resetToInit(Context context) {
this.mPirorLocatableOnScreen = false;
this.mPriorSuccLocated = false;
saveStateInner(context, false);
}
/**
- 由preference初始化。特别是在定位服务重启的时候会进行初始化
*/
public void initStateFromPreference(Context context) {
if (!isLocableOnScreenOn(context)) {
return;
}
this.mPriorSuccLocated = true;
this.mPirorLocatableOnScreen = true;
}
/**
-
判断是否由屏幕关闭导致的定位失败。
-
只有在 网络可访问&&errorCode==4&&(priorLocated&&locatableOnScreen) && !isScreenOn 才认为是有息屏引起的定位失败
-
如果判断条件较为严格,请按需要适当修改
-
@param errorCode 定位错误码, 0=成功, 4=因为网络原因造成的失败
-
@param isScreenOn 当前屏幕是否为点亮状态
*/
public boolean isFailOnScreenOff(Context context, int errorCode, boolean isScreenOn, boolean isWifiable) {
return !isWifiable && errorCode == AMapLocation.ERROR_CODE_FAILURE_CONNECTION && (mPriorSuccLocated && mPirorLocatableOnScreen) && !isScreenOn;
}
/**
- 是否存在屏幕亮而且可以定位的情况的key
*/
private String IS_LOCABLE_KEY = “is_locable_key”;
/**
- IS_LOCABLE_KEY 的过期时间
*/
private String LOCALBLE_KEY_EXPIRE_TIME_KEY = “localble_key_expire_time_key”;
/**
- 过期时间为10分钟
*/
private static final long MINIMAL_EXPIRE_TIME = 30 * 60 * 1000;
private static final String PREFER_NAME = LocationStatusManager.class.getSimpleName();
private static final long DEF_PRIOR_TIME_VAL = -1;
/**
-
如果isLocable,则存入正确的过期时间,否则存默认值
-
@param context
-
@param isLocable
*/
public void saveStateInner(Context context, boolean isLocable) {
SharedPreferences sharedPreferences = context.getSharedPreferences(PREFER_NAME, MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putBoolean(IS_LOCABLE_KEY, isLocable);
editor.putLong(LOCALBLE_KEY_EXPIRE_TIME_KEY, isLocable ? System.currentTimeMillis() : DEF_PRIOR_TIME_VAL);
editor.commit();
}
/**
- 从preference读取,判断是否存在网络状况ok,而且亮屏情况下,可以定位的情况
*/
public boolean isLocableOnScreenOn(Context context) {
SharedPreferences sharedPreferences = context.getSharedPreferences(PREFER_NAME, MODE_PRIVATE);
boolean res = sharedPreferences.getBoolean(IS_LOCABLE_KEY, false);
long priorTime = sharedPreferences.getLong(LOCALBLE_KEY_EXPIRE_TIME_KEY, DEF_PRIOR_TIME_VAL);
if (System.currentTimeMillis() - priorTime > MINIMAL_EXPIRE_TIME) {
saveStateInner(context, false);
return false;
}
return res;
}
}
- LocationChangBroadcastReceiver
做最后定位的结果,保存到数据库里
public class LocationChangBroadcastReceiver extends BroadcastReceiver {
public static final String RECEIVER_ACTION = “location_in_background”;
public static final String RECEIVER_DATA = “location_data”;
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(RECEIVER_ACTION)) {
AMapLocation location = (AMapLocation) intent.getParcelableExtra(RECEIVER_DATA);
if (null != location) {
String string = System.currentTimeMillis() + “,”+location.getLatitude() + “,” + location.getLongitude();
Utils.saveFile(string, “broadcastlocation.txt”, true);
Log.v(“定位数据”, “经度:” + location.getLongitude() + " 纬度:" + location.getLatitude());
SimpleDateFormat sdf = new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss”);
java.util.Date date = new Date(location.getTime());
String tracktime = sdf.format(date);
Map map = new HashMap();
String userid = SpUtils.getString(USER_ID);
map.put(“userid”, userid);
double[] loc = CoordinateTransformUtil.gcj02towgs84(location.getLongitude(),location.getLatitude());
map.put(“tracktime”, tracktime);
map.put(“latitude”, loc[1]);
map.put(“lontitude”, loc[0]);
Frame.getInstance().getDao().insert(“trackbean.insert_track”, map);
}
}
}
}
- NetUtil
用于判断设备是否可以访问网络。
public class NetUtil {
private static class Holder {
public static NetUtil instance = new NetUtil();
}
public static NetUtil getInstance() {
return Holder.instance;
}
/**
-
是否手机信号可连接
-
@param context
-
@return
*/
public boolean isMobileAva(Context context) {
boolean hasMobileCon = false;
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(context.CONNECTIVITY_SERVICE);
NetworkInfo[] netInfos = cm.getAllNetworkInfo();
for (NetworkInfo net : netInfos) {
String type = net.getTypeName();
if (type.equalsIgnoreCase(“MOBILE”)) {
if (net.isConnected()) {
hasMobileCon = true;
}
}
}
return hasMobileCon;
}
/**
-
是否wifi可连接
-
@param context
-
@return
*/
public boolean isWifiCon(Context context) {
boolean hasWifoCon = false;
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(context.CONNECTIVITY_SERVICE);
NetworkInfo[] netInfos = cm.getAllNetworkInfo();
for (NetworkInfo net : netInfos) {
String type = net.getTypeName();
if (type.equalsIgnoreCase(“WIFI”)) {
if (net.isConnected()) {
hasWifoCon = true;
}
}
}
return hasWifoCon;
}
}
- Utils
辅助工具类
public class Utils {
private static String CLOSE_BRODECAST_INTENT_ACTION_NAME=“com.hdsx.background.locationservice.CloseService”;
/**
- 开始定位
*/
public final static int MSG_LOCATION_START = 0;
/**
- 定位完成
*/
public final static int MSG_LOCATION_FINISH = 1;
/**
- 停止定位
*/
public final static int MSG_LOCATION_STOP = 2;
public final static String KEY_URL = “URL”;
public final static String URL_H5LOCATION = “file:///android_asset/location.html”;
private static SimpleDateFormat sdf = null;
private static NotificationManager mNotificationManager;
private final static String PRIMARY_CHANNEL = “default”;
/**
-
根据定位结果返回定位信息的字符串
-
@param location
-
@return
*/
public synchronized static String getLocationStr(AMapLocation location) {
if (null == location) {
return null;
}
StringBuffer sb = new StringBuffer();
//errCode等于0代表定位成功,其他的为定位失败,具体的可以参照官网定位错误码说明
if (location.getErrorCode() == 0) {
sb.append(“定位成功” + “\n”);
sb.append("定位类型: " + location.getLocationType() + “\n”);
sb.append("经 度 : " + location.getLongitude() + “\n”);
sb.append("纬 度 : " + location.getLatitude() + “\n”);
sb.append("精 度 : " + location.getAccuracy() + “米” + “\n”);
sb.append("提供者 : " + location.getProvider() + “\n”);
sb.append("海 拔 : " + location.getAltitude() + “米” + “\n”);
sb.append("速 度 : " + location.getSpeed() + “米/秒” + “\n”);
sb.append("角 度 : " + location.getBearing() + “\n”);
if (location.getProvider().equalsIgnoreCase(
android.location.LocationManager.GPS_PROVIDER)) {
// 以下信息只有提供者是GPS时才会有
// 获取当前提供定位服务的卫星个数
sb.append("星 数 : "
- location.getSatellites() + “\n”);
}
//逆地理信息
sb.append("国 家 : " + location.getCountry() + “\n”);
sb.append("省 : " + location.getProvince() + “\n”);
sb.append("市 : " + location.getCity() + “\n”);
sb.append("城市编码 : " + location.getCityCode() + “\n”);
sb.append("区 : " + location.getDistrict() + “\n”);
sb.append("区域 码 : " + location.getAdCode() + “\n”);
sb.append("地 址 : " + location.getAddress() + “\n”);
sb.append("兴趣点 : " + location.getPoiName() + “\n”);
//定位完成的时间
sb.append("定位时间: " + formatUTC(location.getTime(), “yyyy-MM-dd HH:mm:ss”) + “\n”);
} else {
//定位失败
sb.append(“定位失败” + “\n”);
sb.append(“错误码:” + location.getErrorCode() + “\n”);
sb.append(“错误信息:” + location.getErrorInfo() + “\n”);
sb.append(“错误描述:” + location.getLocationDetail() + “\n”);
}
//定位之后的回调时间
sb.append("回调时间: " + formatUTC(System.currentTimeMillis(), “yyyy-MM-dd HH:mm:ss”) + “\n”);
return sb.toString();
}
public synchronized static String formatUTC(long l, String strPattern) {
if (TextUtils.isEmpty(strPattern)) {
strPattern = “yyyy-MM-dd HH:mm:ss”;
}
if (sdf == null) {
try {
sdf = new SimpleDateFormat(strPattern, Locale.CHINA);
} catch (Throwable e) {
}
} else {
sdf.applyPattern(strPattern);
}
return sdf == null ? “NULL” : sdf.format(l);
}
public static Intent getExplicitIntent(Context context, Intent implicitIntent) {
if (context.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.LOLLIPOP) {
return implicitIntent;
}
// Retrieve all services that can match the given intent
PackageManager pm = context.getPackageManager();
List resolveInfo = pm.queryIntentServices(implicitIntent, 0);
// Make sure only one match was found
if (resolveInfo == null || resolveInfo.size() != 1) {
return null;
}
// Get component info and create ComponentName
ResolveInfo serviceInfo = resolveInfo.get(0);
String packageName = serviceInfo.serviceInfo.packageName;
String className = serviceInfo.serviceInfo.name;
ComponentName component = new ComponentName(packageName, className);
// Create a new intent. Use the old one for extras and such reuse
Intent explicitIntent = new Intent(implicitIntent);
// Set the component to be explicit
explicitIntent.setComponent(component);
return explicitIntent;
}
public static void saveFile(String toSaveString, String fileName, boolean append) {
try {
String sdCardRoot = Environment.getExternalStorageDirectory()
.getAbsolutePath();
File saveFile = new File(sdCardRoot + “/” + fileName);
if (!saveFile.exists()) {
File dir = new File(saveFile.getParent());
dir.mkdirs();
saveFile.createNewFile();
}
FileOutputStream outStream = new FileOutputStream(saveFile, append);
outStream.write(toSaveString.getBytes());
outStream.write(“\r\n”.getBytes());
outStream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public static Notification buildNotification(Context context) {
Notification notification = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(PRIMARY_CHANNEL,
context.getString(R.string.default_channel), NotificationManager.IMPORTANCE_DEFAULT);
channel.setLightColor(Color.GREEN);
channel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
getNotificationManager(context).createNotificationChannel(channel);
Notification.Builder builder = new Notification.Builder(context,
PRIMARY_CHANNEL)
.setContentText(“水源地轨迹记录中…”)
.setSmallIcon(R.drawable.ic_launcher)
.setAutoCancel(true);
notification = builder.build();
} else {
Notification.Builder builder = new Notification.Builder(context);
builder.setSmallIcon(R.drawable.ic_launcher);
builder.setContentText(“水源地轨迹记录中…” )
.setWhen(System.currentTimeMillis());
notification = builder.build();
}
return notification;
}
private static NotificationManager getNotificationManager(Context context) {
if (mNotificationManager == null) {
mNotificationManager = (NotificationManager)context.getSystemService(
Context.NOTIFICATION_SERVICE);
}
return mNotificationManager;
}
public static void startWifi(Context context) {
WifiManager wm = (WifiManager) context
.getSystemService(Context.WIFI_SERVICE);
wm.setWifiEnabled(true);
wm.reconnect();
}
public static boolean isWifiEnabled(Context context) {
WifiManager wm = (WifiManager) context
.getSystemService(Context.WIFI_SERVICE);
return wm.isWifiEnabled();
}
public static String getManufacture(Context context) {
return Build.MANUFACTURER;
}
public static Intent getCloseBrodecastIntent() {
return new Intent(CLOSE_BRODECAST_INTENT_ACTION_NAME);
}
public static IntentFilter getCloseServiceFilter() {
return new IntentFilter(CLOSE_BRODECAST_INTENT_ACTION_NAME);
}
public static class CloseServiceReceiver extends BroadcastReceiver {
Service mService;
public CloseServiceReceiver(Service service) {
this.mService = service;
}
@Override
public void onReceive(Context context, Intent intent) {
if (mService == null) {
return;
}
mService.onDestroy();
}
}
}
- WifiAutoCloseDelegate
接口实现类,回调一下结果
public class WifiAutoCloseDelegate implements IWifiAutoCloseDelegate {
/**
-
请根据后台数据自行添加。此处只针对小米手机
-
@param context
-
@return
*/
@Override
public boolean isUseful(Context context) {
String manName = Utils.getManufacture(context);
Pattern pattern = Pattern.compile(“xiaomi”, Pattern.CASE_INSENSITIVE);
Matcher m = pattern.matcher(manName);
return m.find();
}
@Override
public void initOnServiceStarted(Context context) {
LocationStatusManager.getInstance().initStateFromPreference(context);
}
@Override
public void onLocateSuccess(Context context, boolean isScreenOn, boolean isMobileable) {
LocationStatusManager.getInstance().onLocationSuccess(context, isScreenOn, isMobileable);
}
@Override
public void onLocateFail(Context context, int errorCode, boolean isScreenOn, boolean isWifiable) {
//如果屏幕点亮情况下,因为断网失败,则表示不是屏幕点亮造成的断网失败,并修改参照值
if (isScreenOn && errorCode == AMapLocation.ERROR_CODE_FAILURE_CONNECTION && !isWifiable) {
LocationStatusManager.getInstance().resetToInit(context);
return;
}
if (!LocationStatusManager.getInstance().isFailOnScreenOff(context, errorCode, isScreenOn, isWifiable)) {
return;
}
PowerManagerUtil.getInstance().wakeUpScreen(context);
}
}
基本就这些, 代码比较多, 有兴趣的朋友可以自行阅读,注解基本都有介绍。记录一下此类问题。
更新:2019-01-03 附张效果图
yes.png
上述图片仅用设备GPS定位的。
demo链接如下:https://download.csdn.net/download/binbinxiaoz/10892551 https://download.csdn.net/download/binbinxiaoz/10890248
测试前,请检查手机 对app的电量管理权限以及限制后台运行权限及锁屏后针对app的权限。若无可手动更改请忽略。
测试时,请室外测试,室内gps信号差。若室内测试请切换别的定位模式,保证可以定位但不保证定位的精准度,本身流量等定位偏差就相当的大。
demo中只需关注养护巡查模块即可,别的模块练手加的,无关联。
android studio版本3.1.4
下载demo后,评个分谢谢。
小米9.0手机处理:禁止电池优化, 华为手机会因为耗电过强直接终止进程, 别的手机暂时还为测试。推荐接推送唤醒·
Intent intent = new Intent();
String packageName = getActivity().getPackageName();
PowerManager pm = (PowerManager) getActivity().getSystemService(Context.POWER_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (pm.isIgnoringBatteryOptimizations(packageName))
intent.setAction(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS);
else {
intent.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
intent.setData(Uri.parse(“package:” + packageName));
}
}
getActivity().startActivity(intent);
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)
总结
写到这里也结束了,在文章最后放上一个小小的福利,以下为小编自己在学习过程中整理出的一个关于Flutter的学习思路及方向,从事互联网开发,最主要的是要学好技术,而学习技术是一条慢长而艰苦的道路,不能靠一时激情,也不是熬几天几夜就能学好的,必须养成平时努力学习的习惯,更加需要准确的学习方向达到有效的学习效果。
由于内容较多就只放上一个大概的大纲,需要更及详细的学习思维导图的
还有高级UI、性能优化、架构师课程、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter全方面的Android进阶实践技术资料,并且还有技术大牛一起讨论交流解决问题。
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
谢。
小米9.0手机处理:禁止电池优化, 华为手机会因为耗电过强直接终止进程, 别的手机暂时还为测试。推荐接推送唤醒·
Intent intent = new Intent();
String packageName = getActivity().getPackageName();
PowerManager pm = (PowerManager) getActivity().getSystemService(Context.POWER_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (pm.isIgnoringBatteryOptimizations(packageName))
intent.setAction(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS);
else {
intent.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
intent.setData(Uri.parse(“package:” + packageName));
}
}
getActivity().startActivity(intent);
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-DkJxIX7e-1713770187078)]
[外链图片转存中…(img-Ycs2IDFy-1713770187079)]
[外链图片转存中…(img-yjT0DTbD-1713770187080)]
[外链图片转存中…(img-KKnZaTaW-1713770187081)]
[外链图片转存中…(img-VaZcV5pE-1713770187082)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)
[外链图片转存中…(img-xFrOFGmM-1713770187083)]
总结
写到这里也结束了,在文章最后放上一个小小的福利,以下为小编自己在学习过程中整理出的一个关于Flutter的学习思路及方向,从事互联网开发,最主要的是要学好技术,而学习技术是一条慢长而艰苦的道路,不能靠一时激情,也不是熬几天几夜就能学好的,必须养成平时努力学习的习惯,更加需要准确的学习方向达到有效的学习效果。
由于内容较多就只放上一个大概的大纲,需要更及详细的学习思维导图的
还有高级UI、性能优化、架构师课程、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter全方面的Android进阶实践技术资料,并且还有技术大牛一起讨论交流解决问题。
[外链图片转存中…(img-MOP1070i-1713770187084)]
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!