Android获取地理位置解析

本文详述了Android Q后获取地理位置权限的变更,并深入分析了LocationManager的requestLocationUpdates方法,包括Location监听的实现原理,从创建ListenerTransport、通过AIDL与LocationManagerService交互到接收位置更新回调的过程。同时探讨了如何在后台服务中处理定位权限并提供相关代码示例。
摘要由CSDN通过智能技术生成

近期一个项目用到了该功能,因此进行了比较详细的研究,在这里整理一下。
首先指的一提的是,Android Q版本之后,定位权限有一个改动就是,如果是后台服务想要获取地理位置信息的话,需要申请新的权限ACCESS_BACKGROUND_LOCATION ,如果不想申请该权限进行定位的话,需要将服务切换为前台服务,如何切换的代码在github地址上,附在本文最后。

接下来进行位置监听的代码分析:
想要获取后台位置监听的话,可以直接调用LocationManager的requestLocationUpdates方法,通常来说直接调用的是:

public void requestLocationUpdates(String provider, long minTime, float minDistance,
            LocationListener listener, Looper looper) {
   
        checkProvider(provider);
        checkListener(listener);

        LocationRequest request = LocationRequest.createFromDeprecatedProvider(
                provider, minTime, minDistance, false);
        requestLocationUpdates(request, listener, looper, null);
    }

刚开始进行参数的非空校验:

    private static void checkProvider(String provider) {
   
        if (provider == null) {
   
            throw new IllegalArgumentException("invalid provider: " + provider);
        }
    }

之后调用createFromDeprecatedProvider生成一个request,该部分代码很简单

public static LocationRequest createFromDeprecatedProvider(String provider, long minTime,
            float minDistance, boolean singleShot) {
   
        if (minTime < 0) minTime = 0;
        if (minDistance < 0) minDistance = 0;

        int quality;
        if (LocationManager.PASSIVE_PROVIDER.equals(provider)) {
   
            quality = POWER_NONE;
        } else if (LocationManager.GPS_PROVIDER.equals(provider)) {
   
            quality = ACCURACY_FINE;
        } else {
   
            quality = POWER_LOW;
        }

        LocationRequest request = new LocationRequest()
                .setProvider(provider)
                .setQuality(quality)
                .setInterval(minTime)
                .setFastestInterval(minTime)
                .setSmallestDisplacement(minDistance);
        if (singleShot) request.setNumUpdates(1);
        return request;
    }

创建好request调用requestLocationUpdates:

 private void requestLocationUpdates(LocationRequest request, LocationListener listener,
            Looper looper, PendingIntent intent) {
   

        String packageName = mContext.getPackageName();

        // wrap the listener class
        ListenerTransport transport = wrapListener(listener, looper);

        try {
   
            mService.requestLocationUpdates(request, transport, intent, packageName);
       } catch (RemoteException e) {
   
           throw e.rethrowFromSystemServer();
       }
    }

其中wrapListener的实现如下:

    private ListenerTransport wrapListener(LocationListener listener, Looper looper) {
   
        if (listener == null) return null;
        synchronized (mListeners) {
   
            ListenerTransport transport = mListeners.get(listener);
            if (transport == null) {
   
                transport = new ListenerTransport(listener, looper);
            }
            mListeners.put(listener, transport);
            return transport;
        }
    }

mListeners是维护listener的一个hashmap:

    // Map from LocationListeners to their associated ListenerTransport objects
    private HashMap<LocationListener,ListenerTransport> mListeners =
        new HashMap<LocationListener,ListenerTransport>();

如果该listener之前未注册过的话,会生成一个新的ListenerTransport:

ListenerTransport(LocationListener listener, Looper looper) {
   
            mListener = listener;

            if (looper == null) {
   
                mListenerHandler = new Handler() {
   
                    @Override
                    public void handleMessage(Message msg) {
   
                        _handleMessage(msg);
                    }
                };
            } else {
   
                mListenerHandler = new Handler(looper) {
   
                    @Override
                    public void handleMessage(Message msg) {
   
                        _handleMessage(msg);
                    }
                };
            }
        }

这里会进行loop的判断,一般来说,我们不传入loop时,会生成一个指向当前线程消息队列的handler,接下来看下_handleMessage的实现:


        private void _handleMessage(Message msg) {
   
            switch (msg.what) {
   
                case TYPE_LOCATION_CHANGED:
                    Location location = new Location((Location) msg.obj);
                    mListener.onLocationChanged(location);
                    break;
                case TYPE_STATUS_CHANGED:
                    Bundle b = (Bundle) msg.obj;
                    String provider = b.getString("provider");
                    int status = b.getInt("status");
                    Bundle extras = b.getBundle("extras");
                    mListener.onStatusChanged(provider, status, extras);
                    break;
                case TYPE_PROVIDER_ENABLED:
                    mListener.onProviderEnabled((String) msg
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值