第四节 百度定位、地图SDK,和风天气获取教程

专栏目录

  1. 第一节 自定义轮播图的制作
  2. 第二节 底部导航栏菜单,炫酷菜单动画,背景变暗、按钮焦点获取
  3. 第三节 适配Android10的拍照、从相册获取代码,包括完整的权限申请和图片地址获取
  4. 第四节 百度定位、地图SDK,和风天气获取教程
  5. 第五节 微信朋友圈式九宫格添加图片展示(待更新)
  6. 第六节 第三方api获取淘宝数据,用RecyclerView进行商品展示、刷新和搜索(待更新)

引言

在安卓开发中,我们经常会用到调用地图、定位的API,并且还可能会通过定位来获取当前位置的地址。下面我将带领大家一步步对这些常见的API的调用做一个总结。

效果图

在这里插入图片描述

利用百度地图SDK获取经纬度

定位SDK的核心能力就是帮助开发者快速、精准的获取用户定位信息。开发者只需按照如下流程操作,即可获取用户当前经纬度。

一、准备工作

在使用定位SDK进行具体开发工作之前,需获取密钥(AK),并对开发工程进行环境配置工作。 此外,Google在Android 6.0中引入了动态权限获取机制,开发者在使用定位SDK之前,请详细了解关于Android 6.0系统开发须知。

1.注册和获取密钥

只要注册一个普通的百度账号即可,注册完登录网址
获取AK的流程大致可分为如下四个步骤:
(1)登录API控制台;
(2)创建应用;
(3)配置SHA1和包名;
(4)提交生成AK。

详细内容请参考百度开发文档

2.添加SDK(jar + so)

下载Android定位SDK并解压,将libs中的jar和so放置到工程中相应的位置。

注意,Android定位SDK提供了多种CPU架构的so文件(jar通用,只有一个),开发者可根据实际使用需求,放置所需so到对应的工程文件夹内。

注:jar文件是你在activity中调用的各种定位方法,.so文件是用来适配cpu架构的,需要根据你的需求选用合适so文件,不确定的话就把所有的类型都加上。

下图是so文件存放的位置,你需要在app下创建一个jniLibs文件家(名字必须是这个),文件夹下的目录就是五种cpu架构,我们需要将对应架构的.so文件放在对应文件夹下。
在这里插入图片描述
jar文件放在libs文件夹下。
在这里插入图片描述
.so文件和jar文件下载
链接:https://pan.baidu.com/s/1zyWNe4k6sXTd53nzR0yL3g
提取码:gzay
复制这段内容后打开百度网盘手机App,操作更方便哦–来自百度网盘超级会员V4的分享

3.配置build.gradle文件

放在下面的文件夹的android{}里面
在这里插入图片描述

sourceSets{
        main{
                 jniLibs.srcDir 'libs'
                 jni.srcDirs = []    //disable automatic ndk-build
         }
}

4.添加AK

Android定位SDK自v4.0版本起,需要进行AK鉴权。开发者在使用SDK前,需完成AK申请,并在AndroidManifest.xml文件中,正确填写AK。
在Application标签中增加如下代码:

<meta-data
    android:name="com.baidu.lbsapi.API_KEY"
    android:value="YourAK" >
</meta-data>

在这里插入图片描述

5.添加定位权限

使用定位SDK,需在AndroidManifest.xml文件中Application标签中声明service组件,每个App拥有自己单独的定位service,代码如下:

<service android:name="com.baidu.location.f" android:enabled="true" android:process=":remote"> </service>

除添加service组件外,使用定位SDK还需添加如下权限:

<!-- 这个权限用于进行网络定位-->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!-- 这个权限用于访问GPS定位-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!-- 用于访问wifi网络信息,wifi信息会用于进行网络定位-->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!-- 获取运营商信息,用于支持提供运营商信息相关的接口-->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- 这个权限用于获取wifi的获取权限,wifi信息会用来进行网络定位-->
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<!-- 写入扩展存储,向扩展卡写入数据,用于写入离线定位数据-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- 访问网络,网络定位需要上网-->
<uses-permission android:name="android.permission.INTERNET" />

二、开始实现定位功能

MainActivity.java

import androidx.appcompat.app.AppCompatActivity;
import android.Manifest;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import com.baidu.location.BDAbstractLocationListener;
import com.baidu.location.BDLocation;
import com.baidu.location.LocationClient;
import com.baidu.location.LocationClientOption;

import java.util.List;

public class MainActivity extends AppCompatActivity {
    private TextView textView2;
    private TextView textView3;
    private Button button;
    private String address;
    double latitude;
    double longitude;
    public LocationClient mLocationClient = null;
    private MyLocationListener myListener = new MyLocationListener();
    //BDAbstractLocationListener为7.2版本新增的Abstract类型的监听接口
//原有BDLocationListener接口暂时同步保留。具体介绍请参考后文第四步的说明
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //权限检测和申请工具类
        PermissionUtil.getInstance().onCallback(new PermissionUtil.PermissionCallback() {
            @Override
            public void onGranted(List<String> actions) {
                for (String action : actions) {
                    Log.e("TAG", String.format("onGranted: %s", action));
                }
            }

            @Override
            public void onDenied(List<String> actions) {
                for (String action : actions) {
                    Log.e("TAG", String.format("onGranted: %s", action));
                }
            }
        }).requestPermissions(this, new String[]{
                Manifest.permission.ACCESS_NETWORK_STATE,
                Manifest.permission.ACCESS_WIFI_STATE,
                Manifest.permission.ACCESS_FINE_LOCATION,
                Manifest.permission.ACCESS_COARSE_LOCATION,
                Manifest.permission.CHANGE_WIFI_STATE,
                Manifest.permission.WRITE_EXTERNAL_STORAGE,
                Manifest.permission.INTERNET
        });


        init();
        initLocationClient();
        setLocationClientOption();

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mLocationClient.start();    //开始定位
                //mLocationClient为第二步初始化过的LocationClient对象
                //调用LocationClient的start()方法,便可发起定位请求
            }
        });
    }

    //绑定组件
    private void init(){
        textView2 = findViewById(R.id.textView2);
        textView3 = findViewById(R.id.textView3);
        button = findViewById(R.id.button);
    }

    /**
     * 初始化LocationClient类
     * 请在主线程中声明LocationClient类对象,该对象初始化需传入Context类型参数。
     * 推荐使用getApplicationConext()方法获取全进程有效的Context。
     */
    private void initLocationClient(){
        //定位监听器,一旦调用requestLocation()函数,就会触发MyLocationListener()
        mLocationClient = new LocationClient(getApplicationContext());
        //声明LocationClient类
        mLocationClient.registerLocationListener(myListener);
    }

    /**
     * 配置定位SDK参数
     * 通过参数配置,可选择定位模式、可设定返回经纬度坐标类型、可设定是单次定位还是连续定位。
     * 定位SDK所提供的定位模式包括三种:高精度、低功耗和仅用设备定位。开发者请根据自己的实际使用需求进行选择。
     *
     * 定位SDK能够返回三种坐标类型的经纬度(国内),分别是GCJ02(国测局坐标)、BD09(百度墨卡托坐标)和BD09ll(百度经纬度坐标)。
     * 如果开发者想利用定位SDK获得的经纬度直接在百度地图上标注,请选择坐标类型BD09ll。
     */
    private void setLocationClientOption(){
        LocationClientOption option = new LocationClientOption();
        option.setLocationMode(LocationClientOption.LocationMode.Hight_Accuracy);
        //可选,设置定位模式,默认高精度
        //LocationMode.Hight_Accuracy:高精度;
        //LocationMode. Battery_Saving:低功耗;
        //LocationMode. Device_Sensors:仅使用设备;

        option.setCoorType("bd09ll");
        //可选,设置返回经纬度坐标类型,默认GCJ02
        //GCJ02:国测局坐标;
        //BD09ll:百度经纬度坐标;
        //BD09:百度墨卡托坐标;
        //海外地区定位,无需设置坐标类型,统一返回WGS84类型坐标

        option.setScanSpan(1000);
        //可选,设置发起定位请求的间隔,int类型,单位ms
        //如果设置为0,则代表单次定位,即仅定位一次,默认为0
        //如果设置非0,需设置1000ms以上才有效

        option.setOpenGps(true);
        //可选,设置是否使用gps,默认false
        //使用高精度和仅用设备两种定位模式的,参数必须设置为true

        option.setLocationNotify(true);
        //可选,设置是否当GPS有效时按照1S/1次频率输出GPS结果,默认false

        option.setIgnoreKillProcess(false);
        //可选,定位SDK内部是一个service,并放到了独立进程。
        //设置是否在stop的时候杀死这个进程,默认(建议)不杀死,即setIgnoreKillProcess(true)

        option.SetIgnoreCacheException(false);
        //可选,设置是否收集Crash信息,默认收集,即参数为false

        option.setWifiCacheTimeOut(5*60*1000);
        //可选,V7.2版本新增能力
        //如果设置了该接口,首次启动定位时,会先判断当前Wi-Fi是否超出有效期,若超出有效期,会先重新扫描Wi-Fi,然后定位

        option.setEnableSimulateGps(false);
        //可选,设置是否需要过滤GPS仿真结果,默认需要,即参数为false

        option.setNeedNewVersionRgc(true);
        //可选,设置是否需要最新版本的地址信息。默认需要,即参数为true

        option.setIsNeedAddress(true);
        //可选,是否需要地址信息,默认为不需要,即参数为false
        //如果开发者需要获得当前点的地址信息,此处必须为true

        option.setNeedNewVersionRgc(true);
        //可选,设置是否需要最新版本的地址信息。默认需要,即参数为true

        mLocationClient.setLocOption(option);
        //mLocationClient为第二步初始化过的LocationClient对象
        //需将配置好的LocationClientOption对象,通过setLocOption方法传递给LocationClient对象使用
        //更多LocationClientOption的配置,请参照类参考中LocationClientOption类的详细说明
    }

    /**
     * 实现BDAbstractLocationListener接口
     * Android定位SDK自V7.2版本起,对外提供了Abstract类型的监听接口BDAbstractLocationListener,用于实现定位监听。
     */
    public class MyLocationListener extends BDAbstractLocationListener {
        @Override
        public void onReceiveLocation(BDLocation location){
            //此处的BDLocation为定位结果信息类,通过它的各种get方法可获取定位相关的全部结果
            //以下只列举部分获取经纬度相关(常用)的结果信息
            //更多结果信息获取说明,请参照类参考中BDLocation类中的说明
            latitude = location.getLatitude();    //获取纬度信息
            longitude = location.getLongitude();    //获取经度信息
            float radius = location.getRadius();    //获取定位精度,默认值为0.0f
            String coorType = location.getCoorType();
            //获取经纬度坐标类型,以LocationClientOption中设置过的坐标类型为准
            int errorCode = location.getLocType();
            //获取定位类型、定位错误返回码,具体信息可参照类参考中BDLocation类中的说明
            address = location.getAddrStr();
            textView2.setText(longitude + ", " + latitude);
            textView3.setText(address);
            mLocationClient.stop();
        }
    }
}

