Android:如何在当前主线程中使用mFusedLocationClient回调(结果位置) [英] Android : How to use mFusedLocationClient callback (resulting location) in current mainthread

查看:110
本文介绍了Android:如何在当前主线程中使用mFusedLocationClient回调(结果位置)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下是我连接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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