Android LocationManager 位置更新在设备没有互联网时不启动
Android LocationManager Location Updates not starting when device has no Internet
我正在使用完全离线且自上次更新至 Android 6.0.1
后未连接到 Internet 的设备
有一段时间这个应用程序运行得非常好,并且使用 Google Play Services FusedLocationApi 它会每秒更新一次并执行它应该执行的操作。然后在我对代码的其他部分进行了一些更改后它突然停止工作,我不知道为什么。我认为这可能是 Google Play 服务的问题,所以我按照 this guide.
中的说明使用 Android 的位置服务将其关闭
我删掉了应该与问题无关的代码。我可能不小心删掉了一些变量,但我在 Android Studio 中工作,那里没有任何缺失的变量,所以这可能不是问题所在。我正在使用 Butterknife,所以有一些注释。
这是 Logcat 从创建应用到使用开关打开和关闭位置请求的过程:
08-01 11:04:53.289 11532-11532/mil.navy.nrl.androidrobocontroller W/System: ClassLoader referenced unknown path: /data/app/mil.navy.nrl.androidrobocontroller-1/lib/arm
08-01 11:04:53.534 11532-11532/mil.navy.nrl.androidrobocontroller W/System: ClassLoader referenced unknown path: /data/app/mil.navy.nrl.androidrobocontroller-1/lib/arm
08-01 11:04:53.869 11532-11532/mil.navy.nrl.androidrobocontroller W/art: Before Android 4.1, method android.graphics.PorterDuffColorFilter android.support.graphics.drawable.VectorDrawableCompat.updateTintFilter(android.graphics.PorterDuffColorFilter, android.content.res.ColorStateList, android.graphics.PorterDuff$Mode) would have incorrectly overridden the package-private method in android.graphics.drawable.Drawable
08-01 11:04:54.057 11532-11574/mil.navy.nrl.androidrobocontroller D/OpenGLRenderer: Use EGL_SWAP_BEHAVIOR_PRESERVED: true
08-01 11:04:54.118 11532-11574/mil.navy.nrl.androidrobocontroller I/Adreno-EGL: <qeglDrvAPI_eglInitialize:379>: QUALCOMM Build: 10/21/15, 369a2ea, I96aee987eb
08-01 11:04:54.120 11532-11574/mil.navy.nrl.androidrobocontroller I/OpenGLRenderer: Initialized EGL, version 1.4
08-01 11:04:56.439 11532-11532/mil.navy.nrl.androidrobocontroller V/TrackActivity: Requested location
08-01 11:04:56.440 11532-11532/mil.navy.nrl.androidrobocontroller V/TrackActivity: Permission android.permission.ACCESS_FINE_LOCATION has been granted.
08-01 11:04:56.440 11532-11532/mil.navy.nrl.androidrobocontroller V/TrackActivity: Location updates requested
08-01 11:04:56.445 11532-11532/mil.navy.nrl.androidrobocontroller V/TrackActivity: Check checked and updated.
08-01 11:04:58.791 11532-11532/mil.navy.nrl.androidrobocontroller V/TrackActivity: Permission android.permission.ACCESS_FINE_LOCATION has been granted.
08-01 11:04:58.794 11532-11532/mil.navy.nrl.androidrobocontroller V/TrackActivity: Check unchecked and updated.
据此我知道正在调用 onCheckChanged() 并且它调用 startLocationUpdates() 非常好。它甚至访问了应该请求位置更新但似乎从不响应它们的代码。
这是所有代码:
生命周期方法
package com.example.app;
import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.SwitchCompat;
import android.util.Log;
import android.widget.EditText;
import android.widget.RelativeLayout;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnCheckedChanged;
public class TrackActivity extends AppCompatActivity implements LocationListener,
ActivityCompat.OnRequestPermissionsResultCallback {
private static final String LOG_TAG = "TrackActivity";
private static final boolean SHOW_VERBOSE = true;
private static final int REQUEST_FINE_LOCATION_UPDATE = 1;
private static final int REQUEST_END_LOCATION_UPDATES = 2;
protected LocationManager mLocationManager;
private Location mBestLocation;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_track);
// ButterKnife bind method. REQUIRED FOR ANNOTATIONS TO WORK.
ButterKnife.bind(this);
}
@Override
protected void onStart() {
mLocationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
super.onStart();
}
@Override
protected void onStop() {
// startLocationUpdates(); <--- Made a typo here
endLocationUpdates();
super.onStop();
}
onCheckedChanged
@OnCheckedChanged(R.id.track_send_location_switch)
void onCheckChanged(boolean checked) {
if (checked) {
// Unrelated code cut.
startLocationUpdates();
if (SHOW_VERBOSE) Log.v(LOG_TAG, "Check checked and updated.");
} else {
endLocationUpdates();
// Unrelated code cut
if (SHOW_VERBOSE) Log.v(LOG_TAG, "Check unchecked and updated.");
}
}
开始位置更新
protected void startLocationUpdates() {
if (SHOW_VERBOSE) Log.v(LOG_TAG, "Requested location");
if (checkRequestPermission(Manifest.permission.ACCESS_FINE_LOCATION, REQUEST_FINE_LOCATION_UPDATE)) {
// TODO: Add high accuracy 1 Hz Location Updates
if (SHOW_VERBOSE) Log.v(LOG_TAG, "Location updates requested");
mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, this);
}
}
endLocationUpdates
protected void endLocationUpdates() {
if (checkRequestPermission(
Manifest.permission.ACCESS_FINE_LOCATION, REQUEST_END_LOCATION_UPDATES)) {
mLocationManager.removeUpdates(this);
}
}
checkRequestPermission
protected boolean checkRequestPermission(String permission, int requestCode) {
int permissionCheck = ContextCompat.checkSelfPermission(this, permission);
if(permissionCheck == PackageManager.PERMISSION_GRANTED) {
if(SHOW_VERBOSE) Log.v(LOG_TAG, "Permission " + permission + " has been granted.");
return true;
} else {
ActivityCompat.requestPermissions(this,
new String[]{permission},
requestCode);
}
return false;
}
onRequestPermissionsResult
@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case REQUEST_FINE_LOCATION_ONCE:
if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED)
startLocationUpdates();
break;
case REQUEST_FINE_LOCATION_UPDATE:
if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED)
startLocationUpdates();
break;
case REQUEST_END_LOCATION_UPDATES:
if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED)
endLocationUpdates();
break;
}
}
onLocationChanged
@Override
public void onLocationChanged(Location location) {
if(SHOW_VERBOSE) Log.v(LOG_TAG, "Location request returned");
Location locationToUse;
if(isBetterLocation(location, mBestLocation)) {
locationToUse = location;
mBestLocation = location;
} else {
locationToUse = mBestLocation;
}
if(SHOW_VERBOSE) Log.v(LOG_TAG, "onLocationChanged()");
// Rest of app's code is ommited.
doThingWithLocation(locationToUse);
}
LocationListener 方法
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
@Override
public void onProviderEnabled(String provider) {
if(SHOW_VERBOSE) Log.v(LOG_TAG, "Provider enabled");
}
@Override
public void onProviderDisabled(String provider) {
if(SHOW_VERBOSE) Log.v(LOG_TAG, "Provider disabled");
}
位置策略指南中的方法
protected boolean isBetterLocation(Location location, Location currentBestLocation) {
if(currentBestLocation == null)
return true;
long timeDelta = location.getTime() - currentBestLocation.getTime();
boolean isSignificantlyNewer = timeDelta > 10000;
boolean isSignificantlyOlder = timeDelta < -10000;
boolean isNewer = timeDelta > 0;
if (isSignificantlyNewer) {
return true;
// If the new location is more than two minutes older, it must be worse
} else if (isSignificantlyOlder) {
return false;
}
// Check whether the new location fix is more or less accurate
int accuracyDelta = (int) (location.getAccuracy() - currentBestLocation.getAccuracy());
boolean isLessAccurate = accuracyDelta > 0;
boolean isMoreAccurate = accuracyDelta < 0;
boolean isSignificantlyLessAccurate = accuracyDelta > 200;
// Check if the old and new location are from the same provider
boolean isFromSameProvider = isSameProvider(location.getProvider(),
currentBestLocation.getProvider());
// Determine location quality using a combination of timeliness and accuracy
if (isMoreAccurate) {
return true;
} else if (isNewer && !isLessAccurate) {
return true;
} else if (isNewer && !isSignificantlyLessAccurate && isFromSameProvider) {
return true;
}
return false;
}
/** Checks whether two providers are the same */
private boolean isSameProvider(String provider1, String provider2) {
if (provider1 == null) {
return provider2 == null;
}
return provider1.equals(provider2);
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.app">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name="com.example.app.TrackActivity"
android:windowSoftInputMode="stateHidden">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<action android:name=".TrackActivity" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
非常感谢任何帮助!谢谢!
原来我没有很好的 GPS 信号,这就是导致我出现问题的原因。我以为我坐在 window 旁边没问题,但连接到 GPS 需要很长时间(@cYrixmorten 建议超过 15 分钟)。如果有足够的时间它会连接到 GPS,但我发现一旦我走到外面,它几乎会立即连接。
如果有人需要测试 GPS 服务,我使用了 this GPS 测试应用程序。
我正在使用完全离线且自上次更新至 Android 6.0.1
后未连接到 Internet 的设备有一段时间这个应用程序运行得非常好,并且使用 Google Play Services FusedLocationApi 它会每秒更新一次并执行它应该执行的操作。然后在我对代码的其他部分进行了一些更改后它突然停止工作,我不知道为什么。我认为这可能是 Google Play 服务的问题,所以我按照 this guide.
中的说明使用 Android 的位置服务将其关闭我删掉了应该与问题无关的代码。我可能不小心删掉了一些变量,但我在 Android Studio 中工作,那里没有任何缺失的变量,所以这可能不是问题所在。我正在使用 Butterknife,所以有一些注释。
这是 Logcat 从创建应用到使用开关打开和关闭位置请求的过程:
08-01 11:04:53.289 11532-11532/mil.navy.nrl.androidrobocontroller W/System: ClassLoader referenced unknown path: /data/app/mil.navy.nrl.androidrobocontroller-1/lib/arm
08-01 11:04:53.534 11532-11532/mil.navy.nrl.androidrobocontroller W/System: ClassLoader referenced unknown path: /data/app/mil.navy.nrl.androidrobocontroller-1/lib/arm
08-01 11:04:53.869 11532-11532/mil.navy.nrl.androidrobocontroller W/art: Before Android 4.1, method android.graphics.PorterDuffColorFilter android.support.graphics.drawable.VectorDrawableCompat.updateTintFilter(android.graphics.PorterDuffColorFilter, android.content.res.ColorStateList, android.graphics.PorterDuff$Mode) would have incorrectly overridden the package-private method in android.graphics.drawable.Drawable
08-01 11:04:54.057 11532-11574/mil.navy.nrl.androidrobocontroller D/OpenGLRenderer: Use EGL_SWAP_BEHAVIOR_PRESERVED: true
08-01 11:04:54.118 11532-11574/mil.navy.nrl.androidrobocontroller I/Adreno-EGL: <qeglDrvAPI_eglInitialize:379>: QUALCOMM Build: 10/21/15, 369a2ea, I96aee987eb
08-01 11:04:54.120 11532-11574/mil.navy.nrl.androidrobocontroller I/OpenGLRenderer: Initialized EGL, version 1.4
08-01 11:04:56.439 11532-11532/mil.navy.nrl.androidrobocontroller V/TrackActivity: Requested location
08-01 11:04:56.440 11532-11532/mil.navy.nrl.androidrobocontroller V/TrackActivity: Permission android.permission.ACCESS_FINE_LOCATION has been granted.
08-01 11:04:56.440 11532-11532/mil.navy.nrl.androidrobocontroller V/TrackActivity: Location updates requested
08-01 11:04:56.445 11532-11532/mil.navy.nrl.androidrobocontroller V/TrackActivity: Check checked and updated.
08-01 11:04:58.791 11532-11532/mil.navy.nrl.androidrobocontroller V/TrackActivity: Permission android.permission.ACCESS_FINE_LOCATION has been granted.
08-01 11:04:58.794 11532-11532/mil.navy.nrl.androidrobocontroller V/TrackActivity: Check unchecked and updated.
据此我知道正在调用 onCheckChanged() 并且它调用 startLocationUpdates() 非常好。它甚至访问了应该请求位置更新但似乎从不响应它们的代码。
这是所有代码:
生命周期方法
package com.example.app;
import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.SwitchCompat;
import android.util.Log;
import android.widget.EditText;
import android.widget.RelativeLayout;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnCheckedChanged;
public class TrackActivity extends AppCompatActivity implements LocationListener,
ActivityCompat.OnRequestPermissionsResultCallback {
private static final String LOG_TAG = "TrackActivity";
private static final boolean SHOW_VERBOSE = true;
private static final int REQUEST_FINE_LOCATION_UPDATE = 1;
private static final int REQUEST_END_LOCATION_UPDATES = 2;
protected LocationManager mLocationManager;
private Location mBestLocation;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_track);
// ButterKnife bind method. REQUIRED FOR ANNOTATIONS TO WORK.
ButterKnife.bind(this);
}
@Override
protected void onStart() {
mLocationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
super.onStart();
}
@Override
protected void onStop() {
// startLocationUpdates(); <--- Made a typo here
endLocationUpdates();
super.onStop();
}
onCheckedChanged
@OnCheckedChanged(R.id.track_send_location_switch)
void onCheckChanged(boolean checked) {
if (checked) {
// Unrelated code cut.
startLocationUpdates();
if (SHOW_VERBOSE) Log.v(LOG_TAG, "Check checked and updated.");
} else {
endLocationUpdates();
// Unrelated code cut
if (SHOW_VERBOSE) Log.v(LOG_TAG, "Check unchecked and updated.");
}
}
开始位置更新
protected void startLocationUpdates() {
if (SHOW_VERBOSE) Log.v(LOG_TAG, "Requested location");
if (checkRequestPermission(Manifest.permission.ACCESS_FINE_LOCATION, REQUEST_FINE_LOCATION_UPDATE)) {
// TODO: Add high accuracy 1 Hz Location Updates
if (SHOW_VERBOSE) Log.v(LOG_TAG, "Location updates requested");
mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, this);
}
}
endLocationUpdates
protected void endLocationUpdates() {
if (checkRequestPermission(
Manifest.permission.ACCESS_FINE_LOCATION, REQUEST_END_LOCATION_UPDATES)) {
mLocationManager.removeUpdates(this);
}
}
checkRequestPermission
protected boolean checkRequestPermission(String permission, int requestCode) {
int permissionCheck = ContextCompat.checkSelfPermission(this, permission);
if(permissionCheck == PackageManager.PERMISSION_GRANTED) {
if(SHOW_VERBOSE) Log.v(LOG_TAG, "Permission " + permission + " has been granted.");
return true;
} else {
ActivityCompat.requestPermissions(this,
new String[]{permission},
requestCode);
}
return false;
}
onRequestPermissionsResult
@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case REQUEST_FINE_LOCATION_ONCE:
if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED)
startLocationUpdates();
break;
case REQUEST_FINE_LOCATION_UPDATE:
if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED)
startLocationUpdates();
break;
case REQUEST_END_LOCATION_UPDATES:
if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED)
endLocationUpdates();
break;
}
}
onLocationChanged
@Override
public void onLocationChanged(Location location) {
if(SHOW_VERBOSE) Log.v(LOG_TAG, "Location request returned");
Location locationToUse;
if(isBetterLocation(location, mBestLocation)) {
locationToUse = location;
mBestLocation = location;
} else {
locationToUse = mBestLocation;
}
if(SHOW_VERBOSE) Log.v(LOG_TAG, "onLocationChanged()");
// Rest of app's code is ommited.
doThingWithLocation(locationToUse);
}
LocationListener 方法
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
@Override
public void onProviderEnabled(String provider) {
if(SHOW_VERBOSE) Log.v(LOG_TAG, "Provider enabled");
}
@Override
public void onProviderDisabled(String provider) {
if(SHOW_VERBOSE) Log.v(LOG_TAG, "Provider disabled");
}
位置策略指南中的方法
protected boolean isBetterLocation(Location location, Location currentBestLocation) {
if(currentBestLocation == null)
return true;
long timeDelta = location.getTime() - currentBestLocation.getTime();
boolean isSignificantlyNewer = timeDelta > 10000;
boolean isSignificantlyOlder = timeDelta < -10000;
boolean isNewer = timeDelta > 0;
if (isSignificantlyNewer) {
return true;
// If the new location is more than two minutes older, it must be worse
} else if (isSignificantlyOlder) {
return false;
}
// Check whether the new location fix is more or less accurate
int accuracyDelta = (int) (location.getAccuracy() - currentBestLocation.getAccuracy());
boolean isLessAccurate = accuracyDelta > 0;
boolean isMoreAccurate = accuracyDelta < 0;
boolean isSignificantlyLessAccurate = accuracyDelta > 200;
// Check if the old and new location are from the same provider
boolean isFromSameProvider = isSameProvider(location.getProvider(),
currentBestLocation.getProvider());
// Determine location quality using a combination of timeliness and accuracy
if (isMoreAccurate) {
return true;
} else if (isNewer && !isLessAccurate) {
return true;
} else if (isNewer && !isSignificantlyLessAccurate && isFromSameProvider) {
return true;
}
return false;
}
/** Checks whether two providers are the same */
private boolean isSameProvider(String provider1, String provider2) {
if (provider1 == null) {
return provider2 == null;
}
return provider1.equals(provider2);
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.app">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name="com.example.app.TrackActivity"
android:windowSoftInputMode="stateHidden">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<action android:name=".TrackActivity" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
非常感谢任何帮助!谢谢!
原来我没有很好的 GPS 信号,这就是导致我出现问题的原因。我以为我坐在 window 旁边没问题,但连接到 GPS 需要很长时间(@cYrixmorten 建议超过 15 分钟)。如果有足够的时间它会连接到 GPS,但我发现一旦我走到外面,它几乎会立即连接。
如果有人需要测试 GPS 服务,我使用了 this GPS 测试应用程序。