PermissionUtil工具类

package com.example.mycourse4;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
import android.text.TextUtils;

import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.core.content.PermissionChecker;

import java.util.ArrayList;
import java.util.List;

public class PermissionUtil {
    private static final String TAG = "PermissionUts";
    private final static int request_permission_code = 0x99;
    private PermissionCallback permissionCallback;
    private Handler mHandler = null;

    private static class SingleUts {
        private static PermissionUtil uts = new PermissionUtil();
    }

    private PermissionUtil() {
        final HandlerThread handlerThread = new HandlerThread(TAG);
        handlerThread.start();
        mHandler = new Handler(handlerThread.getLooper());

    }

    public static PermissionUtil getInstance() {
        return SingleUts.uts;
    }


    /**
     * 请求权限
     *
     * @param activity
     * @param permission
     */
    public void requestPermission(Activity activity, String permission) {
        if (null == activity || TextUtils.isEmpty(permission)) {
            return;
        }
        if (!verifyPermission(activity, permission)) {
            ActivityCompat.requestPermissions(activity, new String[]{permission}, request_permission_code);
        }
    }

    /**
     * 请求权限
     *
     * @param activity
     * @param permissions
     */
    public void requestPermissions(final Activity activity, final String[] permissions) {
        if (null == activity || null == permissions || permissions.length == 0) {
            return;
        }
        ActivityCompat.requestPermissions(activity, permissions, request_permission_code);

    }

    /**
     * 校验权限
     *
     * @param activity
     * @param permission
     * @return
     */
    public boolean verifyPermission(Activity activity, String permission) {
        if (null == activity || TextUtils.isEmpty(permission)) {
            return false;
        }
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {
            int grand = ActivityCompat.checkSelfPermission(activity, permission);
            if (grand != PermissionChecker.PERMISSION_GRANTED) {
                return false;
            }
            return true;
        } else {
            return true;
        }
    }

    /**
     * 判断是否勾选禁止后不再询问
     *
     * @param activity
     * @param permission
     * @return
     */
    public boolean shouldShowRequestPermission(Activity activity, String permission) {
        if (null == activity || TextUtils.isEmpty(permission)) {
            return false;
        }
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {
            return ActivityCompat.shouldShowRequestPermissionRationale(activity, permission);
        } else {
            return true;
        }
    }

    public PermissionUtil onCallback(PermissionCallback callback) {
        this.permissionCallback = callback;
        return this;

    }


    /**
     * 回调接口
     */
    public interface PermissionCallback {
        void onGranted(List<String> actions);

        void onDenied(List<String> actions);
    }

    /**
     * 回调
     *
     * @param requestCode
     * @param permissions
     * @param grantResults
     */
    public void onRequestPermissionsResult(int requestCode, @NonNull final String[] permissions, @NonNull final int[] grantResults) {
        if (request_permission_code == requestCode) {
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    List<String> g = new ArrayList<>(permissions.length);
                    List<String> d = new ArrayList<>(permissions.length);
                    for (int j = 0; j < grantResults.length; j++) {
                        final String p = permissions[j];
                        if (grantResults[j] == PackageManager.PERMISSION_GRANTED) {
                            g.add(p);
                        } else if (grantResults[j] == PackageManager.PERMISSION_DENIED) {
                            d.add(p);
                        }
                    }
                    if (null != permissionCallback) {
                        permissionCallback.onGranted(g);
                        permissionCallback.onDenied(d);
                    }
                }
            });
        }
    }
}

XML文件

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/textView4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="76dp"
        android:layout_marginLeft="76dp"
        android:layout_marginTop="228dp"
        android:text="详细地址:"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/textView3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="144dp"
        android:layout_marginLeft="144dp"
        android:layout_marginTop="228dp"
        android:text="demo"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="76dp"
        android:layout_marginLeft="76dp"
        android:layout_marginTop="172dp"
        android:text="经纬度:"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="132dp"
        android:layout_marginLeft="132dp"
        android:layout_marginTop="172dp"
        android:text="demo"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="76dp"
        android:layout_marginLeft="76dp"
        android:layout_marginTop="300dp"
        android:text="获取经纬度和地址"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

三、调用百度地图SDK,显示当前定位

DemoApplication.java

import android.app.Application;
import com.baidu.mapapi.CoordType;
import com.baidu.mapapi.SDKInitializer;

public class DemoApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        //在使用SDK各组件之前初始化context信息,传入ApplicationContext
        SDKInitializer.initialize(this);
        //自4.3.0起,百度地图SDK所有接口均支持百度坐标和国测局坐标,用此方法设置您使用的坐标类型.
        //包括BD09LL和GCJ02两种坐标,默认是BD09LL坐标。
        SDKInitializer.setCoordType(CoordType.BD09LL);
    }
}

