以下是我的 RecyclerView
适配器,我需要更新其中一个 TextView
,它显示当前位置到另一个位置的距离。
现在,为了获取当前位置,我正在使用 mFusedLocationClient.requestLocationUpdates(mFusedLocationRquest,mLocationCallback,null);
如果我使用下面的代码,并且刚刚在具有运行时权限的应用程序中启用了 GPS,我会在线面临 NPE:
float distance = updatedLoc.distanceTo(des);
当我在已启用 GPS 的情况下打开应用程序时,应用程序不会崩溃(可能是因为在这种情况下最后一个已知的 loc 不为空)。
因此,为了确保 updatedLoc
不为 null ,我想确保我的 TextView
仅在位置回调后更新,这怎么可能?
在此API的回调createLocationCallback()
中,我无法正确更新TextView(尝试使用holder作为全局var,但它很困惑并且项目未正确更新。)
提前致谢。
public class PlaceListAdapter extends RecyclerView.Adapter<PlaceListAdapter.PlaceViewHolder> implements android.location.LocationListener{
private static final long LOCATION_REFRESH_TIME = 2000;
private static final float LOCATION_REFRESH_DISTANCE = 100;
private static final int MY_PERMISSION_ACCESS_COURSE_LOCATION = 1001;
private Context mContext;
private PlaceBuffer mPlaces;
Location updatedLoc = null;
PlaceViewHolder myHolder;
boolean canGetLocation = false;
android.location.LocationListener locationListener;
double lat1,long1;
MySimpleCallback mySimpleCallback;
String dist;
private FusedLocationProviderClient mFusedLocationClient;
private LocationRequest mFusedLocationRquest;
private LocationCallback mLocationCallback;
/**
* Creates a callback for receiving location events.
*/
private void createLocationCallback() {
mLocationCallback = new LocationCallback() {
@Override
public void onLocationResult(LocationResult locationResult) {
super.onLocationResult(locationResult);
updatedLoc = locationResult.getLastLocation();
Log.d("testingvalue",String.valueOf(updatedLoc==null));
//mLastUpdateTime = DateFormat.getTimeInstance().format(new Date());
}
};
}
/**
* Constructor using the context and the db cursor
*
* @param context the calling context/activity
*/
public PlaceListAdapter(Context context, PlaceBuffer places) {
this.mContext = context;
this.mPlaces = places;
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(mContext);
createLocationCallback();
createLocationRequest();
if (ActivityCompat.checkSelfPermission(mContext, android.Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions((Activity) mContext,
new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION},
101);
}
mFusedLocationClient.requestLocationUpdates(mFusedLocationRquest,mLocationCallback,null);
}
private void createLocationRequest() {
mFusedLocationRquest = new LocationRequest();
// Sets the desired interval for active location updates. This interval is
// inexact. You may not receive updates at all if no location sources are available, or
// you may receive them slower than requested. You may also receive updates faster than
// requested if other applications are requesting location at a faster interval.
mFusedLocationRquest.setInterval(100);
// Sets the fastest rate for active location updates. This interval is exact, and your
// application will never receive updates faster than this value.
mFusedLocationRquest.setFastestInterval(100);
mFusedLocationRquest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
}
/**
* Called when RecyclerView needs a new ViewHolder of the given type to represent an item
*
* @param parent The ViewGroup into which the new View will be added
* @param viewType The view type of the new View
* @return A new PlaceViewHolder that holds a View with the item_place_card layout
*/
@Override
public PlaceViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// Get the RecyclerView item layout
LayoutInflater inflater = LayoutInflater.from(mContext);
View view = inflater.inflate(R.layout.item_place_card, parent, false);
return new PlaceViewHolder(view);
}
/**
* Binds the data from a particular position in the cursor to the corresponding view holder
*
* @param holder The PlaceViewHolder instance corresponding to the required position
* @param position The current position that needs to be loaded with data
*/
@Override
public void onBindViewHolder(PlaceViewHolder holder, int position) {
String placeName = mPlaces.get(position).getName().toString();
String placeAddress = mPlaces.get(position).getAddress().toString();
double lat = mPlaces.get(position).getLatLng().latitude;
double lng = mPlaces.get(position).getLatLng().longitude;
//Location currentLocation = getCurrentLocation();
//Location currLoc = new GPSTracker(mContext).getLocation();
//Toast.makeText(mContext, "distance is" + dist + "km", Toast.LENGTH_SHORT).show();
Location des = new Location("destination");
des.setLatitude(lat);
des.setLongitude(lng);
float distance = updatedLoc.distanceTo(des);
distance = distance / 1000;
dist = "";
if (distance < 1) {
dist = "less than km away";
} else {
dist = String.format("%.2f", distance) + " km";
}
holder.nameTextView.setText(placeName);
holder.addressTextView.setText(dist);
holder.taskTextView.setText(MainActivity.preference.getString(mPlaces.get(position).getId(), "chv"));
}
public void swapPlaces(PlaceBuffer newPlaces) {
mPlaces = newPlaces;
if (mPlaces != null) {
// Force the RecyclerView to refresh
this.notifyDataSetChanged();
}
}
/**
* Returns the number of items in the cursor
*
* @return Number of items in the cursor, or 0 if null
*/
@Override
public int getItemCount() {
if (mPlaces == null) {
Log.d("countcheck", "zero bro");
return 0;
}
return mPlaces.getCount();
}
@Override
public void onLocationChanged(Location location) {
updatedLoc = location;
}
@Override
public void onStatusChanged(String s, int i, Bundle bundle) {
}
@Override
public void onProviderEnabled(String s) {
}
@Override
public void onProviderDisabled(String s) {
}
/**
* PlaceViewHolder class for the recycler view item
*/
class PlaceViewHolder extends RecyclerView.ViewHolder {
TextView nameTextView;
TextView addressTextView;
TextView taskTextView;
public PlaceViewHolder(View itemView) {
super(itemView);
nameTextView = (TextView) itemView.findViewById(R.id.name_text_view);
addressTextView = (TextView) itemView.findViewById(R.id.address_text_view);
taskTextView = (TextView) itemView.findViewById(R.id.task_text_view);
}
}
}
最佳答案
当调用onBindViewHolder
时,updatedLoc
仍然为空,意味着位置提供程序尚未收到位置。
您应该将 updatedLoc
包装在 onBindViewHolder
中,针对 null 情况,如下所示
if(updatedLoc != null){
float distance = updatedLoc.distanceTo(des);
distance = distance / 1000;
dist = "";
if (distance < 1) {
dist = "less than km away";
} else {
dist = String.format("%.2f", distance) + " km";
}
} else {
dist = "Waiting for location...";
}
holder.nameTextView.setText(placeName);
holder.addressTextView.setText(dist);
每当您收到位置时,都必须再次调用onBindViewHolder
来计算并显示距离,而不是等待位置...
因此您需要更新 createLocationCallback
方法。只需添加 notifyDataSetChanged()
private void createLocationCallback() {
mLocationCallback = new LocationCallback() {
@Override
public void onLocationResult(LocationResult locationResult) {
super.onLocationResult(locationResult);
updatedLoc = locationResult.getLastLocation();
Log.d("testingvalue",String.valueOf(updatedLoc==null));
//mLastUpdateTime = DateFormat.getTimeInstance().format(new Date());
notifyDataSetChanged();
}
};
}
关于安卓 : How to use mFusedLocationClient callback (resulting location) in current mainthread,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45209085/