Java 在Android中创建一个在获取位置后返回地址的类
我正在尝试在Android中创建一个位置获取器类,该类将获取位置并返回Java 在Android中创建一个在获取位置后返回地址的类,java,android,asynchronous,Java,Android,Asynchronous,我正在尝试在Android中创建一个位置获取器类,该类将获取位置并返回地址实例 此类包括向用户请求位置权限、显示权限理由、显示无法获取位置时的错误消息以及带有进度条的AlertDialog,该进度条将显示何时获取位置,并在找到位置或发生错误时隐藏自身 这是我目前的工作: public class LocationFetcher { static Handler handler = new Handler(Looper.getMainLooper()); AlertDialog
地址
实例
此类包括向用户请求位置权限、显示权限理由、显示无法获取位置时的错误消息以及带有进度条的AlertDialog,该进度条将显示何时获取位置,并在找到位置或发生错误时隐藏自身
这是我目前的工作:
public class LocationFetcher {
static Handler handler = new Handler(Looper.getMainLooper());
AlertDialog alertDialog;
Context context;
View retry;
LocationFetcher(Context context, View retry) {
this.context = context;
this.retry = retry;
handler.post(() -> {
alertDialog = new AlertDialog.Builder(context)
.setTitle("Trying to fetch location...")
.setCancelable(false)
.create();
alertDialog.setView(LayoutInflater.from(context).inflate(R.layout.progress_dialog, null));
});
}
void showErrorMessage() {
handler.post(() -> {
alertDialog.dismiss();
new Builder(context)
.setTitle("Error getting location data")
.setMessage("Please check the location settings in the Settings app and try again")
.setPositiveButton("Retry", (dialog, which) -> {
retry.performClick();
alertDialog.dismiss();
})
.setNegativeButton("Cancel", (dialog, which) -> {
// do nothing
}).show();
});
}
Address getLocation() {
final int LOCATION_PERMISSION_REQUEST_CODE = 1;
if (ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
Task<Location> locationTask = LocationServices.getFusedLocationProviderClient(context).getLastLocation();
handler.post(alertDialog::show);
try {
return Executors.newSingleThreadExecutor().submit(() -> {
boolean flag = true;
while (flag) {
if (locationTask.isComplete()) {
if (locationTask.isSuccessful()) {
Location location = locationTask.getResult();
if (location != null) {
List<Address> addresses = null;
try {
addresses = new Geocoder(context, Locale.getDefault()).getFromLocation(location.getLatitude(), location.getLongitude(), 1);
} catch (IOException e) {
e.printStackTrace();
}
if (addresses != null) {
alertDialog.dismiss();
return addresses.get(0);
}
else showErrorMessage();
} else showErrorMessage();
} else if (locationTask.getException() != null)
showErrorMessage();
flag = false;
}
}
return null;
}).get(5, TimeUnit.SECONDS);
} catch (ExecutionException | InterruptedException | TimeoutException e) {
e.printStackTrace();
showErrorMessage();
}
} else // if permission is not there, show permission rationale
if (ActivityCompat.shouldShowRequestPermissionRationale((Activity) context, Manifest.permission.ACCESS_FINE_LOCATION))
handler.post(() -> {
new AlertDialog.Builder(context)
.setTitle("Permission rationale")
.setMessage("This permission is required to access your location. Without it, the app cannot get your location to serve you better.")
.setPositiveButton("Ok", (dialog, which) -> {
ActivityCompat.requestPermissions((Activity) context, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, LOCATION_PERMISSION_REQUEST_CODE);
}).setNegativeButton("Cancel", (dialog, which) -> dialog.dismiss())
.show();
});
else // if rationale not needed, ask for permission again
ActivityCompat.requestPermissions((Activity) context, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, LOCATION_PERMISSION_REQUEST_CODE);
return null;
}
}
并在实际的GetLocation方法中显示对话框:
handler.post(alertDialog::show)代码>
这里发生的事情基本上是因为构造函数中的handler.post
部分作为一个异步操作工作,有些是handler.post(alertDialog::show)代码>行在创建警报对话框
之前执行,这导致GetLocation
方法抛出一个NullPointerException
在使用alertDialog
之前,如何等待构造函数和异步任务(或将异步转换为同步)完成
编辑:
编辑1:
注:
我想异步调用GetLocation方法,即调用如下函数:
Executors.newSingleThreadExecutor().execute(() -> {
LocationFetcher locationFetcher = new LocationFetcher(this, tvCurrentLocation);
Address address = locationFetcher.getLocation();
});
同步创建alertDialog并在新线程中调用方法getLocation
:
构造函数
LocationFetcher(Context context, View retry) {
this.context = context;
this.retry = retry;
alertDialog = new AlertDialog.Builder(context)
.setTitle("Trying to fetch location...")
.setCancelable(false)
.create();
alertDialog.setView(LayoutInflater.from(context).inflate(R.layout.progress_dialog, null));
}
和方法调用
LocationFetcher locationFetcher = new LocationFetcher(this, tvCurrentLocation);
Executors.newSingleThreadExecutor().execute(() -> {
Address address = locationFetcher.getLocation();
});
为什么要异步创建alertDialog?只要在构造函数中同步创建它就可以了。@Yoleth我忘了提到什么。我已经在编辑中添加了它,请检查。仍然是相同的答案,您已经在主线程之外的另一个线程中,因此同步创建alertdialog:)@Yoleth您不能在非UI线程中创建UI元素。这是一个错误。我真不敢相信我竟然如此愚蠢。非常感谢。顺便说一句,您忘记删除答案的构造函数部分中的处理程序。post
。是的,我看到了,我刚刚编辑:)
LocationFetcher locationFetcher = new LocationFetcher(this, tvCurrentLocation);
Executors.newSingleThreadExecutor().execute(() -> {
Address address = locationFetcher.getLocation();
});