您好,欢迎访问一九零五行业门户网

Android实现Service获取当前位置(GPS+基站)的方法

本文实例讲述了android实现service获取当前位置(gps+基站)的方法。分享给大家供大家参考。具体如下:
需求详情:
1)、service中每隔1秒执行一次定位操作(gps+基站)
2)、定位的结果实时显示在界面上(要求得到经度、纬度)
技术支持:
1)、获取经纬度
通过gps+基站获取经纬度,先通过gps来获取,如果为空改用基站进行获取–>gps+基站(基站获取支持联通、电信、移动)。
2)、实时获取经纬度
为了达到实时获取经纬度,需在后台启动获取经纬度的service,然后把经纬度数据通过广播发送出去,在需要的地方进行广播注册(比如在activity中注册广播,显示在界面中)–>涉及到service+broadcastreceiver+activity+thread等知识点。
备注:本文注重实践,如有看不懂的,先去巩固下知识点,可以去看看前面相关的几篇文章。
1、cellinfo实体类–>基站信息
package com.ljq.activity; /** * 基站信息 * * @author jiqinlin * */ public class cellinfo { /** 基站id,用来找到基站的位置 */ private int cellid; /** 移动国家码,共3位,中国为460,即imsi前3位 */ private string mobilecountrycode="460"; /** 移动网络码,共2位,在中国,移动的代码为00和02,联通的代码为01,电信的代码为03,即imsi第4~5位 */ private string mobilenetworkcode="0"; /** 地区区域码 */ private int locationareacode; /** 信号类型[选 gsm|cdma|wcdma] */ private string radiotype=""; public cellinfo() { } public int getcellid() { return cellid; } public void setcellid(int cellid) { this.cellid = cellid; } public string getmobilecountrycode() { return mobilecountrycode; } public void setmobilecountrycode(string mobilecountrycode) { this.mobilecountrycode = mobilecountrycode; } public string getmobilenetworkcode() { return mobilenetworkcode; } public void setmobilenetworkcode(string mobilenetworkcode) { this.mobilenetworkcode = mobilenetworkcode; } public int getlocationareacode() { return locationareacode; } public void setlocationareacode(int locationareacode) { this.locationareacode = locationareacode; } public string getradiotype() { return radiotype; } public void setradiotype(string radiotype) { this.radiotype = radiotype; } }
2、gps类–>gps封装类,用来获取经纬度
package com.ljq.activity; import android.content.context; import android.location.criteria; import android.location.location; import android.location.locationlistener; import android.location.locationmanager; import android.os.bundle; public class gps{ private location location = null; private locationmanager locationmanager = null; private context context = null; /** * 初始化 * * @param ctx */ public gps(context ctx) { context=ctx; locationmanager=(locationmanager)context.getsystemservice(context.location_service); location = locationmanager.getlastknownlocation(getprovider()); locationmanager.requestlocationupdates(locationmanager.gps_provider, 2000, 10, locationlistener); } // 获取location provider private string getprovider() { // 构建位置查询条件 criteria criteria = new criteria(); // 查询精度:高 criteria.setaccuracy(criteria.accuracy_fine); // 是否查询海拨:否 criteria.setaltituderequired(false); // 是否查询方位角 : 否 criteria.setbearingrequired(false); // 是否允许付费:是 criteria.setcostallowed(true); // 电量要求:低 criteria.setpowerrequirement(criteria.power_low); // 返回最合适的符合条件的provider,第2个参数为true说明 , 如果只有一个provider是有效的,则返回当前provider return locationmanager.getbestprovider(criteria, true); } private locationlistener locationlistener = new locationlistener() { // 位置发生改变后调用 public void onlocationchanged(location l) { if(l!=null){ location=l; } } // provider 被用户关闭后调用 public void onproviderdisabled(string provider) { location=null; } // provider 被用户开启后调用 public void onproviderenabled(string provider) { location l = locationmanager.getlastknownlocation(provider); if(l!=null){ location=l; } } // provider 状态变化时调用 public void onstatuschanged(string provider, int status, bundle extras) { } }; public location getlocation(){ return location; } public void closelocation(){ if(locationmanager!=null){ if(locationlistener!=null){ locationmanager.removeupdates(locationlistener); locationlistener=null; } locationmanager=null; } } }
3、gpsservice服务类
package com.ljq.activity; import java.util.arraylist; import android.app.service; import android.content.intent; import android.location.location; import android.os.ibinder; import android.util.log; public class gpsservice extends service { arraylist<cellinfo> cellids = null; private gps gps=null; private boolean threaddisable=false; private final static string tag=gpsservice.class.getsimplename(); @override public void oncreate() { super.oncreate(); gps=new gps(gpsservice.this); cellids=utiltool.init(gpsservice.this); new thread(new runnable(){ @override public void run() { while (!threaddisable) { try { thread.sleep(1000); } catch (interruptedexception e) { e.printstacktrace(); } if(gps!=null){ //当结束服务时gps为空 //获取经纬度 location location=gps.getlocation(); //如果gps无法获取经纬度,改用基站定位获取 if(location==null){ log.v(tag, "gps location null"); //2.根据基站信息获取经纬度 try { location = utiltool.callgear(gpsservice.this, cellids); } catch (exception e) { location=null; e.printstacktrace(); } if(location==null){ log.v(tag, "cell location null"); } } //发送广播 intent intent=new intent(); intent.putextra("lat", location==null?"":location.getlatitude()+""); intent.putextra("lon", location==null?"":location.getlongitude()+""); intent.setaction("com.ljq.activity.gpsservice"); sendbroadcast(intent); } } } }).start(); } @override public void ondestroy() { threaddisable=true; if(cellids!=null&&cellids.size()>0){ cellids=null; } if(gps!=null){ gps.closelocation(); gps=null; } super.ondestroy(); } @override public ibinder onbind(intent arg0) { return null; } }
4、gpsactivity–>在界面上实时显示经纬度数据
package com.ljq.activity; import android.app.activity; import android.content.broadcastreceiver; import android.content.context; import android.content.intent; import android.content.intentfilter; import android.location.location; import android.location.locationmanager; import android.os.bundle; import android.util.log; import android.widget.edittext; import android.widget.toast; public class gpsactivity extends activity { private double homelat=26.0673834d; //宿舍纬度 private double homelon=119.3119936d; //宿舍经度 private edittext edittext = null; private myreceiver receiver=null; private final static string tag=gpsactivity.class.getsimplename(); @override public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.main); edittext=(edittext)findviewbyid(r.id.edittext); //判断gps是否可用 log.i(tag, utiltool.isgpsenabled((locationmanager)getsystemservice(context.location_service))+""); if(!utiltool.isgpsenabled((locationmanager)getsystemservice(context.location_service))){ toast.maketext(this, "gsp当前已禁用,请在您的系统设置屏幕启动。", toast.length_long).show(); intent callgpssettingintent = new intent(android.provider.settings.action_location_source_settings); startactivity(callgpssettingintent); return; } //启动服务 startservice(new intent(this, gpsservice.class)); //注册广播 receiver=new myreceiver(); intentfilter filter=new intentfilter(); filter.addaction("com.ljq.activity.gpsservice"); registerreceiver(receiver, filter); } //获取广播数据 private class myreceiver extends broadcastreceiver{ @override public void onreceive(context context, intent intent) { bundle bundle=intent.getextras(); string lon=bundle.getstring("lon"); string lat=bundle.getstring("lat"); if(lon!=null&&!"".equals(lon)&&lat!=null&&!"".equals(lat)){ double distance=getdistance(double.parsedouble(lat), double.parsedouble(lon), homelat, homelon); edittext.settext("目前经纬度\n经度:"+lon+"\n纬度:"+lat+"\n离宿舍距离:"+java.lang.math.abs(distance)); }else{ edittext.settext("目前经纬度\n经度:"+lon+"\n纬度:"+lat); } } } @override protected void ondestroy() { //注销服务 unregisterreceiver(receiver); //结束服务,如果想让服务一直运行就注销此句 stopservice(new intent(this, gpsservice.class)); super.ondestroy(); } /** * 把经纬度换算成距离 * * @param lat1 开始纬度 * @param lon1 开始经度 * @param lat2 结束纬度 * @param lon2 结束经度 * @return */ private double getdistance(double lat1, double lon1, double lat2, double lon2) { float[] results = new float[1]; location.distancebetween(lat1, lon1, lat2, lon2, results); return results[0]; } }
5、utiltool–>工具类
package com.ljq.activity; import java.io.bytearrayoutputstream; import java.io.ioexception; import java.io.inputstream; import java.io.outputstream; import java.io.unsupportedencodingexception; import java.net.httpurlconnection; import java.net.malformedurlexception; import java.net.protocolexception; import java.net.url; import java.util.arraylist; import java.util.calendar; import java.util.list; import java.util.locale; import org.apache.http.client.clientprotocolexception; import org.json.jsonexception; import org.json.jsonobject; import android.content.context; import android.location.location; import android.location.locationmanager; import android.telephony.neighboringcellinfo; import android.telephony.telephonymanager; import android.telephony.cdma.cdmacelllocation; import android.telephony.gsm.gsmcelllocation; import android.util.log; import android.widget.toast; public class utiltool { public static boolean isgpsenabled(locationmanager locationmanager) { boolean isopengps = locationmanager.isproviderenabled(android.location.locationmanager.gps_provider); boolean isopennetwork = locationmanager.isproviderenabled(android.location.locationmanager.network_provider); if (isopengps || isopennetwork) { return true; } return false; } /** * 根据基站信息获取经纬度 * * 原理向http://www.google.com/loc/json发送http的post请求,根据google返回的结果获取经纬度 * * @param cellids * @return * @throws exception */ public static location callgear(context ctx, arraylist<cellinfo> cellids) throws exception { string result=""; jsonobject data=null; if (cellids == null||cellids.size()==0) { utiltool.alert(ctx, "cell request param null"); return null; }; try { result = utiltool.getresponseresult(ctx, "http://www.google.com/loc/json", cellids); if(result.length() <= 1) return null; data = new jsonobject(result); data = (jsonobject) data.get("location"); location loc = new location(locationmanager.network_provider); loc.setlatitude((double) data.get("latitude")); loc.setlongitude((double) data.get("longitude")); loc.setaccuracy(float.parsefloat(data.get("accuracy").tostring())); loc.settime(utiltool.getutctime()); return loc; } catch (jsonexception e) { return null; } catch (unsupportedencodingexception e) { e.printstacktrace(); } catch (clientprotocolexception e) { e.printstacktrace(); } catch (ioexception e) { e.printstacktrace(); } return null; } /** * 接收google返回的数据格式 * * 出参:{"location":{"latitude":26.0673834,"longitude":119.3119936, * "address":{"country":"中国","country_code":"cn","region":"福建省","city":"福州市", * "street":"五一中路","street_number":"128号"},"accuracy":935.0}, * "access_token":"2:xiu8yrsiffhuavrj:aj9k70vjmrwo_9_g"} * 请求路径:http://maps.google.cn/maps/geo?key=abcdefg&q=26.0673834,119.3119936 * * @param cellids * @return * @throws unsupportedencodingexception * @throws malformedurlexception * @throws ioexception * @throws protocolexception * @throws exception */ public static string getresponseresult(context ctx,string path, arraylist<cellinfo> cellinfos) throws unsupportedencodingexception, malformedurlexception, ioexception, protocolexception, exception { string result=""; log.i(ctx.getapplicationcontext().getclass().getsimplename(), "in param: "+getrequestparams(cellinfos)); inputstream instream=utiltool.sendpostrequest(path, getrequestparams(cellinfos), "utf-8"); if(instream!=null){ byte[] datas=utiltool.readinputstream(instream); if(datas!=null&&datas.length>0){ result=new string(datas, "utf-8"); //log.i(ctx.getclass().getsimplename(), "receive result:"+result);//服务器返回的结果信息 log.i(ctx.getapplicationcontext().getclass().getsimplename(), "google cell receive data result:"+result); }else{ log.i(ctx.getapplicationcontext().getclass().getsimplename(), "google cell receive data null"); } }else{ log.i(ctx.getapplicationcontext().getclass().getsimplename(), "google cell receive instream null"); } return result; } /** * 拼装json请求参数,拼装基站信息 * * 入参:{'version': '1.1.0','host': 'maps.google.com','home_mobile_country_code': 460, * 'home_mobile_network_code': 14136,'radio_type': 'cdma','request_address': true, * 'address_language': 'zh_cn','cell_towers':[{'cell_id': '12835','location_area_code': 6, * 'mobile_country_code': 460,'mobile_network_code': 14136,'age': 0}]} * @param cellinfos * @return */ public static string getrequestparams(list<cellinfo> cellinfos){ stringbuffer sb=new stringbuffer(""); sb.append("{"); if(cellinfos!=null&&cellinfos.size()>0){ sb.append("'version': '1.1.0',"); //google api 版本[必] sb.append("'host': 'maps.google.com',"); //服务器域名[必] sb.append("'home_mobile_country_code': "+cellinfos.get(0).getmobilecountrycode()+","); //移动用户所属国家代号[选 中国460] sb.append("'home_mobile_network_code': "+cellinfos.get(0).getmobilenetworkcode()+","); //移动系统号码[默认0] sb.append("'radio_type': '"+cellinfos.get(0).getradiotype()+"',"); //信号类型[选 gsm|cdma|wcdma] sb.append("'request_address': true,"); //是否返回数据[必] sb.append("'address_language': 'zh_cn',"); //反馈数据语言[选 中国 zh_cn] sb.append("'cell_towers':["); //移动基站参数对象[必] for(cellinfo cellinfo:cellinfos){ sb.append("{"); sb.append("'cell_id': '"+cellinfo.getcellid()+"',"); //基站id[必] sb.append("'location_area_code': "+cellinfo.getlocationareacode()+","); //地区区域码[必] sb.append("'mobile_country_code': "+cellinfo.getmobilecountrycode()+","); sb.append("'mobile_network_code': "+cellinfo.getmobilenetworkcode()+","); sb.append("'age': 0"); //使用好久的数据库[选 默认0表示使用最新的数据库] sb.append("},"); } sb.deletecharat(sb.length()-1); sb.append("]"); } sb.append("}"); return sb.tostring(); } /** * 获取utc时间 * * utc + 时区差 = 本地时间(北京为东八区) * * @return */ public static long getutctime() { //取得本地时间 calendar cal = calendar.getinstance(locale.china); //取得时间偏移量 int zoneoffset = cal.get(java.util.calendar.zone_offset); //取得夏令时差 int dstoffset = cal.get(java.util.calendar.dst_offset); //从本地时间里扣除这些差量,即可以取得utc时间 cal.add(java.util.calendar.millisecond, -(zoneoffset + dstoffset)); return cal.gettimeinmillis(); } /** * 初始化,记得放在oncreate()方法里初始化,获取基站信息 * * @return */ public static arraylist<cellinfo> init(context ctx) { arraylist<cellinfo> cellinfos = new arraylist<cellinfo>(); telephonymanager tm = (telephonymanager) ctx.getsystemservice(context.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(); alert(ctx, "imsi: "+imsi); //为了区分移动、联通还是电信,推荐使用imsi来判断(万不得己的情况下用getnetworktype()判断,比如imsi为空时) if(imsi!=null&&!"".equals(imsi)){ alert(ctx, "imsi"); if (imsi.startswith("46000") || imsi.startswith("46002")) {// 因为移动网络编号46000下的imsi已经用完,所以虚拟了一个46002编号,134/159号段使用了此编号 // 中国移动 mobile(cellinfos, tm); } else if (imsi.startswith("46001")) { // 中国联通 union(cellinfos, tm); } else if (imsi.startswith("46003")) { // 中国电信 cdma(cellinfos, tm); } }else{ alert(ctx, "type"); // 在中国,联通的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){ cdma(cellinfos, tm); } //移动(edge(2.75g)是gprs(2.5g)的升级版,速度比gprs要快。目前移动基本在国内升级普及edge,联通则在大城市部署edge。) else if(type == telephonymanager.network_type_edge || type == telephonymanager.network_type_gprs ){ mobile(cellinfos, 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){ union(cellinfos, tm); } } return cellinfos; } /** * 电信 * * @param cellinfos * @param tm */ private static void cdma(arraylist<cellinfo> cellinfos, 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"); cellinfos.add(info); //前面获取到的都是单个基站的信息,接下来再获取周围邻近基站信息以辅助通过基站定位的精准性 // 获得邻近基站信息 list<neighboringcellinfo> list = tm.getneighboringcellinfo(); int size = list.size(); for (int i = 0; i < size; i++) { cellinfo cell = new cellinfo(); cell.setcellid(list.get(i).getcid()); cell.setlocationareacode(location.getnetworkid()); cell.setmobilenetworkcode(string.valueof(location.getsystemid())); cell.setmobilecountrycode(tm.getnetworkoperator().substring(0, 3)); cell.setradiotype("cdma"); cellinfos.add(cell); } } /** * 移动 * * @param cellinfos * @param tm */ private static void mobile(arraylist<cellinfo> cellinfos, 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"); cellinfos.add(info); //前面获取到的都是单个基站的信息,接下来再获取周围邻近基站信息以辅助通过基站定位的精准性 // 获得邻近基站信息 list<neighboringcellinfo> list = tm.getneighboringcellinfo(); int size = list.size(); for (int i = 0; i < size; i++) { cellinfo cell = new cellinfo(); cell.setcellid(list.get(i).getcid()); cell.setlocationareacode(location.getlac()); cell.setmobilenetworkcode(tm.getnetworkoperator().substring(3, 5)); cell.setmobilecountrycode(tm.getnetworkoperator().substring(0, 3)); cell.setradiotype("gsm"); cellinfos.add(cell); } } /** * 联通 * * @param cellinfos * @param tm */ private static void union(arraylist<cellinfo> cellinfos, 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.setmobilenetworkcode(""); info.setmobilecountrycode(""); info.setradiotype("gsm"); cellinfos.add(info); //前面获取到的都是单个基站的信息,接下来再获取周围邻近基站信息以辅助通过基站定位的精准性 // 获得邻近基站信息 list<neighboringcellinfo> list = tm.getneighboringcellinfo(); int size = list.size(); for (int i = 0; i < size; i++) { cellinfo cell = new cellinfo(); cell.setcellid(list.get(i).getcid()); cell.setlocationareacode(location.getlac()); cell.setmobilenetworkcode(""); cell.setmobilecountrycode(""); cell.setradiotype("gsm"); cellinfos.add(cell); } } /** * 提示 * * @param ctx * @param msg */ public static void alert(context ctx,string msg){ toast.maketext(ctx, msg, toast.length_long).show(); } /** * 发送post请求,返回输入流 * * @param path 访问路径 * @param params json数据格式 * @param encoding 编码 * @return * @throws unsupportedencodingexception * @throws malformedurlexception * @throws ioexception * @throws protocolexception */ public static inputstream sendpostrequest(string path, string params, string encoding) throws unsupportedencodingexception, malformedurlexception, ioexception, protocolexception { byte[] data = params.getbytes(encoding); url url = new url(path); httpurlconnection conn = (httpurlconnection)url.openconnection(); conn.setrequestmethod("post"); conn.setdooutput(true); //application/x-javascript text/xml->xml数据 application/x-javascript->json对象 application/x-www-form-urlencoded->表单数据 conn.setrequestproperty("content-type", "application/x-javascript; charset="+ encoding); conn.setrequestproperty("content-length", string.valueof(data.length)); conn.setconnecttimeout(5 * 1000); outputstream outstream = conn.getoutputstream(); outstream.write(data); outstream.flush(); outstream.close(); if(conn.getresponsecode()==200) return conn.getinputstream(); return null; } /** * 发送get请求 * * @param path 请求路径 * @return * @throws exception */ public static string sendgetrequest(string path) throws exception { url url = new url(path); httpurlconnection conn = (httpurlconnection) url.openconnection(); conn.setconnecttimeout(5 * 1000); conn.setrequestmethod("get"); inputstream instream = conn.getinputstream(); byte[] data = readinputstream(instream); string result = new string(data, "utf-8"); return result; } /** * 从输入流中读取数据 * @param instream * @return * @throws exception */ public static byte[] readinputstream(inputstream instream) throws exception{ bytearrayoutputstream outstream = new bytearrayoutputstream(); byte[] buffer = new byte[1024]; int len = 0; while( (len = instream.read(buffer)) !=-1 ){ outstream.write(buffer, 0, len); } byte[] data = outstream.tobytearray();//网页的二进制数据 outstream.close(); instream.close(); return data; } }
6、main.xml–>布局文件
<?xml version="1.0" encoding="utf-8"?> <linearlayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <edittext android:layout_width="fill_parent" android:layout_height="wrap_content" android:cursorvisible="false" android:editable="false" android:id="@+id/edittext"/> </linearlayout>
7、清单文件
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.ljq.activity" android:versioncode="1" android:versionname="1.0"> <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name=".gpsactivity" 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:label="gps服务" android:name=".gpsservice" /> </application> <uses-sdk android:minsdkversion="7" /> <uses-permission android:name="android.permission.access_fine_location" /> <uses-permission android:name="android.permission.access_coarse_location" /> <uses-permission android:name="android.permission.internet" /> <uses-permission android:name="android.permission.read_phone_state" /> <uses-permission android:name="android.permission.access_wifi_state" /> </manifest>
效果如下:
希望本文所述对大家的android程序设计有所帮助。
更多android实现service获取当前位置(gps+基站)的方法。
其它类似信息

推荐信息