android开发一个定位和轨迹播放的程序
2015-11-27 17:54
483 查看
最近很多的跑步app,大概功能就是点击“开始”就自动定位,然后记录位置,上传到服务端(也有不上传的),最后将运动的轨迹在地图上显示出来。因为开启gps一般是每3、5秒就记录一下当前的gps,为此需要一个本地数据库支持,可以将位置信息每隔3秒记录一次并保存到本地数据库,然后设置一个消息服务,定时10分钟后上传一次本地数据库到服务器端,同时可以删除本地数据以减少数据空间占用量。
以下是代码:
配置文件:AndroidManifest.xml
主程序布局页activity_main.xml
主界面程序MainActivity.java
GpsServer.java
LbsService.java
BootCompletedReceiver.java
GpsUtil.java
PhoneUtil.java
关于地图轨迹的展示可以使用百度或高德的api实现 ,比较简单,就不贴代码了。另外在地位的时候,会经常出现跳点,或有时回到超点,这个可以使用位置计算,如果在移动过程中当前点和上一点距离为0的话或很小,说明没有移动,可以不记录,以节省资源。
以下是代码:
配置文件:AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.totlbs.app" > <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <uses-permission android:name="android.permission.SEND_SMS"></uses-permission> <uses-permission android:name="android.permission.RECEIVE_SMS"></uses-permission> <uses-permission android:name="android.permission.READ_SMS"></uses-permission> <uses-permission android:name="android.permission.WRITE_SMS"></uses-permission> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name="com.totlbs.app.MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <service android:name="com.totlbs.app.Service.GpsService"></service> <service android:name="com.totlbs.app.Service.LbsService"></service> <receiver android:name="com.totlbs.app.Receiver.BootCompletedReceiver"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED" /> </intent-filter> </receiver> </application> </manifest>
主程序布局页activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin" tools:context="com.totlbs.app.MainActivity"> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Start Service" android:id="@+id/button" android:layout_alignParentTop="true" android:layout_centerHorizontal="true" android:onClick="startService" /> </RelativeLayout>
主界面程序MainActivity.java
package com.totlbs.app; import android.content.Intent; import android.support.v7.app.ActionBarActivity; import android.os.Bundle; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; import com.totlbs.app.Service.GpsService; public class MainActivity extends ActionBarActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } public void startService(View view){ Intent newIntent = new Intent(MainActivity.this, GpsService.class); newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); //注意,必须添加这个标记,否则启动会失败 Log.i("GpsService", "Start Service"); startService(newIntent); } public void stopService(View view){ Intent newIntent = new Intent(MainActivity.this, GpsService.class); //newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); //注意,必须添加这个标记,否则启动会失败 Log.i("GpsService", "Stop Service"); stopService(newIntent); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } }
GpsServer.java
package com.totlbs.app.Service; import android.app.AlarmManager; import android.app.PendingIntent; import android.app.Service; import android.content.ContentResolver; import android.content.Intent; import android.os.Binder; import android.os.Handler; import android.os.IBinder; import android.util.Log; import com.totlbs.app.Mobile.SMSConstant; import com.totlbs.app.Mobile.SMSHandler; import com.totlbs.app.Mobile.SMSObserver; import com.totlbs.app.Receiver.BootCompletedReceiver; import java.io.DataOutputStream; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLEncoder; import java.util.Calendar; /** * Created by Administrator on 14-5-15. */ public class GpsService extends Service { private static final String TAG = "GpsService"; private SMSObserver mObserver; @Override public IBinder onBind(Intent intent) { Log.i(TAG, "gbs_onBind"); return null; } @Override public void onCreate() { Log.i(TAG, "gbs_onCreate"); Intent intent =new Intent(GpsService.this, BootCompletedReceiver.class); intent.setAction("com.totlbs.app.lbs.start"); PendingIntent sender=PendingIntent.getBroadcast(GpsService.this, 0, intent, 0); AlarmManager alarm=(AlarmManager)getSystemService(ALARM_SERVICE); alarm.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(),60*60*1000,sender); //开始短信监听 addSMSObserver(); super.onCreate(); } @Override public void onDestroy() { Log.i(TAG, "gbs_onDestroy"); Intent intent =new Intent(GpsService.this, BootCompletedReceiver.class); intent.setAction("com.totlbs.app.lbs.start"); PendingIntent sender=PendingIntent.getBroadcast(GpsService.this, 0, intent, 0); AlarmManager alarm=(AlarmManager)getSystemService(ALARM_SERVICE); alarm.cancel(sender); //删除短信监听 this.getContentResolver().unregisterContentObserver(mObserver); super.onDestroy(); System.exit(0); } @Override public int onStartCommand(Intent intent, int flags, int startId) { // TODO Auto-generated method stub Log.i(TAG, "gbs_onStartCommand"); return super.onStartCommand(intent, flags, startId); } public void addSMSObserver() { Log.i(TAG, "add a SMS observer. "); ContentResolver resolver = getContentResolver(); Handler handler = new SMSHandler(GpsService.this); mObserver = new SMSObserver(resolver, handler); resolver.registerContentObserver(SMSConstant.CONTENT_URI, true, mObserver); } }
LbsService.java
package com.totlbs.app.Service; import android.app.PendingIntent; import android.app.Service; import android.content.Context; import android.content.Intent; import android.location.LocationManager; import android.net.Uri; import android.os.Binder; import android.os.IBinder; import android.util.Log; import com.totlbs.app.Util.GpsUtil; import com.totlbs.app.Util.HttpUtil; import com.totlbs.app.Util.PhoneUtil; import java.io.DataOutputStream; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLEncoder; /** * Created by Administrator on 14-5-15. */ public class LbsService extends Service { private static final String TAG = "GpsService"; @Override public IBinder onBind(Intent intent) { Log.i(TAG, "lbs_onBind"); return null; } @Override public void onCreate() { Log.i(TAG, "lbs_onCreate"); super.onCreate(); } @Override public void onDestroy() { Log.i(TAG, "lbs_onDestroy"); super.onDestroy(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { // TODO Auto-generated method stub Log.i(TAG, "lbs_onStartCommand"); PhoneUtil.send(this); /* if(!isOPenGps(this)){ Log.i(TAG, "gps not open"); PhoneUtil.send(this); }else{ Log.i(TAG, "gps open"); GpsUtil gu=new GpsUtil(); gu.getLocation(this); } */ return super.onStartCommand(intent, flags, startId); } /** * 判断GPS是否开启,GPS或者AGPS开启一个就认为是开启的 * @param context * @return true 表示开启 */ public boolean isOPenGps(Context context) { LocationManager lm= (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); // 通过GPS卫星定位,定位级别可以精确到街(通过24颗卫星定位,在室外和空旷的地方定位准确、速度快) boolean gps = lm.isProviderEnabled(LocationManager.GPS_PROVIDER); // 通过WLAN或移动网络(3G/2G)确定的位置(也称作AGPS,辅助GPS定位。主要用于在室内或遮盖物(建筑群或茂密的深林等)密集的地方定位) //boolean network = lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER); if (gps) { return true; } return false; } }
BootCompletedReceiver.java
package com.totlbs.app.Receiver; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.util.Log; import com.totlbs.app.Service.GpsService; import com.totlbs.app.Service.LbsService; /** * Created by Administrator on 14-5-15. */ public class BootCompletedReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) { Intent newIntent = new Intent(context, GpsService.class); newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); //注意,必须添加这个标记,否则启动会失败 Log.i("GpsService", "Start Gps Service"); context.startService(newIntent); }else if(intent.getAction().equals("com.totlbs.app.lbs.start")){ Intent newIntent = new Intent(context, LbsService.class); newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); //注意,必须添加这个标记,否则启动会失败 Log.i("GpsService", "Start Lbs Service"); context.startService(newIntent); }else if(intent.getAction().equals("com.totlbs.app.lbs.stop")){ Intent newIntent = new Intent(context, LbsService.class); Log.i("GpsService", "Stop Lbs Service"); context.stopService(newIntent); } } }
GpsUtil.java
package com.totlbs.app.Util; import android.content.Context; import android.location.Criteria; import android.location.GpsSatellite; import android.location.GpsStatus; import android.location.Location; import android.location.LocationListener; import android.location.LocationManager; import android.location.LocationProvider; import android.os.Bundle; import android.util.Log; import java.util.Iterator; /** * Created by Administrator on 14-5-21. */ public class GpsUtil { private LocationManager lm; Location location; String bestProvider; boolean isget=false; String TAG="GpsUtil"; String deviceid; //位置监听 LocationListener locationListener=new LocationListener() { /** * 位置信息变化时触发 */ public void onLocationChanged(Location location) { send(location); } /** * GPS状态变化时触发 */ public void onStatusChanged(String provider, int status, Bundle extras) { switch (status) { //GPS状态为可见时 case LocationProvider.AVAILABLE: Log.i(TAG, "当前GPS状态为可见状态"); break; //GPS状态为服务区外时 case LocationProvider.OUT_OF_SERVICE: Log.i(TAG, "当前GPS状态为服务区外状态"); break; //GPS状态为暂停服务时 case LocationProvider.TEMPORARILY_UNAVAILABLE: Log.i(TAG, "当前GPS状态为暂停服务状态"); break; } } /** * GPS开启时触发 */ public void onProviderEnabled(String provider) { Location location=lm.getLastKnownLocation(provider); send(location); } /** * GPS禁用时触发 */ public void onProviderDisabled(String provider) { send(null); } }; //状态监听 GpsStatus.Listener listener = new GpsStatus.Listener() { public void onGpsStatusChanged(int event) { switch (event) { //第一次定位 case GpsStatus.GPS_EVENT_FIRST_FIX: Log.i(TAG, "第一次定位"); break; //卫星状态改变 case GpsStatus.GPS_EVENT_SATELLITE_STATUS: Log.i(TAG, "卫星状态改变"); //获取当前状态 GpsStatus gpsStatus=lm.getGpsStatus(null); //获取卫星颗数的默认最大值 int maxSatellites = gpsStatus.getMaxSatellites(); //创建一个迭代器保存所有卫星 Iterator<GpsSatellite> iters = gpsStatus.getSatellites().iterator(); int count = 0; while (iters.hasNext() && count <= maxSatellites) { GpsSatellite s = iters.next(); count++; } Log.i(TAG,"搜索到:"+count+"颗卫星"); break; //定位启动 case GpsStatus.GPS_EVENT_STARTED: Log.i(TAG, "定位启动"); break; //定位结束 case GpsStatus.GPS_EVENT_STOPPED: Log.i(TAG, "定位结束"); break; } }; }; public void getLocation(Context ctx){ deviceid=PhoneUtil.getDeviceId(ctx); lm=(LocationManager)ctx.getSystemService(Context.LOCATION_SERVICE); bestProvider = lm.getBestProvider(getCriteria(), true); lm.addGpsStatusListener(listener); //注意:此处更新准确度非常低,推荐在service里面启动一个Thread,在run中sleep(10000);然后执行handler.sendMessage(),更新位置 lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 10000, 10, locationListener); ///////////////////////////// new Thread(new Runnable(){ @Override public void run() { while (!isget) { try { Thread.sleep(3000); Log.i(TAG, "wait 3 seconds"); } catch (InterruptedException e) { e.printStackTrace(); } if(lm!=null) { //当结束服务时gps为空 // 获取经纬度 location = lm.getLastKnownLocation(bestProvider); //如果gps无法获取经纬度,改用基站定位获取 if (location == null) { Log.i(TAG, "gps location null"); }else { Log.i(TAG, "success get location"); send(location); isget=true; } } } } }).start(); } public void send(Location loc){ if(loc!=null) { Log.i(TAG, "时间:" + location.getTime()); Log.i(TAG, "经度:" + location.getLongitude()); Log.i(TAG, "纬度:" + location.getLatitude()); Log.i(TAG, "海拔:" + location.getAltitude()); new Thread() { public void run() { HttpUtil hu=new HttpUtil(); String pdata="deviceid="+deviceid+"&lng="+location.getLongitude()+"&lat="+ location.getLatitude()+"&t=gps"; hu.getHtml(Constant.LbsPostUrl, pdata, true, "utf-8"); } ; }.start(); } } /** * 返回查询条件 * @return */ private Criteria getCriteria(){ Criteria criteria=new Criteria(); //设置定位精确度 Criteria.ACCURACY_COARSE比较粗略,Criteria.ACCURACY_FINE则比较精细 criteria.setAccuracy(Criteria.ACCURACY_FINE); //设置是否要求速度 criteria.setSpeedRequired(false); // 设置是否允许运营商收费 criteria.setCostAllowed(false); //设置是否需要方位信息 criteria.setBearingRequired(false); //设置是否需要海拔信息 criteria.setAltitudeRequired(false); // 设置对电源的需求 criteria.setPowerRequirement(Criteria.POWER_LOW); return criteria; } }
PhoneUtil.java
package com.totlbs.app.Util; import android.content.Context; import android.location.Location; import android.telephony.NeighboringCellInfo; import android.telephony.TelephonyManager; import android.telephony.cdma.CdmaCellLocation; import android.telephony.gsm.GsmCellLocation; import android.util.Log; import java.util.ArrayList; import java.util.List; /** * Created by Administrator on 14-5-21. */ public class PhoneUtil { static String deviceid=""; static CellInfo cif=null; public static CellInfo getCellInfo(Context ctx){ TelephonyManager tm = (TelephonyManager) ctx.getSystemService(ctx.TELEPHONY_SERVICE); //网络制式 int type = tm.getNetworkType(); /** * 获取SIM卡的IMSI码 * SIM卡唯一标识:IMSI 国际移动用户识别码(IMSI:International Mobile Subscriber Identification Number)是区别移动用户的标志, * 储存在SIM卡中,可用于区别移动用户的有效信息。IMSI由MCC、MNC、MSIN组成,其中MCC为移动国家号码,由3位数字组成, * 唯一地识别移动客户所属的国家,我国为460;MNC为网络id,由2位数字组成, * 用于识别移动客户所归属的移动网络,中国移动为00,中国联通为01,中国电信为03;MSIN为移动客户识别码,采用等长11位数字构成。 * 唯一地识别国内GSM移动通信网中移动客户。所以要区分是移动还是联通,只需取得SIM卡中的MNC字段即可 */ String imsi = tm.getSubscriberId(); //为了区分移动、联通还是电信,推荐使用imsi来判断(万不得己的情况下用getNetworkType()判断,比如imsi为空时) if(imsi!=null&&!"".equals(imsi)){ if (imsi.startsWith("46000") || imsi.startsWith("46002")) {// 因为移动网络编号46000下的IMSI已经用完,所以虚拟了一个46002编号,134/159号段使用了此编号 // 中国移动 return mobile(tm); } else if (imsi.startsWith("46001")) { // 中国联通 return union(tm); } else if (imsi.startsWith("46003")) { // 中国电信 return cdma(tm); } }else{ // 在中国,联通的3G为UMTS或HSDPA,电信的3G为EVDO // 在中国,移动的2G是EGDE,联通的2G为GPRS,电信的2G为CDMA // String OperatorName = tm.getNetworkOperatorName(); //中国电信 if (type == TelephonyManager.NETWORK_TYPE_EVDO_A || type == TelephonyManager.NETWORK_TYPE_EVDO_0 || type == TelephonyManager.NETWORK_TYPE_CDMA || type ==TelephonyManager.NETWORK_TYPE_1xRTT){ return cdma(tm); } //移动(EDGE(2.75G)是GPRS(2.5G)的升级版,速度比GPRS要快。目前移动基本在国内升级普及EDGE,联通则在大城市部署EDGE。) else if(type == TelephonyManager.NETWORK_TYPE_EDGE || type == TelephonyManager.NETWORK_TYPE_GPRS ){ return mobile(tm); } //联通(EDGE(2.75G)是GPRS(2.5G)的升级版,速度比GPRS要快。目前移动基本在国内升级普及EDGE,联通则在大城市部署EDGE。) else if(type == TelephonyManager.NETWORK_TYPE_GPRS ||type == TelephonyManager.NETWORK_TYPE_EDGE ||type == TelephonyManager.NETWORK_TYPE_UMTS ||type == TelephonyManager.NETWORK_TYPE_HSDPA){ return union(tm); } } return null; } public static void send(Context ctx){ deviceid=getDeviceId(ctx); cif=getCellInfo(ctx); if(cif!=null) { Log.i("cell","send cell info"); new Thread() { public void run() { HttpUtil hu = new HttpUtil(); String pdata="deviceid="+deviceid+"&mcc="+cif.getMobileCountryCode()+"&mnc="+cif.getMobileNetworkCode()+"&cid="+cif.getCellId()+"&lac="+cif.getLocationAreaCode()+"&t=phone"; Log.i("",pdata); hu.getHtml(Constant.LbsPostUrl, pdata, true, "utf-8"); } ; }.start(); }else{ Log.i("cell","cell info null"); } } public static String getDeviceId(Context ctx){ TelephonyManager tm = (TelephonyManager) ctx.getSystemService(ctx.TELEPHONY_SERVICE); return tm.getDeviceId(); } /** * 电信 * * @param tm */ private static CellInfo cdma(TelephonyManager tm) { CdmaCellLocation location = (CdmaCellLocation) tm.getCellLocation(); CellInfo info = new CellInfo(); info.setCellId(location.getBaseStationId()); info.setLocationAreaCode(location.getNetworkId()); info.setMobileNetworkCode(String.valueOf(location.getSystemId())); info.setMobileCountryCode(tm.getNetworkOperator().substring(0, 3)); info.setRadioType("cdma"); return info; } /** * 移动 * * @param tm */ private static CellInfo mobile(TelephonyManager tm) { GsmCellLocation location = (GsmCellLocation)tm.getCellLocation(); CellInfo info = new CellInfo(); info.setCellId(location.getCid()); info.setLocationAreaCode(location.getLac()); info.setMobileNetworkCode(tm.getNetworkOperator().substring(3, 5)); info.setMobileCountryCode(tm.getNetworkOperator().substring(0, 3)); info.setRadioType("gsm"); return info; } /** * 联通 * * @param tm */ private static CellInfo union(TelephonyManager tm) { GsmCellLocation location = (GsmCellLocation)tm.getCellLocation(); CellInfo info = new CellInfo(); //经过测试,获取联通数据以下两行必须去掉,否则会出现错误,错误类型为JSON Parsing Error info.setMobileNetworkCode(tm.getNetworkOperator().substring(3, 5)); info.setMobileCountryCode(tm.getNetworkOperator().substring(0, 3)); info.setCellId(location.getCid()); info.setLocationAreaCode(location.getLac()); info.setRadioType("gsm"); return info; } }
关于地图轨迹的展示可以使用百度或高德的api实现 ,比较简单,就不贴代码了。另外在地位的时候,会经常出现跳点,或有时回到超点,这个可以使用位置计算,如果在移动过程中当前点和上一点距离为0的话或很小,说明没有移动,可以不记录,以节省资源。
相关文章推荐
- android studio自定义类和方法的注释
- Mac无线连接adb 调试android程序
- Android——自定义通知栏使用
- Android中得Static关键字
- Android 集成支付宝SDK实现快捷支付--详解
- 完美调用系统相机拍照,获取图片进行压缩并本地保存
- android中drawable资源的解释及例子
- Android Studio 和 Gradle的那些事儿
- android项目自定义组合控件
- Error : cause android.compileSdkVersion is missing
- android代码添加:ProgressBar
- android 里面一些关于时间的组件
- Android五种数据传递方法汇总
- Android Studio项目整合PullToRefresh的问题记录
- android studio 导入 PullToRefresh
- AndroidL 预置APK
- Android自定义View实现验证码
- Android之ActionBar常用设计和使用总结
- 解决Android studio ERROR: 9-patch image D:\test\res\drawable-hdpi\sk.9.png malforme
- GROUP for class: org.gradle.api.publication.maven.internal.deployer.DefaultGroovyMavenDeployer