Android 天气APP(二)获取定位信息

本文详细介绍如何在Android天气应用中实现定位功能,包括使用ViewBinding简化代码、初始化定位SDK、检查并请求权限、以及展示定位结果等步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

上一篇:Android 天气APP(一)开发准备

新版-------------------

  我们接着往下更新,本篇文章要做的是获取定位信息显示在页面,那么首先我们需要修改一下activity_main.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/tv_address_detail"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

这里我给了TextView一个id,现在内容是Hello World!,当我们运行App时这里就会变成当前的地址。

一、使用ViewBinding

  在上一篇文章中,我们做了ViewBinding功能的开启,说到过我们不需要再写findViewById了,那么我们现在来使用一下ViewBinding,进入MainActivity,修改代码如下所示:

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;

import com.llw.goodweather.databinding.ActivityMainBinding;

public class MainActivity extends AppCompatActivity {
    
    private ActivityMainBinding binding;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = ActivityMainBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());
    }
}

  这里的ActivityMainBinding 就是我们开启ViewBinding功能之后,编译器根据xml布局去自动生成的编译时类,里面就写好了findViewById了,它的用法比较简单,先声明,再赋值,最后设置到setContentView(),注意这个类的命名方式,和xml的文件名称有关,我们的xml文件名称是activity_main.xml,所以生成的时候ActivityMain,再加上Binding。如果你这里爆红就说明你没有进行导包,鼠标点击爆红的地方,Alt + Enter,选择有import的哪一项就可以了,下面我们可以使用binding点出控件,如下图所示:

在这里插入图片描述
  这里点出来的控件也是遵守驼峰命名的,我们还可以知道这个控件是一个什么控件,ViewBinding的使用就是这么简单,当然了在不同的View上使用也会不同,碰到了,我们再讲。

二、初始化SDK

  在使用之前我们需要先对SDK进行初始化,定位SDK中除了那个jar包,还有一些so库文件,这些文件也需要正常加载到项目中,才能正常使用SDK功能,在app的build.gradle中添加如下代码:

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

添加位置如下图所示:

在这里插入图片描述

  然后Sync Now进行同步一下,就可以使用了,不过我们的初始化还没有完成,因为工信部提出了关于个人信息保护的要求,所以需要在使用SDK功能之前同意隐私政策,而我们又不想写重复的代码,那么就可以这样来做,我们自定义一个Application,在初始化的时候同意隐私政策即可。

com.llw.goodweather下新建一个WeatherApp类,里面的代码如下所示:

public class WeatherApp extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        //使用定位需要同意隐私合规政策
        LocationClient.setAgreePrivacy(true);
    }
}

要使这个类生效,我们需要在AndroidManifest.xml中进行配置,如下图所示:

在这里插入图片描述

三、初始化定位

  因为这个项目可能用到定位的功能不止一个Activity,所以我们可以将功能封装起来,我们在com.llw.goodweather包下新建一个location包,里面新建一个接口LocationCallback,代码如下:

/**
 * 定位接口
 */
public interface LocationCallback {
    /**
     * 接收定位
     * @param bdLocation 定位数据
     */
    void onReceiveLocation(BDLocation bdLocation);
}

然后通过在location包下新建一个自定义监听类MyLocationListener,代码如下:

/**
 * 自定义定位监听类
 */
public class MyLocationListener extends BDAbstractLocationListener {

    private final String TAG = MyLocationListener.class.getSimpleName();

    //定位回调
    private LocationCallback callback;

    //需要定位的页面调用此方法进行接口回调处理
    public void setCallback(LocationCallback callback) {
        this.callback = callback;
    }

