一、引言
我昨天写了《安卓应用开发学习:获取经纬度及地理位置描述信息》日志,今天再接再厉,记录一下跟着《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; // 用于统计指定类型卫星数
@Override
protected 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, "需要打开定位功能才能查看卫星导航信息");
}
@Override
protected 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手机返回值为fused
String 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() {
@Override
public void onStarted() {}
@Override
public void onStopped() {}
@Override
public void onFirstFix(int ttffMillis) {}
// 在卫星导航系统的状态变更时触发
@Override
public 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=IRNSS
int 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() {
@Override
public void onLocationChanged(Location location) {
showLocation(location); // 显示定位结果文本
}
@Override
public void onProviderDisabled(String arg0) {
}
@Override
public void onProviderEnabled(String arg0) {
}
@Override
public void onStatusChanged(String arg0, int arg1, Bundle arg2) {
}
};
// 定义一个刷新任务,若无法定位则每隔一秒就尝试定位
private Runnable mRefresh = new Runnable() {
@Override
public void run() {
if (!isLocationEnable) {
initLocation(); // 初始化定位服务
mHandler.postDelayed(this, 1000);
}
}
};
@Override
protected 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() {
// 在卫星导航系统的状态变更时触发
@Override
public 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) { // 美国的GPS
item.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">
<TextView
android: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" />
<TextView
android: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.CompassView
android:id="@+id/cv_satellite"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<GridLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:layout_gravity="center_horizontal"
android:columnCount="5" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:orientation="vertical" >
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
app:srcCompat="@drawable/satellite_china"/>
<TextView
android: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>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:orientation="vertical" >
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
app:srcCompat="@drawable/satellite_america"/>
<TextView
android: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>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:orientation="vertical" >
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
app:srcCompat="@drawable/satellite_russia"/>
<TextView
android: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>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:orientation="vertical" >
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
app:srcCompat="@drawable/satellite_europe"/>
<TextView
android: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>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:orientation="vertical" >
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
app:srcCompat="@drawable/satellite_other"/>
<TextView
android: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方法,使得该视图无论竖屏还是横屏都保持正方形状
@Override
protected 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);
}
@Override
protected 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);
}
}