安卓应用开发学习:获取导航卫星信息

一、引言

我昨天写了《安卓应用开发学习:获取经纬度及地理位置描述信息》日志,今天再接再厉,记录一下跟着《Android App 开发进阶与项目实战》一书,实现获取导航卫星信息,并在手机上显示的功能的情况。先上实现后的在手机上搜索卫星信息的最终效果图。

 

二、书上相关内容

书上对全球卫星导航系统做了简单的介绍,说明了获取导航卫星信息的大致方法。

随教材提供了完整的代码,照着做做出来的效果如下:

三、我对代码的改进

做出来后,有一个问题就是在我的手机上定位类型显示的null,而教材上是卫星定位。这一问题经过研究发现是我的手机上返回的Fused定位,而不是作者书籍中返回的Gps定位,关于这个问题的解决办法,我已经在 《安卓应用开发学习:获取经纬度及地理位置描述信息》一文的末尾进行的补充,这里就不复述了。

另外,我在网上搜了一下类似的软件界面,不少界面还会显示各个类型的卫星的数量,我也想显示,就需要对代码进行研究和修改,来实现。

我的做法是,增加几个整数型变量(num_china, num_america, num_russia, num_europe, num_other)用于统计各个类型的卫星数量,在卫星导航系统的状态变更时触发的onSatelliteStatusChanged方法中,获取到卫星信息后,就对卫星类别进行统计,根据卫星类型代码值分别递增上面的整数型变量。类型代码的对照关系如下:

0=UNKNOWN; 1= GPS; 2=SBAS; 3=GLONASS; 4=QZSS; 5=BEIDOU; 6=GALILEO; 7=IRNSS

在完成搜星后,将整数型变量中的值更新到页面中,如此就得到了如下的最终效果图。

四、代码展示

最后上相关的关键代码。

1.搜星的Activity文件

src\main\java\......\SatelliteSphereActivity.java

