Android:如何在当前主线程中使用mFusedLocationClient回调(结果位置) [英] Android : How to use mFusedLocationClient callback (resulting location) in current mainthread
问题描述
以下是我连接RecyclerView
的适配器,在该适配器中,我需要更新显示当前位置到另一个位置的距离的TextView
之一.
Following is my adapter for a RecyclerView
where i need to update one of the TextView
which shows distance of current location to another location .
现在,要获取当前位置,我正在使用mFusedLocationClient.requestLocationUpdates(mFusedLocationRquest,mLocationCallback,null);
Now , to get the current location , i am using mFusedLocationClient.requestLocationUpdates(mFusedLocationRquest,mLocationCallback,null);
如果我要使用以下代码,并且刚刚在具有运行时权限的应用程序中启用了gps,我将在线上遇到NPE:
If i am going with the below code and have just enabled gps in app with runtime permission , i face NPE on line :
float distance = updatedLoc.distanceTo(des);
当我在已启用gps的情况下打开时,应用程序不会崩溃(可能是因为在这种情况下,最后一个已知位置不为null).
App does not crash when i open with gps already enabled (probably because the last known loc is not null in that case ).
所以要确保updatedLoc
不为null,我想确保仅在位置回调之后更新我的TextView
,这怎么可能?
So to make sure that updatedLoc
is not null , i want to make sure that my TextView
is updated after the location callback only , how would that be possible ?
在此API的回调createLocationCallback()
中,我无法正确更新TextView(尝试将holder作为全局变量使用,但这很混乱,项目未正确更新.)
In this API's callback , createLocationCallback()
, i am unable to update the TextView properly (tried using holder as global var , but it was messy and items weren't updated properly .)
谢谢.
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
仍为null,表示位置提供者尚未收到位置.
When the onBindViewHolder
is called, updatedLoc
is still null, means location provider has not received location yet.
您应将onBindViewHolder
中的updatedLoc
换成空字符,如下所示:
You should wrap the updatedLoc
in onBindViewHolder
against to null case like below
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
来计算和显示距离,而不是Waiting for location...
And whenever you receive the location, onBindViewHolder
must be called again to calculate and show distance instead of Waiting for location...
因此,您需要更新createLocationCallback
方法.只需添加notifyDataSetChanged()
So you need to update createLocationCallback
method. Just add 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();
}
};
}
这篇关于Android:如何在当前主线程中使用mFusedLocationClient回调(结果位置)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!