    @Override
    public void onReceiveLocation(BDLocation bdLocation) {
        if (callback == null) {
            Log.e(TAG, "callback is Null!");
            return;
        }
        callback.onReceiveLocation(bdLocation);
    }
}

  这里我们将百度SDK定位的定位结果返回工程抽离出来,用接口回调的方式,减少Activity使用时的成本,哪里使用就哪里实现接口接口。

  那么我们现在要在MainActivity中使用要怎么做呢?在MainActivity中新增一个初始化定位的方法,代码如下所示:

	public LocationClient mLocationClient = null;
    private final MyLocationListener myListener = new MyLocationListener();
	
	/**
     * 初始化定位
     */
    private void initLocation() {
        try {
            mLocationClient = new LocationClient(getApplicationContext());
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (mLocationClient != null) {
            myListener.setCallback(this);
            //注册定位监听
            mLocationClient.registerLocationListener(myListener);
            LocationClientOption option = new LocationClientOption();
            //如果开发者需要获得当前点的地址信息,此处必须为true
            option.setIsNeedAddress(true);
            //可选,设置是否需要最新版本的地址信息。默认不需要,即参数为false
            option.setNeedNewVersionRgc(true);
            //需将配置好的LocationClientOption对象,通过setLocOption方法传递给LocationClient对象使用
            mLocationClient.setLocOption(option);
        }
    }

  不出意外的话你会有一个地方报错,就是this,这里就是我上面提到的你需要实现,重写自己的方法,有一个快捷的方式,鼠标点击这个this,使用Alt + Enter出现一个弹窗,这里选择第四项,如下图所示:

在这里插入图片描述

回车后你会发现多了一个onReceiveLocation()方法,代码如下:

    @Override
    public void onReceiveLocation(BDLocation bdLocation) {
        
    }

我们可以在这里面通过bdLocation得到一些需要的信息,例如:

	@Override
    public void onReceiveLocation(BDLocation bdLocation) {
        double latitude = bdLocation.getLatitude();    //获取纬度信息
        double longitude = bdLocation.getLongitude();    //获取经度信息
        float radius = bdLocation.getRadius();    //获取定位精度,默认值为0.0f
        String coorType = bdLocation.getCoorType();
        //获取经纬度坐标类型,以LocationClientOption中设置过的坐标类型为准
        int errorCode = bdLocation.getLocType();//161  表示网络定位结果
        //获取定位类型、定位错误返回码,具体信息可参照类参考中BDLocation类中的说明
        String addr = bdLocation.getAddrStr();    //获取详细地址信息
        String country = bdLocation.getCountry();    //获取国家
        String province = bdLocation.getProvince();    //获取省份
        String city = bdLocation.getCity();    //获取城市
        String district = bdLocation.getDistrict();    //获取区县
        String street = bdLocation.getStreet();    //获取街道信息
        String locationDescribe = bdLocation.getLocationDescribe();    //获取位置描述信息
        binding.tvAddressDetail.setText(addr);//设置文本显示
    }

  这里我们可以获取到的信息我简单列举了一些,然后我们设置了binding.tvAddressDetail.setText(addr);,这样如果我们定位成功,那么TextView就会显示当前的地址内容。

现在初始化定位已经写好了,那么下面需要写一个方法来启动定位,在MainActivity中新增如下方法代码:

	private void startLocation() {
        if (mLocationClient != null) {
            mLocationClient.start();
        }
    }

四、检查和请求权限

  要能够启动定位,需要请求权限。在做权限请求之前,我们需要先想清楚业务逻辑,首先我们要请求那些权限、其次要检查Android版本、最后如果权限通过了则不要重复请求,先声明一些变量。

	//权限数组
    private final String[] permissions = {Manifest.permission.ACCESS_FINE_LOCATION};
    //请求权限意图
    private ActivityResultLauncher<String[]> requestPermissionIntent;

  这里我们通过意图的方式动态请求多个权限,这个意图是Activity Result API中的用法,这个组件也是Jetpack中的,意图可以做的事情是很多的,请求权限只是其中之一,我们先写一个方法用来实例化意图,在请求返回之后就启动定位,在MainActivity中新增方法,代码如下所示:

	private void registerIntent() {
        //请求权限意图
        requestPermissionIntent = registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), result -> {
            boolean fineLocation = Boolean.TRUE.equals(result.get(Manifest.permission.ACCESS_FINE_LOCATION));
            if (fineLocation) {
                //权限已经获取到,开始定位
                startLocation();
            }
        });
    }

  这个意图有一个特别的地方需要在Activity初始化之前进行注册,因此在这里我们需要在onCreate中调用,位置要注意一下,如下图所示:

