安卓 : How to use mFusedLocationClient callback (resulting location) in current mainthread

标签 android callback gps location android-adapter

以下是我的 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/

相关文章:

android - XMPP 交货收据 XEP-0184 与 ASMACK

android - ActionBar 溢出图标拒绝更改

android - Android开发+如何建立将保存在此文件夹中的文件夹和文件?

android - LocationManager 与 Google Maps API 的准确性

android - 如果 RaisedButton.icon() 上的构造函数中的图标值为空,如何保持图标禁用?

objective-c - Obj-C 在同一个类中的静态方法的静态方法上使用@selector?

swift - 在回调函数 swift 上展开一个 Optional 值

javascript - C# 中的作用域、变量访问

android - Android 中的 Google map 将纬度/经度初始化为 0.0(有时...)

iphone - 如何在 iPhone 上保存带有 EXIF(GPS) 和方向的照片?