MainActivity.java(加入百度地图后的代码)

import androidx.appcompat.app.AppCompatActivity;
import android.Manifest;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import com.baidu.location.BDAbstractLocationListener;
import com.baidu.location.BDLocation;
import com.baidu.location.LocationClient;
import com.baidu.location.LocationClientOption;
import com.baidu.mapapi.PermissionUtils;
import com.baidu.mapapi.map.BaiduMap;
import com.baidu.mapapi.map.MapStatus;
import com.baidu.mapapi.map.MapStatusUpdate;
import com.baidu.mapapi.map.MapStatusUpdateFactory;
import com.baidu.mapapi.map.MapView;
import com.baidu.mapapi.map.MyLocationData;
import com.baidu.mapapi.model.LatLng;

import java.util.List;

public class MainActivity extends AppCompatActivity {
    private TextView textView2;
    private TextView textView3;
    private Button button;
    private String address;
    double latitude;
    double longitude;
    public LocationClient mLocationClient = null;
    private MyLocationListener myListener = new MyLocationListener();

    private boolean isFirstLocate = true;
    private MapView mMapView = null;
    private BaiduMap mBaiduMap;
    //BDAbstractLocationListener为7.2版本新增的Abstract类型的监听接口
    //原有BDLocationListener接口暂时同步保留。具体介绍请参考后文第四步的说明
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //权限检测和申请工具类
        PermissionUtil.getInstance().onCallback(new PermissionUtil.PermissionCallback() {
            @Override
            public void onGranted(List<String> actions) {
                for (String action : actions) {
                    Log.e("TAG", String.format("onGranted: %s", action));
                }
            }

            @Override
            public void onDenied(List<String> actions) {
                for (String action : actions) {
                    Log.e("TAG", String.format("onGranted: %s", action));
                }
            }
        }).requestPermissions(this, new String[]{
                Manifest.permission.ACCESS_NETWORK_STATE,
                Manifest.permission.ACCESS_WIFI_STATE,
                Manifest.permission.ACCESS_FINE_LOCATION,
                Manifest.permission.ACCESS_COARSE_LOCATION,
                Manifest.permission.CHANGE_WIFI_STATE,
                Manifest.permission.WRITE_EXTERNAL_STORAGE,
                Manifest.permission.INTERNET
        });

        init();
        initLocationClient();
        setLocationClientOption();
        mMapView = (MapView) findViewById(R.id.bmapView);
        // 不显示缩放比例尺
        mMapView.showZoomControls(false);
        // 不显示百度地图Logo
        mMapView.removeViewAt(1);
        //百度地图
        mBaiduMap = mMapView.getMap();
        // 改变地图状态,使地图显示在恰当的缩放大小
        MapStatus mMapStatus = new MapStatus.Builder().zoom(15).build();
        MapStatusUpdate mMapStatusUpdate = MapStatusUpdateFactory.newMapStatus(mMapStatus);
        mBaiduMap.setMapStatus(mMapStatusUpdate);

        //获取地图控件引用
        mBaiduMap.setMyLocationEnabled(true);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mLocationClient.start();    //开始定位
                //mLocationClient为第二步初始化过的LocationClient对象
                //调用LocationClient的start()方法,便可发起定位请求
            }
        });
    }

    //绑定组件
    private void init(){
        textView2 = findViewById(R.id.textView2);
        textView3 = findViewById(R.id.textView3);
        button = findViewById(R.id.button);
    }

    /**
     * 初始化LocationClient类
     * 请在主线程中声明LocationClient类对象,该对象初始化需传入Context类型参数。
     * 推荐使用getApplicationConext()方法获取全进程有效的Context。
     */
    private void initLocationClient(){
        //定位监听器,一旦调用requestLocation()函数,就会触发MyLocationListener()
        mLocationClient = new LocationClient(getApplicationContext());
        //声明LocationClient类
        mLocationClient.registerLocationListener(myListener);
    }

    /**
     * 配置定位SDK参数
     * 通过参数配置,可选择定位模式、可设定返回经纬度坐标类型、可设定是单次定位还是连续定位。
     * 定位SDK所提供的定位模式包括三种:高精度、低功耗和仅用设备定位。开发者请根据自己的实际使用需求进行选择。
     *
     * 定位SDK能够返回三种坐标类型的经纬度(国内),分别是GCJ02(国测局坐标)、BD09(百度墨卡托坐标)和BD09ll(百度经纬度坐标)。
     * 如果开发者想利用定位SDK获得的经纬度直接在百度地图上标注,请选择坐标类型BD09ll。
     */
    private void setLocationClientOption(){
        LocationClientOption option = new LocationClientOption();
        option.setLocationMode(LocationClientOption.LocationMode.Hight_Accuracy);
        //可选,设置定位模式,默认高精度
        //LocationMode.Hight_Accuracy:高精度;
        //LocationMode. Battery_Saving:低功耗;
        //LocationMode. Device_Sensors:仅使用设备;

        option.setCoorType("bd09ll");
        //可选,设置返回经纬度坐标类型,默认GCJ02
        //GCJ02:国测局坐标;
        //BD09ll:百度经纬度坐标;
        //BD09:百度墨卡托坐标;
        //海外地区定位,无需设置坐标类型,统一返回WGS84类型坐标

        option.setScanSpan(1000);
        //可选,设置发起定位请求的间隔,int类型,单位ms
        //如果设置为0,则代表单次定位,即仅定位一次,默认为0
        //如果设置非0,需设置1000ms以上才有效

        option.setOpenGps(true);
        //可选,设置是否使用gps,默认false
        //使用高精度和仅用设备两种定位模式的,参数必须设置为true

        option.setLocationNotify(true);
        //可选,设置是否当GPS有效时按照1S/1次频率输出GPS结果,默认false

        option.setIgnoreKillProcess(false);
        //可选,定位SDK内部是一个service,并放到了独立进程。
        //设置是否在stop的时候杀死这个进程,默认(建议)不杀死,即setIgnoreKillProcess(true)

        option.SetIgnoreCacheException(false);
        //可选,设置是否收集Crash信息,默认收集,即参数为false

        option.setWifiCacheTimeOut(5*60*1000);
        //可选,V7.2版本新增能力
        //如果设置了该接口,首次启动定位时,会先判断当前Wi-Fi是否超出有效期,若超出有效期,会先重新扫描Wi-Fi,然后定位

        option.setEnableSimulateGps(false);
        //可选,设置是否需要过滤GPS仿真结果,默认需要,即参数为false

        option.setNeedNewVersionRgc(true);
        //可选,设置是否需要最新版本的地址信息。默认需要,即参数为true

        option.setIsNeedAddress(true);
        //可选,是否需要地址信息,默认为不需要,即参数为false
        //如果开发者需要获得当前点的地址信息,此处必须为true

        option.setNeedNewVersionRgc(true);
        //可选,设置是否需要最新版本的地址信息。默认需要,即参数为true

        mLocationClient.setLocOption(option);
        //mLocationClient为第二步初始化过的LocationClient对象
        //需将配置好的LocationClientOption对象,通过setLocOption方法传递给LocationClient对象使用
        //更多LocationClientOption的配置,请参照类参考中LocationClientOption类的详细说明
    }

    /**
     * 实现BDAbstractLocationListener接口
     * Android定位SDK自V7.2版本起,对外提供了Abstract类型的监听接口BDAbstractLocationListener,用于实现定位监听。
     */
    public class MyLocationListener extends BDAbstractLocationListener {
        @Override
        public void onReceiveLocation(BDLocation location){
            //mapView 销毁后不在处理新接收的位置
            if (location == null || mMapView == null){
                return;
            }
            //此处的BDLocation为定位结果信息类,通过它的各种get方法可获取定位相关的全部结果
            //以下只列举部分获取经纬度相关(常用)的结果信息
            //更多结果信息获取说明,请参照类参考中BDLocation类中的说明
            latitude = location.getLatitude();    //获取纬度信息
            longitude = location.getLongitude();    //获取经度信息
            float radius = location.getRadius();    //获取定位精度,默认值为0.0f
            String coorType = location.getCoorType();
            //获取经纬度坐标类型,以LocationClientOption中设置过的坐标类型为准
            int errorCode = location.getLocType();
            //获取定位类型、定位错误返回码,具体信息可参照类参考中BDLocation类中的说明
            address = location.getAddrStr();
            textView2.setText(longitude + ", " + latitude);
            textView3.setText(address);
            mLocationClient.stop();
            //mapView 销毁后不在处理新接收的位置
            if (location == null || mMapView == null){
                return;
            }
            MyLocationData locData = new MyLocationData.Builder()
                    .accuracy(location.getRadius())
                    // 此处设置开发者获取到的方向信息,顺时针0-360
                    .direction(location.getDirection()).latitude(location.getLatitude())
                    .longitude(location.getLongitude()).build();
            mBaiduMap.setMyLocationData(locData);

            navigateTo(location);
        }
    }

    /*移动到指定位置*/
    private void navigateTo(BDLocation location){
        LatLng ll = new LatLng(location.getLatitude(),location.getLongitude());
        MapStatusUpdate update = MapStatusUpdateFactory.newLatLng(ll);
        mBaiduMap.animateMapStatus(update);
        update = MapStatusUpdateFactory.zoomTo(25f);
        mBaiduMap.animateMapStatus(update);

        MyLocationData.Builder locationBuilder =
                new MyLocationData.Builder();
        locationBuilder.latitude(location.getLatitude());
        locationBuilder.longitude(location.getLongitude());
        MyLocationData locationData = locationBuilder.build();
        mBaiduMap.setMyLocationData(locationData);
    }

    @Override
    protected void onResume() {
        super.onResume();
        //在activity执行onResume时执行mMapView. onResume (),实现地图生命周期管理
        mMapView.onResume();
    }
    @Override
    protected void onPause() {
        super.onPause();
        //在activity执行onPause时执行mMapView. onPause (),实现地图生命周期管理
        mMapView.onPause();
    }
    @Override
    protected void onDestroy() {
        mLocationClient.stop();
        mBaiduMap.setMyLocationEnabled(false);
        mMapView.onDestroy();
        mMapView = null;
        super.onDestroy();
        //在activity执行onDestroy时执行mMapView.onDestroy(),实现地图生命周期管理
    }
}

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.mycourse4">
    <!-- 这个权限用于进行网络定位-->
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <!-- 这个权限用于访问GPS定位-->
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <!-- 用于访问wifi网络信息,wifi信息会用于进行网络定位-->
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <!-- 获取运营商信息,用于支持提供运营商信息相关的接口-->
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <!-- 这个权限用于获取wifi的获取权限,wifi信息会用来进行网络定位-->
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
    <!-- 写入扩展存储,向扩展卡写入数据,用于写入离线定位数据-->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <!-- 访问网络,网络定位需要上网-->
    <uses-permission android:name="android.permission.INTERNET" />

    <application
        android:name="DemoApplication"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <meta-data
            android:name="com.baidu.lbsapi.API_KEY"
            android:value="YourAK" >
        </meta-data>


        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <service android:name="com.baidu.location.f"
            android:enabled="true"
            android:process=":remote"/>
    </application>