在这里插入图片描述

下面我们一个请求权限的方法,代码如下:

	private void requestPermission() {
        //因为项目的最低版本API是23,所以肯定需要动态请求危险权限,只需要判断权限是否拥有即可
        if (checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            //开始权限请求
            requestPermissionIntent.launch(permissions);
            return;
        }
        //开始定位
        startLocation();
    }

  这里在请求权限之前进行了一个检查,如果有权限则就直接开始定位了。最后我们在onCreate()方法中进行调用,如下图所示:

在这里插入图片描述

下面运行一下吧,记得用手机真机运行,如下图所示:

在这里插入图片描述

五、文章源码

欢迎 StarFork

第二篇文章源码地址:GoodWeather-New-2

旧版-------------------

二、编写代码

1. 获取当前所在位置信息

先修改activity_main.xml文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:gravity="center"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
	<!--显示详细定位信息-->
    <TextView
        android:id="@+id/tv_address_detail"
        android:padding="20dp"
        android:gravity="center"
        android:textColor="#000"
        android:textSize="18sp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Hello World!" />

</LinearLayout>

① 绑定控件

然后进入到MainActivity.java
鼠标右键点击布局文件activity_main 选择Generate
在这里插入图片描述

在这里插入图片描述
现在就可以用这个插件,点击红色边框中的Generate ButterKnife Iniertions
在这里插入图片描述
然后Confirm提交即可
在这里插入图片描述

② Android版本判断

之前提到Android6.0之后有运行时权限这么一说,所以要先判断是什么版本。在这之前先写一个Toast工具类。
新建了一个utils包用于存放工具类。
在这里插入图片描述

工具类代码如下:

package com.llw.goodweather.utils;

import android.content.Context;
import android.widget.Toast;

/**
 * 消息提示工具类
 */
public class ToastUtils {
    public static void showLongToast(Context context, CharSequence llw) {
        Toast.makeText(context.getApplicationContext(), llw, Toast.LENGTH_LONG).show();
    }

    public static void showShortToast(Context context, CharSequence llw) {
        Toast.makeText(context.getApplicationContext(), llw, Toast.LENGTH_SHORT).show();
    }
}

然后在代码中做版本业务逻辑的判断。

	//权限判断
    private void permissionVersion(){
        if(Build.VERSION.SDK_INT >= 23){//6.0或6.0以上
            //动态权限申请
            
        }else {//6.0以下
            //发现只要权限在AndroidManifest.xml中注册过,均会认为该权限granted  提示一下即可
            ToastUtils.showShortToast(this,"你的版本在Android6.0以下,不需要动态申请权限。");
        }
    }

之后在onCreate方法中调用

	@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);

        permissionVersion();//权限判断
    }

③ 权限申请

	private RxPermissions rxPermissions;//权限请求框架
	@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);

        rxPermissions = new RxPermissions(this);//实例化这个权限请求框架,否则会报错
        permissionVersion();//权限判断

    }
	//动态权限申请
    private void permissionsRequest() {
        rxPermissions.request(Manifest.permission.ACCESS_FINE_LOCATION)
                .subscribe(granted -> {
                    if (granted) {//申请成功
                        //得到权限之后开始定位

                    } else {//申请失败
                        ToastUtils.showShortToast(this, "权限未开启");
                    }
                });
    }

接下来在 permissionVersion 方法里面进行权限的申请
在这里插入图片描述

这个思路就相当的清晰了,一环扣一环,这样写的好处是便于理解,千万不要把什么东西都往onCreate里面塞,那样不仅增加代码阅读难度,也会提高BUG出现的频率。

④ 初始化LocationClient类

请在主线程中声明LocationClient类对象,该对象初始化需传入Context类型参数。

	//定位器
    public LocationClient mLocationClient = null;
    private MyLocationListener myListener = new MyLocationListener();
	//开始定位
    private void startLocation() {
        //声明LocationClient类
        mLocationClient = new LocationClient(this);
        //注册监听函数
        mLocationClient.registerLocationListener(myListener);
        LocationClientOption option = new LocationClientOption();

        //如果开发者需要获得当前点的地址信息,此处必须为true
        option.setIsNeedAddress(true);
        //可选,设置是否需要最新版本的地址信息。默认不需要,即参数为false
        option.setNeedNewVersionRgc(true);
        //mLocationClient为第二步初始化过的LocationClient对象
        //需将配置好的LocationClientOption对象,通过setLocOption方法传递给LocationClient对象使用
        mLocationClient.setLocOption(option);
        //启动定位
        mLocationClient.start();

    }

这时,你会发现myListener会有红线报错,是因为我们没有实现这个接口,下面来实现,这个方法和onCreate是平级的,你只要是写在MainActivity的{}里面,想放那里就放那里

⑤ 实现BDAbstractLocationListener接口

	/**
     * 定位结果返回
     */
    private class MyLocationListener extends BDAbstractLocationListener {
        @Override
        public void onReceiveLocation(BDLocation location) {
            double latitude = location.getLatitude();    //获取纬度信息
            double longitude = location.getLongitude();    //获取经度信息
            float radius = location.getRadius();    //获取定位精度,默认值为0.0f
            String coorType = location.getCoorType();
            //获取经纬度坐标类型,以LocationClientOption中设置过的坐标类型为准
            int errorCode = location.getLocType();//161  表示网络定位结果
            //获取定位类型、定位错误返回码,具体信息可参照类参考中BDLocation类中的说明
            String addr = location.getAddrStr();    //获取详细地址信息
            String country = location.getCountry();    //获取国家
            String province = location.getProvince();    //获取省份
            String city = location.getCity();    //获取城市
            String district = location.getDistrict();    //获取区县
            String street = location.getStreet();    //获取街道信息
            String locationDescribe = location.getLocationDescribe();    //获取位置描述信息
            tvAddressDetail.setText(addr);//设置文本显示
        }
    }

⑥ 显示定位结果

permissionsRequest() 方法中得到权限后调用定位方法,定位得到数据后在监听器里返回详细地址。
在这里插入图片描述
运行一下,请运行在自己的手机上,别使用虚拟机和模拟器(PS: 如果你运行报错了,请把你的错误信息贴出来,我好判断是什么问题)

在这里插入图片描述
点击 仅使用期间允许或者始终允许 之后就可以得到定位地址了。
在这里插入图片描述
现在位置已经拿到了,接下来就是通过这个位置来查询当天的天气了。如果你运行之后没有拿到地址,并且你已经打开了手机的定位开关和网络连接。那么此时你肯定是用模拟器或者虚拟机运行的,定位SDK中不适配模拟器和虚拟机,所以请使用真机运行

源码地址:GoodWeather
欢迎 StarFork

下一篇:Android 天气APP(三)访问天气API与数据请求

