您的位置:首页 > 移动开发 > Android开发

android开发一个定位和轨迹播放的程序

2015-11-27 17:54 483 查看
最近很多的跑步app,大概功能就是点击“开始”就自动定位,然后记录位置,上传到服务端(也有不上传的),最后将运动的轨迹在地图上显示出来。因为开启gps一般是每3、5秒就记录一下当前的gps,为此需要一个本地数据库支持,可以将位置信息每隔3秒记录一次并保存到本地数据库,然后设置一个消息服务,定时10分钟后上传一次本地数据库到服务器端,同时可以删除本地数据以减少数据空间占用量。

以下是代码:

配置文件: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的话或很小,说明没有移动,可以不记录,以节省资源。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: