java - 在Android中获取位置后创建一个返回地址的类
问题描述
我正在尝试在 Android 中创建一个多合一位置获取器类,它将获取位置并返回Address
实例。
此类结合了向用户询问位置许可、显示许可理由、在无法获取位置时显示错误消息以及带有 ProgressBar 的 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;
}
}
我面临的问题在于代码的这些部分:
构造函数:
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));
});
并在实际的 GetLocation 方法中显示对话框:
handler.post(alertDialog::show);
基本上这里发生的事情是因为handler.post
构造函数中的部分作为异步操作工作,有时该handler.post(alertDialog::show);
行在创建之前执行,alertDialog
这导致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();
});
推荐阅读
- excel - 我需要就下面编写的代码提供建议,以防止粘贴到下拉单元格上
- reactjs - Button、ButtonGroup 和 Typography 的 Material-UI Grid 基线对齐
- docker - 在 Docker Swarm 上看不到 PiHole 客户端
- css - 如何仅使用 CSS 而不使用 flexbox 更改 TH 内的两个 SPAN 的顺序
- python - 将循环变量保存在不同的 CSV 文件中
- google-sheets - 计算谷歌表中行之间的不匹配
- javascript - Bootstrap 4中的响应列高度
- hololens - HL2 睡眠设置
- mysql - 不使用 GROUP BY 从重复数据中获取唯一记录
- javascript - 数组中的对象键求和,但求和仅在函数javascript loadsh中提供单词