<think>嗯,用户想了解如何配置和使用yum源。首先,我需要回忆一下关于yum源的基本知识。记得yum源是软件仓库,用来管理RPM包的安装和依赖关系。配置yum源通常涉及编辑.repo文件,这些文件位于/etc/yum.repos.d/目录下。还有可能涉及到本地源和网络源的配置。 根据用户提供的引用内容,引用[2]提到yum的配置文件分为main和repository部分,main在/etc/yum.conf,而repository在/etc/yum.repos.d/里的各个文件。所以配置的时候需要关注这两个部分。用户可能遇到的问题包括如何创建新的源文件,如何指向本地或网络路径,以及如何处理GPG检查。 用户的问题可能包括步骤不清晰,比如如何挂载ISO镜像来配置本地源。引用[3]中提到了创建local.repo文件,并指定baseurl为file:///路径。这时候需要确保挂载点正确,并且权限设置没问题。另外,可能需要禁用默认的网络源,避免冲突。 用户还可能关心如何测试配置后的yum源是否生效,比如运行yum clean all和yum makecache。此外,常见问题如无法找到包,可能和baseurl的配置错误有关,或者网络源不可达。需要检查URL是否正确,网络连接是否正常。 可能还需要解释不同的源类型,比如本地、网络(如阿里云、清华源),以及如何备份原有的配置文件,避免出错后恢复。引用[1]提到可以将默认文件移到/opt下或重命名,这样可以禁用默认源,避免干扰。 总结下来,回答的结构应该分步骤,包括备份、创建repo文件、配置内容、清理缓存,然后验证。同时,常见问题部分需要列出可能的问题和解决方法,如GPG检查、路径错误等。还要注意使用正确的格式,行内变量用$符号,独立公式用$$,不过这里可能数学公式不多,但需要确保LaTeX正确。</think>### 如何配置和使用yum源? #### 一、yum源的核心配置方法 1. **备份默认源** 操作前建议备份系统原有源配置: ```bash mv /etc/yum.repos.d/*.repo /opt/backup/ # 将默认源文件移动到备份目录 ``` 这是为了防止原有配置与新配置产生冲突[^1]。 2. **本地yum源配置** - **挂载镜像文件** 将CentOS镜像文件挂载到指定目录: ```bash mount -o loop /path/to/CentOS-ISO /mnt/cdrom ``` - **创建配置文件** 新建`/etc/yum.repos.d/local.repo`并写入: ```ini [local-base] name=Local-CentOS-Base baseurl=file:///mnt/cdrom gpgcheck=0 enabled=1 ``` 关键参数说明: - `baseurl`:本地路径使用`file://`协议头[^3] - `gpgcheck=0`表示跳过数字签名验证 3. **网络yum源配置** 以阿里云源为例,创建`/etc/yum.repos.d/aliyun.repo`: ```ini [aliyun-base] name=Aliyun-CentOS-Base baseurl=https://mirrors.aliyun.com/centos/$releasever/os/$basearch/ gpgcheck=1 gpgkey=https://mirrors.aliyun.com/centos/RPM-GPG-KEY-CentOS-7 enabled=1 ``` 注意:`$releasever`和`$basearch`会自动解析为系统版本和架构[^2] #### 、关键操作命令 1. **清理缓存并更新** ```bash yum clean all # 清除旧缓存 yum makecache # 生成新缓存 yum repolist all # 验证源状态 ``` 2. **典型使用场景** ```bash yum install httpd -y # 安装软件包 yum update # 更新所有软件 yum search python3 # 搜索软件包 ``` #### 三、常见问题排查 | 问题现象 | 解决方案 | |---------|----------| | `Could not resolve host` | 检查网络连接和`baseurl`地址 | | `Package not found` | 确认仓库是否包含该软件包版本 | | GPG签名校验失败 | 设置`gpgcheck=0`或导入正确密钥 | #### 四、进阶配置技巧 1. **多源优先级控制** 安装`yum-plugin-priorities`插件,在`.repo`文件中添加: ```ini priority=1 # 数字越小优先级越高 ``` 2. **仓库分组管理** 通过`[epel]`、`[docker]`等独立仓库配置实现分类管理
评论 186
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

初学者-Study

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

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

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

打赏作者

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

抵扣说明:

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

余额充值