</manifest>

四、添加和风天气SDK,显示当前位置天气

注册和风天气账号

在应用管理创建一个安卓SDK应用

在这里插入图片描述

DemoApplication.java

import android.app.Application;
import com.baidu.mapapi.CoordType;
import com.baidu.mapapi.SDKInitializer;
import com.qweather.sdk.view.HeConfig;

public class DemoApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        //在使用SDK各组件之前初始化context信息,传入ApplicationContext
        SDKInitializer.initialize(this);
        //自4.3.0起,百度地图SDK所有接口均支持百度坐标和国测局坐标,用此方法设置您使用的坐标类型.
        //包括BD09LL和GCJ02两种坐标,默认是BD09LL坐标。
        SDKInitializer.setCoordType(CoordType.BD09LL);
        //和风天气
        HeConfig.init("PublicId", "PrivateKey");
        HeConfig.switchToDevService();
    }
}

添加了和风天气安卓SDK后的MainActivity.java

import androidx.appcompat.app.AppCompatActivity;
import android.Manifest;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import com.baidu.location.BDAbstractLocationListener;
import com.baidu.location.BDLocation;
import com.baidu.location.LocationClient;
import com.baidu.location.LocationClientOption;
import com.baidu.mapapi.PermissionUtils;
import com.baidu.mapapi.map.BaiduMap;
import com.baidu.mapapi.map.MapStatus;
import com.baidu.mapapi.map.MapStatusUpdate;
import com.baidu.mapapi.map.MapStatusUpdateFactory;
import com.baidu.mapapi.map.MapView;
import com.baidu.mapapi.map.MyLocationData;
import com.baidu.mapapi.model.LatLng;
import com.google.gson.Gson;
import com.qweather.sdk.bean.base.Code;
import com.qweather.sdk.bean.base.Lang;
import com.qweather.sdk.bean.base.Unit;
import com.qweather.sdk.bean.weather.WeatherNowBean;
import com.qweather.sdk.view.QWeather;

import java.util.List;

public class MainActivity extends AppCompatActivity {
    private TextView textView2;
    private TextView textView3;
    private TextView textView6;
    private Button button;
    private Button button2;
    private String address;
    double latitude;
    double longitude;
    public LocationClient mLocationClient = null;
    private MyLocationListener myListener = new MyLocationListener();

    private boolean isFirstLocate = true;
    private MapView mMapView = null;
    private BaiduMap mBaiduMap;
    //BDAbstractLocationListener为7.2版本新增的Abstract类型的监听接口
    //原有BDLocationListener接口暂时同步保留。具体介绍请参考后文第四步的说明
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //权限检测和申请工具类
        PermissionUtil.getInstance().onCallback(new PermissionUtil.PermissionCallback() {
            @Override
            public void onGranted(List<String> actions) {
                for (String action : actions) {
                    Log.e("TAG", String.format("onGranted: %s", action));
                }
            }

            @Override
            public void onDenied(List<String> actions) {
                for (String action : actions) {
                    Log.e("TAG", String.format("onGranted: %s", action));
                }
            }
        }).requestPermissions(this, new String[]{
                Manifest.permission.ACCESS_NETWORK_STATE,
                Manifest.permission.ACCESS_WIFI_STATE,
                Manifest.permission.ACCESS_FINE_LOCATION,
                Manifest.permission.ACCESS_COARSE_LOCATION,
                Manifest.permission.CHANGE_WIFI_STATE,
                Manifest.permission.WRITE_EXTERNAL_STORAGE,
                Manifest.permission.INTERNET
        });

        init();
        initLocationClient();
        setLocationClientOption();
        mMapView = (MapView) findViewById(R.id.bmapView);
        // 不显示缩放比例尺
        mMapView.showZoomControls(false);
        // 不显示百度地图Logo
        mMapView.removeViewAt(1);
        //百度地图
        mBaiduMap = mMapView.getMap();
        // 改变地图状态,使地图显示在恰当的缩放大小
        MapStatus mMapStatus = new MapStatus.Builder().zoom(15).build();
        MapStatusUpdate mMapStatusUpdate = MapStatusUpdateFactory.newMapStatus(mMapStatus);
        mBaiduMap.setMapStatus(mMapStatusUpdate);