import android.Manifest;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.pm.PackageManager;
import android.location.Criteria;
import android.location.GnssStatus;
import android.location.GpsSatellite;
import android.location.GpsStatus;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.widget.TextView;
import android.widget.Toast;import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;import com.bahamutjapp.bean.Satellite;
import com.bahamutjapp.util.DateUtil;
import com.bahamutjapp.util.SwitchUtil;
import com.bahamutjapp.widget.CompassView;import java.util.HashMap;
import java.util.Map;@SuppressLint("DefaultLocale")
public class SatelliteSphereActivity extends AppCompatActivity {private final static String TAG = "SatelliteSphereActivity";private Map<String, String> providerMap = new HashMap<>(); // 定位提供者映射private TextView tv_satellite; // 声明一个文本视图对象private CompassView cv_satellite; // 声明一个罗盘视图对象private Map<Integer, Satellite> mapSatellite = new HashMap<>(); // 导航卫星映射private LocationManager mLocationMgr; // 声明一个定位管理器对象private Criteria mCriteria = new Criteria(); // 声明一个定位准则对象private Handler mHandler = new Handler(Looper.myLooper()); // 声明一个处理器对象private boolean isLocationEnable = false; // 定位服务是否可用private String mLocationType = ""; // 定位类型。是卫星定位还是网络定位private TextView tv_china, tv_america, tv_russia, tv_europe, tv_other;  // 申明文本视图对象private int num_china, num_america, num_russia, num_europe, num_other;  // 用于统计指定类型卫星数@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_satellite_sphere);providerMap.put("gps", "卫星");providerMap.put("network", "网络");providerMap.put("fused", "融合");  // 我的手机经测试getBestProvider返回的fused,估添加了此行tv_satellite = findViewById(R.id.tv_satellite);  // 显示搜索到的卫星信息和经纬度信息cv_satellite = findViewById(R.id.cv_satellite);  // 罗盘视图对象显示卫星分布图tv_china = findViewById(R.id.tv_china);  // 显示中国北斗卫星数tv_america = findViewById(R.id.tv_america);  // 显示美国GPS卫星数tv_russia = findViewById(R.id.tv_russia);  // 显示俄罗斯格洛纳斯卫星数tv_europe = findViewById(R.id.tv_europe);  // 显示欧洲伽利略卫星数tv_other = findViewById(R.id.tv_other);  // 显示其它卫星数num_china = num_america = num_russia = num_europe = num_other = 0;  // 指定类型卫星数量初始化SwitchUtil.checkLocationIsOpen(this, "需要打开定位功能才能查看卫星导航信息");}@Overrideprotected void onResume() {super.onResume();mHandler.removeCallbacks(mRefresh); // 移除定位刷新任务initLocation(); // 初始化定位服务mHandler.postDelayed(mRefresh, 100); // 延迟100毫秒启动定位刷新任务}// 初始化定位服务private void initLocation() {// 从系统服务中获取定位管理器mLocationMgr = (LocationManager) getSystemService(Context.LOCATION_SERVICE);// 定位条件器Criteria设置// 设置定位精确度 Criteria.ACCURACY_COARSE表示粗略,Criteria.ACCURACY_FIN表示精细mCriteria.setAccuracy(Criteria.ACCURACY_FINE);mCriteria.setAltitudeRequired(true); // 设置是否需要海拔信息mCriteria.setBearingRequired(true); // 设置是否需要方位信息mCriteria.setCostAllowed(true); // 设置是否允许运营商收费mCriteria.setPowerRequirement(Criteria.POWER_LOW); // 设置对电源的需求// 获取定位管理器LocationManager的最佳定位提供者,本人手机oppo手机返回值为fusedString bestProvider = mLocationMgr.getBestProvider(mCriteria, true);if (mLocationMgr.isProviderEnabled(bestProvider)) {  // 定位提供者当前可用mLocationType = providerMap.get(bestProvider)+"定位";beginLocation(bestProvider); // 开始定位isLocationEnable = true;} else { // 定位提供者暂不可用isLocationEnable = false;}}// 设置定位结果文本private void showLocation(Location location) {if (location != null) {String desc = String.format("当前定位类型:%s\n定位时间:%s" +"\n经度:%f, 纬度:%f\n高度:%d米,  精度:%d米",mLocationType, DateUtil.formatDate(location.getTime()),location.getLongitude(), location.getLatitude(),Math.round(location.getAltitude()), Math.round(location.getAccuracy()));tv_satellite.setText(desc);} else {Log.d(TAG, "暂未获取到定位对象");}}// 开始定位private void beginLocation(String method) {// 检查当前设备是否已经开启了定位功能if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {Toast.makeText(this, "请授予定位权限并开启定位功能", Toast.LENGTH_SHORT).show();return;}// 设置定位管理器的位置变更监听器mLocationMgr.requestLocationUpdates(method, 300, 0, mLocationListener);// 获取最后一次成功定位的位置信息Location location = mLocationMgr.getLastKnownLocation(method);showLocation(location); // 显示定位结果文本if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {// 注册全球导航卫星系统的状态监听器mLocationMgr.registerGnssStatusCallback(mGnssStatusListener, null);} else {// 给定位管理器添加导航状态监听器mLocationMgr.addGpsStatusListener(mStatusListener);}}private String[] mSystemArray = new String[] {"UNKNOWN", "GPS", "SBAS","GLONASS", "QZSS", "BEIDOU", "GALILEO", "IRNSS"};  // 卫星类型列表@RequiresApi(api = Build.VERSION_CODES.N)// 定义一个GNSS状态监听器private GnssStatus.Callback mGnssStatusListener = new GnssStatus.Callback() {@Overridepublic void onStarted() {}@Overridepublic void onStopped() {}@Overridepublic void onFirstFix(int ttffMillis) {}// 在卫星导航系统的状态变更时触发@Overridepublic void onSatelliteStatusChanged(GnssStatus status) {mapSatellite.clear();  // 卫星列表重置num_china = num_america = num_russia = num_europe = num_other = 0;  // 卫星数量重置for (int i=0; i<status.getSatelliteCount(); i++) {Log.d(TAG, "i="+i+",getSvid="+status.getSvid(i)+",getConstellationType="+status.getConstellationType(i));Satellite item = new Satellite(); // 创建一个卫星信息对象item.signal = status.getCn0DbHz(i); // 获取卫星的信号item.elevation = status.getElevationDegrees(i); // 获取卫星的仰角item.azimuth = status.getAzimuthDegrees(i); // 获取卫星的方位角item.time = DateUtil.getNowDateTime(); // 获取当前时间// systemType与卫星类型对照: 0=UNKNOWN; 1= GPS; 2=SBAS; 3=GLONASS;//                         4=QZSS; 5=BEIDOU; 6=GALILEO; 7=IRNSSint systemType = status.getConstellationType(i); // 获取卫星的类型item.name = mSystemArray[systemType];mapSatellite.put(i, item);// 统计各类型卫星数量if (systemType == 1) {num_america += 1;} else if (systemType == 3) {num_russia += 1;} else if (systemType == 5) {num_china += 1;} else if (systemType == 6) {num_europe += 1;} else {num_other += 1;}}cv_satellite.setSatelliteMap(mapSatellite); // 设置卫星浑天仪// 显示给类型的卫星数tv_china.setText(String.valueOf(num_china));tv_america.setText(String.valueOf(num_america));tv_russia.setText(String.valueOf(num_russia));tv_europe.setText(String.valueOf(num_europe));tv_other.setText(String.valueOf(num_other));}};// 定义一个位置变更监听器private LocationListener mLocationListener = new LocationListener() {@Overridepublic void onLocationChanged(Location location) {showLocation(location); // 显示定位结果文本}@Overridepublic void onProviderDisabled(String arg0) {}@Overridepublic void onProviderEnabled(String arg0) {}@Overridepublic void onStatusChanged(String arg0, int arg1, Bundle arg2) {}};// 定义一个刷新任务,若无法定位则每隔一秒就尝试定位private Runnable mRefresh = new Runnable() {@Overridepublic void run() {if (!isLocationEnable) {initLocation(); // 初始化定位服务mHandler.postDelayed(this, 1000);}}};@Overrideprotected void onDestroy() {super.onDestroy();if (mLocationMgr != null) {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {// 注销全球导航卫星系统的状态监听器mLocationMgr.unregisterGnssStatusCallback(mGnssStatusListener);} else {// 移除定位管理器的导航状态监听器mLocationMgr.removeGpsStatusListener(mStatusListener);}// 移除定位管理器的位置变更监听器mLocationMgr.removeUpdates(mLocationListener);}}// 定义一个导航状态监听器private GpsStatus.Listener mStatusListener = new GpsStatus.Listener() {// 在卫星导航系统的状态变更时触发@Overridepublic void onGpsStatusChanged(int event) {if (ActivityCompat.checkSelfPermission(SatelliteSphereActivity.this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {// 获取卫星定位的状态信息GpsStatus gpsStatus = mLocationMgr.getGpsStatus(null);switch (event) {case GpsStatus.GPS_EVENT_SATELLITE_STATUS: // 周期性报告卫星状态// 得到所有收到的卫星的信息,包括 卫星的高度角、方位角、信噪比、和伪随机号(及卫星编号)Iterable<GpsSatellite> satellites = gpsStatus.getSatellites();for (GpsSatellite satellite : satellites) {/** satellite.getElevation(); //卫星的仰角 (卫星的高度)* satellite.getAzimuth(); //卫星的方位角* satellite.getSnr(); //卫星的信噪比* satellite.getPrn(); //卫星的伪随机码,可以认为就是卫星的编号* satellite.hasAlmanac(); //卫星是否有年历表* satellite.hasEphemeris(); //卫星是否有星历表* satellite.usedInFix(); //卫星是否被用于近期的GPS修正计算*/Satellite item = new Satellite(); // 创建一个卫星信息对象int prn_id = satellite.getPrn(); // 获取卫星的编号item.signal = Math.round(satellite.getSnr()); // 获取卫星的信号item.elevation = Math.round(satellite.getElevation()); // 获取卫星的仰角item.azimuth = Math.round(satellite.getAzimuth()); // 获取卫星的方位角item.time = DateUtil.getNowDateTime(); // 获取当前时间if (prn_id <= 51) { // 美国的GPSitem.name = "GPS";} else if (prn_id >= 201 && prn_id <= 235) { // 中国的北斗item.name = "BEIDOU";} else if (prn_id >= 65 && prn_id <= 96) { // 俄罗斯的格洛纳斯item.name = "GLONASS";} else if (prn_id >= 301 && prn_id <= 336) { // 欧洲的伽利略item.name = "GALILEO";} else {item.name = "未知";}Log.d(TAG, "id="+prn_id+", signal="+item.signal+", elevation="+item.elevation+", azimuth="+item.azimuth);mapSatellite.put(prn_id, item);}cv_satellite.setSatelliteMap(mapSatellite); // 设置卫星浑天仪case GpsStatus.GPS_EVENT_FIRST_FIX: // 首次卫星定位case GpsStatus.GPS_EVENT_STARTED: // 卫星导航服务开始case GpsStatus.GPS_EVENT_STOPPED: // 卫星导航服务停止default:break;}}}};}

2.Activity文件对应的xml文件

src\main\res\layout\activity_satellite_sphere.xml

注:改文件引用的图片文件放在src\main\res\layout\drawable-xhdpi文件夹下,图片文件是原书作者的劳动成果,不便提供。

<?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:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"tools:context=".SatelliteSphereActivity"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:paddingStart="10dp"android:paddingEnd="10dp"android:text="卫星浑天仪"android:textSize="24sp"android:textStyle="bold" /><TextViewandroid:id="@+id/tv_satellite"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="20dp"android:layout_marginBottom="10dp"android:paddingStart="10dp"android:paddingEnd="10dp"android:text="卫星信息"android:textSize="16sp" /><com.bahamutjapp.widget.CompassViewandroid:id="@+id/cv_satellite"android:layout_width="match_parent"android:layout_height="wrap_content" /><GridLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_margin="10dp"android:layout_gravity="center_horizontal"android:columnCount="5" ><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_margin="20dp"android:orientation="vertical" ><ImageViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"app:srcCompat="@drawable/satellite_china"/><TextViewandroid:id="@+id/tv_china"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:text="0"android:textSize="18sp"android:textStyle="bold" /></LinearLayout><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_margin="20dp"android:orientation="vertical" ><ImageViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"app:srcCompat="@drawable/satellite_america"/><TextViewandroid:id="@+id/tv_america"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:text="0"android:textSize="18sp"android:textStyle="bold" /></LinearLayout><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_margin="20dp"android:orientation="vertical" ><ImageViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"app:srcCompat="@drawable/satellite_russia"/><TextViewandroid:id="@+id/tv_russia"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:text="0"android:textSize="18sp"android:textStyle="bold" /></LinearLayout><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_margin="20dp"android:orientation="vertical" ><ImageViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"app:srcCompat="@drawable/satellite_europe"/><TextViewandroid:id="@+id/tv_europe"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:text="0"android:textSize="18sp"android:textStyle="bold" /></LinearLayout><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_margin="20dp"android:orientation="vertical" ><ImageViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"app:srcCompat="@drawable/satellite_other"/><TextViewandroid:id="@+id/tv_other"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:text="0"android:textSize="18sp"android:textStyle="bold" /></LinearLayout></GridLayout></LinearLayout>

3.自定义的罗盘组件,用于显示卫星图

src\main\java\......\widget\CompassView.java

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;import com.bahamutjapp.R;
import com.bahamutjapp.bean.Satellite;
import com.bahamutjapp.util.Utils;import java.util.HashMap;
import java.util.Map;public class CompassView extends View {private final static String TAG = "CompassView";private int mWidth; // 视图宽度private Paint mPaintLine; // 弧线的画笔private Paint mPaintText; // 文字的画笔private Paint mPaintAngle; // 刻度的画笔private Bitmap mCompassBg; // 背景罗盘的位图private Rect mRectSrc; // 位图的原始边界private Rect mRectDest; // 位图的目标边界private RectF mRectAngle; // 刻度的矩形边界private Bitmap mSatelliteChina; // 中国北斗卫星的图标private Bitmap mSatelliteAmerica; // 美国GPS卫星的图标private Bitmap mSatelliteRussia; // 俄罗斯格洛纳斯卫星的图标private Bitmap mSatelliteEurope; // 欧洲伽利略卫星的图标private Bitmap mSatelliteOther; // 其他国家卫星的图标private Map<Integer, Satellite> mapSatellite = new HashMap<>(); // 卫星分布映射private int mScaleLength = 25; // 刻度线的长度private float mBorder = 0.9f; // 边界的倍率,比如只在整个区域的90%内部绘图public CompassView(Context context) {this(context, null);}public CompassView(Context context, AttributeSet attr) {super(context, attr);// 以下初始化弧线的画笔mPaintLine = new Paint();mPaintLine.setAntiAlias(true); // 设置抗锯齿mPaintLine.setColor(Color.GREEN); // 设置画笔的颜色mPaintLine.setStrokeWidth(2); // 设置画笔的线宽mPaintLine.setStyle(Style.STROKE); // 设置画笔的类型。STROK表示空心,FILL表示实心// 以下初始化文字的画笔mPaintText = new Paint();mPaintText.setAntiAlias(true); // 设置抗锯齿mPaintText.setColor(Color.RED); // 设置画笔的颜色mPaintText.setStrokeWidth(1); // 设置画笔的线宽mPaintText.setTextSize(Utils.dip2px(context, 14));// 以下初始化刻度的画笔mPaintAngle = new Paint();mPaintAngle.setAntiAlias(true); // 设置抗锯齿mPaintAngle.setColor(Color.BLACK); // 设置画笔的颜色mPaintAngle.setStrokeWidth(1); // 设置画笔的线宽mPaintAngle.setTextSize(Utils.dip2px(context, 12));// 从资源图片中获取罗盘背景的位图mCompassBg = BitmapFactory.decodeResource(getResources(), R.drawable.compass_bg);// 根据位图的宽高创建位图的原始边界mRectSrc = new Rect(0, 0, mCompassBg.getWidth(), mCompassBg.getHeight());// 从资源图片中获取中国北斗卫星的图标mSatelliteChina = BitmapFactory.decodeResource(getResources(), R.drawable.satellite_china);// 从资源图片中获取美国GPS卫星的图标mSatelliteAmerica = BitmapFactory.decodeResource(getResources(), R.drawable.satellite_america);// 从资源图片中获取俄罗斯格洛纳斯卫星的图标mSatelliteRussia = BitmapFactory.decodeResource(getResources(), R.drawable.satellite_russia);// 从资源图片中获取欧洲伽利略卫星的图标mSatelliteEurope = BitmapFactory.decodeResource(getResources(), R.drawable.satellite_europe);// 从资源图片中获取其他国家卫星的图标mSatelliteOther = BitmapFactory.decodeResource(getResources(), R.drawable.satellite_other);}// 重写onMeasure方法,使得该视图无论竖屏还是横屏都保持正方形状@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {int width = View.MeasureSpec.getSize(widthMeasureSpec);int height = View.MeasureSpec.getSize(heightMeasureSpec);mWidth = getMeasuredWidth(); // 获取视图的实际宽度if (width < height) { // 宽度比高度小,则缩短高度使之与宽度一样长super.onMeasure(widthMeasureSpec, widthMeasureSpec);} else { // 宽度比高度大,则缩短宽度使之与高度一样长super.onMeasure(heightMeasureSpec, heightMeasureSpec);}// 根据视图的宽高创建位图的目标边界mRectDest = new Rect(0, 0, mWidth, mWidth);// 创建刻度的矩形边界mRectAngle = new RectF(mWidth / 10, mWidth / 10, mWidth * 9 / 10, mWidth * 9 / 10);Log.d(TAG, "mWidth=" + mWidth);}@Overrideprotected void dispatchDraw(Canvas canvas) {super.dispatchDraw(canvas);int radius = mWidth / 2;int margin = radius / 10;// 在画布上绘制罗盘背景canvas.drawBitmap(mCompassBg, mRectSrc, mRectDest, new Paint());// 以下在画布上绘制各种半径的圆圈canvas.drawCircle(radius, radius, radius * 3 / 10, mPaintLine);canvas.drawCircle(radius, radius, radius * 5 / 10, mPaintLine);canvas.drawCircle(radius, radius, radius * 7 / 10, mPaintLine);canvas.drawCircle(radius, radius, radius * 9 / 10, mPaintLine);// 在画布上绘制罗盘的中央垂直线canvas.drawLine(radius, margin, radius, mWidth - margin, mPaintLine);// 在画布上绘制罗盘的中央水平线canvas.drawLine(margin, radius, mWidth - margin, radius, mPaintLine);// 画罗盘的刻度for (int i = 0; i < 360; i += 30) {Path path = new Path(); // 创建一个路径对象path.addArc(mRectAngle, i - 3, i + 3); // 往路径添加圆弧int angle = (i + 90) % 360;// 在画布上绘制刻度文字canvas.drawTextOnPath("" + angle, path, 0, 0, mPaintAngle);// 在画布上绘制刻度线条canvas.drawLine(getXpos(radius, angle, radius * mBorder),getYpos(radius, angle, radius * mBorder),getXpos(radius, angle, (radius - mScaleLength) * mBorder),getYpos(radius, angle, (radius - mScaleLength) * mBorder),mPaintAngle);}// 画卫星分布图for (Map.Entry<Integer, Satellite> item_map : mapSatellite.entrySet()) {Satellite item = item_map.getValue();Bitmap bitmap;if (item.name.equals("BEIDOU")) { // 北斗卫星bitmap = mSatelliteChina;} else if (item.name.equals("GPS") || item.name.equals("SBAS")) { // GPS卫星bitmap = mSatelliteAmerica;} else if (item.name.equals("GLONASS")) { // 格洛纳斯卫星bitmap = mSatelliteRussia;} else if (item.name.equals("GALILEO")) { // 伽利略卫星bitmap = mSatelliteEurope;} else if (!item.name.equals("")) { // 其他卫星bitmap = mSatelliteOther;} else {continue;}float left = getXpos(radius, item.azimuth, radius * mBorder * getCos(item.elevation));float top = getYpos(radius, item.azimuth, radius * mBorder * getCos(item.elevation));// 在画布上绘制卫星图标canvas.drawBitmap(bitmap, left - bitmap.getWidth() / 2,top - bitmap.getHeight() / 2, new Paint());}canvas.drawText("北", radius - 15, margin - 15, mPaintText);}// 根据半径、角度、线长,计算该点的横坐标private float getXpos(int radius, float angle, double length) {return (float) (radius + getCos(angle) * length);}// 根据半径、角度、线长,计算该点的纵坐标private float getYpos(int radius, float angle, double length) {return (float) (radius + getSin(angle) * length);}// 获得指定角度的正弦值private double getSin(float angle) {return Math.sin(Math.PI * angle / 180.0);}// 获得指定角度的余弦值private double getCos(float angle) {return Math.cos(Math.PI * angle / 180.0);}// 设置卫星分布映射,用于卫星浑天仪public void setSatelliteMap(Map<Integer, Satellite> map) {mapSatellite = map;postInvalidate(); // 立即刷新视图(线程安全方式)}}

4.卫星信息的对象

src\main\java\......\bean\Satellite.java

public class Satellite {public String name; // 卫星导航系统的名称public float signal; // 卫星的信噪比(信号)public float elevation; // 卫星的仰角public float azimuth; // 卫星的方位角public String time; // 当前时间public Satellite() {name = "";signal = -1;elevation = -1;azimuth = -1;time = "";}
}

5.SwitchUtil.java文件(获取定位功能开关状态)

src\main\java\......\util\SwitchUtil.java

import android.content.Context;
import android.content.Intent;
import android.location.LocationManager;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.wifi.WifiManager;
import android.provider.Settings;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.widget.Toast;import java.lang.reflect.Method;public class SwitchUtil {private static final String TAG = "SwitchUtil";// 获取定位功能的开关状态public static boolean getLocationStatus(Context ctx) {// 从系统服务中获取定位管理器LocationManager lm = (LocationManager) ctx.getSystemService(Context.LOCATION_SERVICE);return lm.isProviderEnabled(LocationManager.GPS_PROVIDER);}// 检查定位功能是否打开,若未打开则跳到系统的定位功能设置页面public static void checkLocationIsOpen(Context ctx, String hint) {if (!getLocationStatus(ctx)) {Toast.makeText(ctx, hint, Toast.LENGTH_SHORT).show();Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);ctx.startActivity(intent);}}}

6. DateUtil.java文件(对日期数据进行格式化)

src\main\java\......\util\DateUtil.java

import android.annotation.SuppressLint;import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;@SuppressLint("SimpleDateFormat")
public class DateUtil {// 获取当前的日期时间public static String getNowDateTime() {SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");return sdf.format(new Date());}// 将长整型的时间数值格式化为日期时间字符串public static String formatDate(long time) {Date date = new Date(time);SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");return sdf.format(date);}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/860470.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Redis的持久化方式和注意点

redis持久篇 两种持久化技术&#xff1a; AOF日志和RDB快照 Redis默认会开启RBD快照 AOF:持久化只会记录写操作命令。 是一种日志&#xff0c;写入到文件&#xff0c;有相应的格式文本 就是 Redis 里的AOF(Append Only File)持久化功能&#xff0c;注意只会记录写操作命令…

决定马萨诸塞州版图的关键历史事件

决定马萨诸塞州版图的关键历史事件&#xff1a; 1. 早期探索与*民定居&#xff1a;17世纪初&#xff0c;英国清教徒为寻求宗教自由&#xff0c;乘坐“五月花号”到达新大陆&#xff0c;并于1620年在现在的普利茅斯建立了第一个永久性英国*民地。随后&#xff0c;更多的英国*民…

LKD-Net: Large Kernel Convolution Network for Single Image Dehazing

LKD-Net&#xff1a;用于单幅图像去噪的大型核卷积网络 摘要 基于深度卷积神经网络(CNN)的单幅图像去噪方法已经取得了很大的成功。以往的方法致力于通过增加网络的深度和宽度来提高网络的性能。目前的方法侧重于增加卷积核的大小&#xff0c;以受益于更大的接受野来增强其性能…

昇思25天学习打卡营第1天|新手上路

这里写自定义目录标题 打卡昇思MindSpore扫盲快速入门 打卡 昇思MindSpore扫盲 第一节基本是一个mindspore的科普扫盲。大概介绍一通mindspore的一些架构&#xff0c;feature&#xff0c;以及其对比于其他同类框架的优势。简单扫读了一遍大概有点印象直接跳过。 快速入门 这…

Vue 3 中处理文件上传和响应式更新

Vue 3 中处理文件上传和响应式更新 一、前言1.创建文件上传组件2.解释代码3.在主应用中使用文件上传组件4.总结 一、前言 在现代 web 开发中&#xff0c;文件上传是一个常见需求。本文将详细介绍如何在 Vue 3 中处理文件上传&#xff0c;并确保上传后的文件列表能够响应式更新…

如何把图片转换成pdf格式?图片转PDF方法分享

如何把图片转换成pdf格式&#xff1f;图片转换为PDF格式的重要性不言而喻。PDF文件不仅能够在各种操作系统和设备上保持一致的显示效果&#xff0c;还能确保图片内容的清晰度和质量不受损害。此外&#xff0c;PDF格式支持加密和权限设置&#xff0c;可以保护图片内容不被轻易篡…

FireFox 编译指南2024 Windows10篇-环境准备(一)

1. 引言 在开源浏览器项目中&#xff0c;Firefox因其高性能和灵活性而备受开发者青睐。为了在本地环境中编译和定制Firefox&#xff0c;开发者需要做好充分的环境准备工作。这不仅是编译成功的基础&#xff0c;也是后续调试、优化和二次开发的关键步骤。 编译Firefox是一个复…

深入剖析Tomcat(十二) 详解StandardContext

StandardContext是Context容器的一个标准实现&#xff0c;一般情况下&#xff0c;Tomcat都是使用StandardContext类来创建Context容器。前面讲过&#xff0c;Context容器代表了一个Web应用&#xff0c;Tomcat本身支持部署多个应用&#xff0c;相应的每个应用都会有一个Standard…

实用软件下载:ABBYY Finereader 15最新安装包及详细安装教程

数据表明FineReader PDF提供实用、简易的工具&#xff0c;将纸质文档和PDF结合起来&#xff0c;提高了数字工作场所的效率。我们都知道 即时背景识别:使不可搜索的PDF能够在工作中立即使用。值得一提的是文档转换更精准&#xff1a;OCR技术&#xff0c;它提高了PDF转换、布局保…

基于STM32的简易计算器proteus仿真设计(仿真+程序+设计报告+讲解视频)

基于STM32的简易计算器proteus仿真设计 讲解视频1.主要功能2. 仿真3. 程序4. 设计报告5. 资料清单&下载链接 基于STM32的简易计算器proteus仿真设计(仿真程序设计报告讲解视频&#xff09; 仿真图proteus 8.9 程序编译器&#xff1a;keil 5 编程语言&#xff1a;C语言 …

深入JVM:详解JIT即时编译器

文章目录 深入JVM&#xff1a;详解JIT即时编译器一、序言二、基础概念1、何为JIT即时编译2、热点代码 三、HotSpot内置的即时编译器1、C1编译器2、C2编译器3、分层编译3.1 协作流程 四、常见JIT优化技术1、方法内联2、逃逸分析&#xff08;1&#xff09;同步锁消除&#xff08;…

数据结构:栈和队列详解

栈 栈的概念 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶&#xff0c;另一端称为栈底。栈中的数据元素遵守先进后出LIFO&#xff08;Last In First Out&#xff09;的原则。大家可以理解为…

Day60 代码随想录打卡|回溯算法篇---组合

题目&#xff08;leecode T77&#xff09;&#xff1a; 给定两个整数 n 和 k&#xff0c;返回范围 [1, n] 中所有可能的 k 个数的组合。 你可以按 任何顺序 返回答案。 方法&#xff1a;本题最直观的解法是使用暴力for循环遍历法&#xff0c;根据k的大小定for循环的嵌套次数&…

Posix消息队列使用总结

Posix在线文档&#xff1a; The Single UNIX Specification, Version 2 (opengroup.org) Linux系统中提供了两种不同接口的消息队列&#xff1a; POSIX消息队列。POSIX为可移植的操作系统接口。System V消息队列。System V 是 AT&T 的第一个商业UNIX版本(UNIX System III)的…

[Python人工智能] 四十六.PyTorch入门 (1)环境搭建、神经网络普及和Torch基础知识

从本专栏开始,作者正式研究Python深度学习、神经网络及人工智能相关知识。前文讲解合如何利用keras和tensorflow构建基于注意力机制的CNN-BiLSTM-ATT-CRF模型,并实现中文实体识别研究。这篇文章将介绍PyTorch入门知识。前面我们的Python人工智能主要以TensorFlow和Keras为主,…

【Linux】进程间通信_4

文章目录 七、进程间通信1. 进程间通信分类systeam V共享内存消息队列信号量 未完待续 七、进程间通信 1. 进程间通信分类 systeam V共享内存 进程间通信的本质就是让不同进程看到同一份资源。而systeam V是通过让不同的进程经过页表映射到同一块内存空间&#xff08;操作系…

LED显示屏中什么是静态驱动?什么是扫描驱动?两者的区别是什么?

随着科技的飞速发展&#xff0c;LED显示屏作为现代信息显示技术的重要组成部分&#xff0c;正以其独特的优势引领着显示行业的革新。近日&#xff0c;LED显示屏市场呈现出蓬勃的发展态势&#xff0c;技术创新不断推动行业向前发展&#xff0c;让LED显示屏无论是在商场的广告牌、…

苏东坡传-读书笔记一

太守的官衙位于杭州中心&#xff0c;但是苏东坡却喜欢在较为富有诗意的地方办公。他往往在葛岭下面有十三间房子的寿星院办公&#xff0c;因为那里风光如画。看公文不在寒碧轩&#xff0c;就在雨奇堂。我们记得雨奇堂是从苏东坡西湖诗“山色空濛雨亦奇”而得名的。在这里&#…

04-Shell编程之正则表达式与文本处理器

4.1 正则表达式 4.1.1正则表达式概述 1.正则表达式的定义 正则表达式又称正规表达式&#xff0c;常规表达式。在代码中常简写为regex&#xff0c;regexp&#xff0c;或RE。正则表达式是使用一个字符来描述&#xff0c;匹配一系列符合某个句法规则的字符串&#xff0c;简单的…

【现代操作系统】什么是操作系统

1.前言 现代计算机系统由一个或多个处理器、主存、磁盘、打印机、键盘、鼠标、显示器、网络接口以及各种其他输入/输出设备组成。一般而言&#xff0c;现代计算机系统是一个复杂的系统。如果每位应用程序员都不得不掌握系统的所有细节&#xff0c;那就不可能再编写代码了。而且…