我创建了一个AsyncTask来检索精度为20米的GPS位置。 我想执行一个while循环,直到准确性可以加入。
问题是当我请求更新职位时我遇到了异常。
java.lang.NullPointerException: Calling thread must be a prepared Looper thread.
这是错误的代码
@Override
protected String doInBackground(Void... params) {
if (ActivityCompat.checkSelfPermission(activity, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(activity, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return null;
}
mLocationRequest.setInterval(100);
mLocationRequest.setPriority(100);
mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
while (mLastLocation == null || (mLastLocation.getAccuracy()>Float.parseFloat("20.0") && mLastLocation.hasAccuracy())){
try {
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient,mLocationRequest,activity);
mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
} catch (SecurityException secex) {
}
}
return null;
}
答案 0 :(得分:9)
我整整一天都遇到了麻烦。我在服务中的后台运行FusedLocationApi。
我做了什么 - 我在其他地方读过它 - 将Looper.getMainLooper()添加为requestLocationUpdates()
的最后一个参数。
所以,而不是这个
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient,mLocationRequest,activity);
你会有
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this, Looper.getMainLooper());
如果您阅读整个FusedLocationProviderApi页面,您会看到该方法会根据参数执行不同的操作。
答案 1 :(得分:2)
在doInBackground中运行时使用Looper.prepare() or runOnUiThread()
函数在UI中进行更改,或者在doInBackground以外的方法中进行更改
示例:
runOnUiThread(new Runnable() {
@Override
public void run() {
progressBar = new ProgressDialog(MainActivity.this);
progressBar.setCancelable(false);
progressBar.setTitle("Downloading Files...");
progressBar.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progressBar.setProgress(0);
progressBar.setMax(100);
progressBar.show();
}
});
答案 2 :(得分:0)
我使用了guava中的SettableFuture,这样当调用返回时我就不会在主循环器上运行不必要的代码。 (如果你的回调开启了一些繁重的工作量并导致UI崩溃,这可能是一个问题。)
protected String doInBackground(Void... params) {
SettableFuture<Location> future = SettableFuture.create();
Log.w(TAG, "before fused call isMainLooper= %b", Looper.getMainLooper().isCurrentThread());
// future.set runs on the main thread.
//future.get stays on the background thread.
mFusedLocationApi.requestLocationUpdates(
client,
LOCATION_REQUEST,
location1 -> {
future.set(location1);
Log.w(TAG, "callback: isMainLooper= %b", Looper.getMainLooper().isCurrentThread());
}
Looper.getMainLooper());
location = future.get(10, SECONDS);
Log.w(TAG, "after fused call isMainLooper= %b", Looper.getMainLooper().isCurrentThread());
记录输出
W TAG: before fused call isMainLooper = false
W TAG: callback: isMainLooper = true
W TAG: after fused call isMainLooper = false
答案 3 :(得分:0)
我在后台获取位置时遇到了问题。当我发现异常时我添加了Looper.getMainLooper ..然后我决定再次阅读文档,我完全改变了我在后台获取位置的方式;区别在于使用FusedLocationProviderClient
和这样的回调。
首先定义您的提供者客户端。
private FusedLocationProviderClient mFusedLocationClient;
定义位置回调,确保使用com.google.android.gms.location.LocationCallback
/**
* Fuse location api callback
*/
private LocationCallback mLocationCallback = new LocationCallback() {
@Override
public void onLocationResult(LocationResult locationResult) {
super.onLocationResult(locationResult);
for (Location location : locationResult.getLocations()) {
mLastLocation = location;
//Send to your server or update your UI
}
}
@Override
public void onLocationAvailability(LocationAvailability locationAvailability) {
super.onLocationAvailability(locationAvailability);
//Send to your server or update your UI
}
};
定义请求位置更新的方法
public void startLocationUpdates() {
boolean hasLocationPermission = ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED &&
ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED;
if (!hasLocationPermission) {
gettingLocationUpdates = false;
return;
}
mFusedLocationClient.requestLocationUpdates(mLocationRequest, mLocationCallback, /*Looper*/ null);
com.google.android.gms.tasks.Task<Location> task = mFusedLocationClient.getLastLocation();
task.addOnCompleteListener(task1 -> {
mLastLocation = task1.getResult();
gettingLocationUpdates = true;
});
}
在服务的onCreate中初始化它并开始请求更新
@Override
public void onCreate() {
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
startLocationUpdates();
}
不要忘记删除位置更新,否则它将永远不会停止
@Override
public void onDestroy() {
if (mFusedLocationClient != null) {
mFusedLocationClient.flushLocations();
mFusedLocationClient.removeLocationUpdates(mLocationCallback);
}
尝试一下,让我知道。