        //获取地图控件引用
        mBaiduMap.setMyLocationEnabled(true);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mLocationClient.start();    //开始定位
                //mLocationClient为第二步初始化过的LocationClient对象
                //调用LocationClient的start()方法,便可发起定位请求
            }
        });

        //和风天气
        button2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                /**
                 * 实况天气数据
                 * @param location 所查询的地区,可通过该地区名称、ID、IP和经纬度进行查询经纬度格式:经度,纬度
                 *                 (英文,分隔,十进制格式,北纬东经为正,南纬西经为负)
                 * @param lang     (选填)多语言,可以不使用该参数,默认为简体中文
                 * @param unit     (选填)单位选择,公制(m)或英制(i),默认为公制单位
                 * @param listener 网络访问结果回调
                 */
                QWeather.getWeatherNow(MainActivity.this, longitude+","+latitude, Lang.ZH_HANS, Unit.METRIC, new QWeather.OnResultWeatherNowListener() {
                    @Override
                    public void onError(Throwable e) {
                        Log.i("TAG", "getWeather onError: " + e);
                    }

                    @Override
                    public void onSuccess(WeatherNowBean weatherBean) {
                        Log.i("TAG", "getWeather onSuccess: " + new Gson().toJson(weatherBean));
                        //先判断返回的status是否正确,当status正确时获取数据,若status不正确,可查看status对应的Code值找到原因
                        if (Code.OK.getCode().equalsIgnoreCase(weatherBean.getCode())) {
                            WeatherNowBean.NowBaseBean now = weatherBean.getNow();
                            textView6.setText(now.getText()+" "+now.getTemp()+"ºC");
                        } else {
                            //在此查看返回数据失败的原因
                            String status = weatherBean.getCode();
                            Code code = Code.toEnum(status);
                            Log.i("TAG", "failed code: " + code);
                        }
                    }
                });
            }
        });
    }

    //绑定组件
    private void init(){
        textView2 = findViewById(R.id.textView2);
        textView3 = findViewById(R.id.textView3);
        textView6 = findViewById(R.id.textView6);
        button = findViewById(R.id.button);
        button2 = findViewById(R.id.button2);
    }

    /**
     * 初始化LocationClient类
     * 请在主线程中声明LocationClient类对象,该对象初始化需传入Context类型参数。
     * 推荐使用getApplicationConext()方法获取全进程有效的Context。
     */
    private void initLocationClient(){
        //定位监听器,一旦调用requestLocation()函数,就会触发MyLocationListener()
        mLocationClient = new LocationClient(getApplicationContext());
        //声明LocationClient类
        mLocationClient.registerLocationListener(myListener);
    }

    /**
     * 配置定位SDK参数
     * 通过参数配置,可选择定位模式、可设定返回经纬度坐标类型、可设定是单次定位还是连续定位。
     * 定位SDK所提供的定位模式包括三种:高精度、低功耗和仅用设备定位。开发者请根据自己的实际使用需求进行选择。
     *
     * 定位SDK能够返回三种坐标类型的经纬度(国内),分别是GCJ02(国测局坐标)、BD09(百度墨卡托坐标)和BD09ll(百度经纬度坐标)。
     * 如果开发者想利用定位SDK获得的经纬度直接在百度地图上标注,请选择坐标类型BD09ll。
     */
    private void setLocationClientOption(){
        LocationClientOption option = new LocationClientOption();
        option.setLocationMode(LocationClientOption.LocationMode.Hight_Accuracy);
        //可选,设置定位模式,默认高精度
        //LocationMode.Hight_Accuracy:高精度;
        //LocationMode. Battery_Saving:低功耗;
        //LocationMode. Device_Sensors:仅使用设备;

        option.setCoorType("bd09ll");
        //可选,设置返回经纬度坐标类型,默认GCJ02
        //GCJ02:国测局坐标;
        //BD09ll:百度经纬度坐标;
        //BD09:百度墨卡托坐标;
        //海外地区定位,无需设置坐标类型,统一返回WGS84类型坐标

        option.setScanSpan(1000);
        //可选,设置发起定位请求的间隔,int类型,单位ms
        //如果设置为0,则代表单次定位,即仅定位一次,默认为0
        //如果设置非0,需设置1000ms以上才有效

        option.setOpenGps(true);
        //可选,设置是否使用gps,默认false
        //使用高精度和仅用设备两种定位模式的,参数必须设置为true

        option.setLocationNotify(true);
        //可选,设置是否当GPS有效时按照1S/1次频率输出GPS结果,默认false

        option.setIgnoreKillProcess(false);
        //可选,定位SDK内部是一个service,并放到了独立进程。
        //设置是否在stop的时候杀死这个进程,默认(建议)不杀死,即setIgnoreKillProcess(true)

        option.SetIgnoreCacheException(false);
        //可选,设置是否收集Crash信息,默认收集,即参数为false

        option.setWifiCacheTimeOut(5*60*1000);
        //可选,V7.2版本新增能力
        //如果设置了该接口,首次启动定位时,会先判断当前Wi-Fi是否超出有效期,若超出有效期,会先重新扫描Wi-Fi,然后定位

        option.setEnableSimulateGps(false);
        //可选,设置是否需要过滤GPS仿真结果,默认需要,即参数为false

        option.setNeedNewVersionRgc(true);
        //可选,设置是否需要最新版本的地址信息。默认需要,即参数为true

        option.setIsNeedAddress(true);
        //可选,是否需要地址信息,默认为不需要,即参数为false
        //如果开发者需要获得当前点的地址信息,此处必须为true

        option.setNeedNewVersionRgc(true);
        //可选,设置是否需要最新版本的地址信息。默认需要,即参数为true

        mLocationClient.setLocOption(option);
        //mLocationClient为第二步初始化过的LocationClient对象
        //需将配置好的LocationClientOption对象,通过setLocOption方法传递给LocationClient对象使用
        //更多LocationClientOption的配置,请参照类参考中LocationClientOption类的详细说明
    }

    /**
     * 实现BDAbstractLocationListener接口
     * Android定位SDK自V7.2版本起,对外提供了Abstract类型的监听接口BDAbstractLocationListener,用于实现定位监听。
     */
    public class MyLocationListener extends BDAbstractLocationListener {
        @Override
        public void onReceiveLocation(BDLocation location){
            //mapView 销毁后不在处理新接收的位置
            if (location == null || mMapView == null){
                return;
            }
            //此处的BDLocation为定位结果信息类,通过它的各种get方法可获取定位相关的全部结果
            //以下只列举部分获取经纬度相关(常用)的结果信息
            //更多结果信息获取说明,请参照类参考中BDLocation类中的说明
            latitude = location.getLatitude();    //获取纬度信息
            longitude = location.getLongitude();    //获取经度信息
            float radius = location.getRadius();    //获取定位精度,默认值为0.0f
            String coorType = location.getCoorType();
            //获取经纬度坐标类型,以LocationClientOption中设置过的坐标类型为准
            int errorCode = location.getLocType();
            //获取定位类型、定位错误返回码,具体信息可参照类参考中BDLocation类中的说明
            address = location.getAddrStr();
            textView2.setText(longitude + ", " + latitude);
            textView3.setText(address);
            mLocationClient.stop();
            //mapView 销毁后不在处理新接收的位置
            if (location == null || mMapView == null){
                return;
            }
            MyLocationData locData = new MyLocationData.Builder()
                    .accuracy(location.getRadius())
                    // 此处设置开发者获取到的方向信息,顺时针0-360
                    .direction(location.getDirection()).latitude(location.getLatitude())
                    .longitude(location.getLongitude()).build();
            mBaiduMap.setMyLocationData(locData);

            navigateTo(location);
        }
    }

    /*移动到指定位置*/
    private void navigateTo(BDLocation location){
        LatLng ll = new LatLng(location.getLatitude(),location.getLongitude());
        MapStatusUpdate update = MapStatusUpdateFactory.newLatLng(ll);
        mBaiduMap.animateMapStatus(update);
        update = MapStatusUpdateFactory.zoomTo(25f);
        mBaiduMap.animateMapStatus(update);

        MyLocationData.Builder locationBuilder =
                new MyLocationData.Builder();
        locationBuilder.latitude(location.getLatitude());
        locationBuilder.longitude(location.getLongitude());
        MyLocationData locationData = locationBuilder.build();
        mBaiduMap.setMyLocationData(locationData);
    }

    @Override
    protected void onResume() {
        super.onResume();
        //在activity执行onResume时执行mMapView. onResume (),实现地图生命周期管理
        mMapView.onResume();
    }
    @Override
    protected void onPause() {
        super.onPause();
        //在activity执行onPause时执行mMapView. onPause (),实现地图生命周期管理
        mMapView.onPause();
    }
    @Override
    protected void onDestroy() {
        mLocationClient.stop();
        mBaiduMap.setMyLocationEnabled(false);
        mMapView.onDestroy();
        mMapView = null;
        super.onDestroy();
        //在activity执行onDestroy时执行mMapView.onDestroy(),实现地图生命周期管理
    }
}

bulid.gradle

dependencies {
    implementation fileTree(dir: "libs", include: ["*.jar"])
    implementation 'androidx.appcompat:appcompat:1.2.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
    implementation files('libs\\BaiduLBS_Android.jar')
    implementation files('libs\\QWeather_Public_Android_V4.2.jar')
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test.ext:junit:1.1.2'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
    implementation 'com.squareup.okhttp3:okhttp:4.3.0'
    implementation 'com.google.code.gson:gson:2.8.6'
}

xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/textView4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="20dp"
        android:layout_marginLeft="20dp"
        android:layout_marginTop="36dp"
        android:text="详细地址:"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/textView3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="92dp"
        android:layout_marginLeft="92dp"
        android:layout_marginTop="36dp"
        android:text="demo"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="20dp"
        android:layout_marginLeft="20dp"
        android:layout_marginTop="16dp"
        android:text="经纬度:"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="76dp"
        android:layout_marginLeft="76dp"
        android:layout_marginTop="16dp"
        android:text="demo"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <com.baidu.mapapi.map.MapView
        android:id="@+id/bmapView"
        android:layout_width="match_parent"
        android:layout_height="361dp"
        android:layout_marginTop="68dp"
        android:clickable="true"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="24dp"
        android:layout_marginLeft="24dp"
        android:layout_marginTop="440dp"
        android:text="获取经纬度和地址并定位"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/textView5"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="28dp"
        android:layout_marginLeft="28dp"
        android:layout_marginTop="28dp"
        android:text="当前位置天气:"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/button" />

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="28dp"
        android:layout_marginLeft="28dp"
        android:layout_marginTop="544dp"
        android:text="获取天气信息"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/textView6"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="128dp"
        android:layout_marginLeft="128dp"
        android:layout_marginTop="516dp"
        android:text="TextView"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

SDK

所有的SDK和so文件都在上面的百度网盘链接里,jar文件放在libs里面,记得右键add as Library。so文件放在jniLibs下对应文件夹下。

项目结构

在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

特立独行の猫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值