android 应用类APP开发小结——android Google map 小应用
首届Google暑期大学生博客分享大赛——2010 Andriod篇
做了一个小应用智能情景的切换,这个应用是学习android开发以来应用类开发的比较满意的一个。虽然它只有一个view 一个activity,但是却囊括了android的很多特性。借此机会,和大家分享一下这个小应用。
?
先上截图:
?
应用的主要功能是根据适当的情景(如地点,手机状态等)为用户自动的切换情景模式。
比方说:手机向上是铃音+震动,当开会时,将手机翻转,将自动切换成静音模式。
还可以根据经纬度,到达一个地方后自动切换成用户预先设置的情景模式。
(当然,由于没找到合适的经纬度换算工具,经纬度的判断目前只能是精确位置,不是范围值。
因此只能算是个学习的小应用了,实际的应用还有待完善啊。如果有高手知道的话,麻烦告诉我下。万分感谢)
?
-------------------------废话不多说开始代码部分-----------------------------------------------------
虽然是一个只有一个页面的小应用,但是
麻雀虽小,五脏俱全
这个应用的功能点主要有:
???? 改变情景模式
???? 实时获取地理位置
???? 实时判断手机重力状态
用到的技术包括:
1.android Google map的应用
2.Android组件的使用
??? Activity(MapActivity)
??? Service
??? Broadcastreceiver
3.Xml解析
4.文件存储
5.传感器使用
6.底层绘图
7.自定义view
?
由于使回头看代码,我就从简单的部分一步步介绍。
?
首先是权限问题,很多新手都犯了这个毛病,程序出错,往往是权限没有添加。
?这个应用需要网络连接的权限,因为Google map是实时更新的么。然后是GPS传感器关于地理位置的权限。最后需要存储用户的记录点,所以有文件读写的权限。
?
为了记录用户记录的情景地点,我使用了XML作为存储的标准,并将文件存在了SD卡上
XML解析
网络上有很详细的各种解析方式,我采用了其中的一种。如果想了解其他的请Google。。。。。
记录地点信息,我定义了一个POJO类
?当触发一定情景时只要发送一个Intent。广播接收器就可以接受到,然后执行相应代码
??
对于service我们只需要知道它的5个生命周期,然后在相应的周期中干我们需要的事情即可。
而启动一个service,和停止service也很简单
?
startService(new Intent(
??????????? ??? "cn.zucc.yoyo.ringmaster.RING_SERVICE2"));public class MapLocationOverlay extends Overlay { private Bitmap bubbleIcon, shadowIcon; private Bitmap bubbleVolume,bubbleVolumeOff,bubbleVibrate,bubbleVolumeeVibrate; private MapLocationViewer mapLocationViewer;private PaintinnerPaint, borderPaint, textPaint; private RecordLocation selectedMapLocation; private Handler mHandler; public void setinfowindow(Handler handler){ this.mHandler = handler; }public MapLocationOverlay(MapLocationViewermapLocationViewer) {this.mapLocationViewer = mapLocationViewer;bubbleIcon = BitmapFactory.decodeResource(mapLocationViewer.getResources(),R.drawable.bubble);bubbleVolume = BitmapFactory.decodeResource(mapLocationViewer.getResources(),R.drawable.bubble_volume);bubbleVolumeOff = BitmapFactory.decodeResource(mapLocationViewer.getResources(),R.drawable.bubble_volumeoff);bubbleVibrate = BitmapFactory.decodeResource(mapLocationViewer.getResources(),R.drawable.bubble_vibrate);bubbleVolumeeVibrate = BitmapFactory.decodeResource(mapLocationViewer.getResources(),R.drawable.bubble_volumevibrate);shadowIcon = BitmapFactory.decodeResource(mapLocationViewer.getResources(),R.drawable.shadow);}@Overridepublic boolean onTap(GeoPoint p, MapViewmapView) {// Store whether prior popup was displayed so we can call invalidate() & remove it if necessary.boolean isRemovePriorPopup = selectedMapLocation != null;// Next test whether a new popup should be displayedselectedMapLocation = getHitMapLocation(mapView,p);if ( isRemovePriorPopup || selectedMapLocation != null) {if(selectedMapLocation==null){//发送消息Message msg = mHandler.obtainMessage();msg.what = RingMaster.REFERSH_LOCATION;Bundle b = new Bundle();b.putInt("view",android.view.View.GONE);msg.setData(b);mHandler.sendMessage(msg);}else{//发送消息Message msg = mHandler.obtainMessage();msg.what = RingMaster.REFERSH_LOCATION;Bundle b = new Bundle();b.putString("location", selectedMapLocation.getLocation_Id());//b.putString("ringmode", selectedMapLocation.getLocation_ring());b.putDouble("latitude", selectedMapLocation.getLocation_latitude());b.putDouble("longitude", selectedMapLocation.getLocation_longitude());b.putInt("view", android.view.View.VISIBLE);msg.setData(b);mHandler.sendMessage(msg);mapView.getController().animateTo(p);mapView.invalidate();}}// Lastly return true if we handled this onTap()return selectedMapLocation != null;} @Overridepublic void draw(Canvas canvas, MapViewmapView, boolean shadow) { drawMapLocations(canvas, mapView, shadow); //drawInfoWindow(canvas, mapView, shadow); } private RecordLocation getHitMapLocation(MapViewmapView, GeoPointtapPoint) { // Track which MapLocation was hit...if any RecordLocation hitMapLocation = null; RectF hitTestRecr = new RectF();Point screenCoords = new Point(); Iterator<RecordLocation> iterator = mapLocationViewer.getMapLocations().iterator(); while(iterator.hasNext()) { RecordLocation testLocation = iterator.next(); // Translate the MapLocation's lat/long coordinates to screen coordinates mapView.getProjection().toPixels(testLocation.getPoint(), screenCoords); // Create a 'hit' testing Rectangle w/size and coordinates of our icon // Set the 'hit' testing Rectangle with the size and coordinates of our on screen icon hitTestRecr.set(-bubbleIcon.getWidth()*2,-bubbleIcon.getHeight()*2,bubbleIcon.getWidth()*2,0); hitTestRecr.offset(screenCoords.x,screenCoords.y); // Finally test for a match between our 'hit' Rectangle and the location clicked by the user mapView.getProjection().toPixels(tapPoint, screenCoords); if (hitTestRecr.contains(screenCoords.x,screenCoords.y)) { hitMapLocation = testLocation; break; } } // Lastly clear the newMouseSelection as it has now been processed tapPoint = null; return hitMapLocation; } private static final int VOLUME=1,VIBRATE=2,VOLUMEOFF=3,VOLUMEVIBRATE=4; private void drawMapLocations(Canvas canvas, MapViewmapView, boolean shadow) { if(mapLocationViewer.getMapLocations()!=null){ Iterator<RecordLocation> iterator = mapLocationViewer.getMapLocations().iterator(); Point screenCoords = new Point(); while(iterator.hasNext()) { RecordLocation location = iterator.next(); mapView.getProjection().toPixels(location.getPoint(), screenCoords); if (shadow) { // Only offset the shadow in the y-axis as the shadow is angled so the base is at x=0; canvas.drawBitmap(shadowIcon, screenCoords.x, screenCoords.y - shadowIcon.getHeight(),null); } else { switch(Integer.valueOf(location.getLocation_ring())){ case VOLUME: canvas.drawBitmap(bubbleVolume, screenCoords.x - bubbleVolume.getWidth()/2, screenCoords.y - bubbleVolume.getHeight(),null); break; case VIBRATE: canvas.drawBitmap(bubbleVibrate, screenCoords.x - bubbleVibrate.getWidth()/2, screenCoords.y - bubbleVibrate.getHeight(),null); break; case VOLUMEOFF: canvas.drawBitmap(bubbleVolumeOff, screenCoords.x - bubbleVolumeOff.getWidth()/2, screenCoords.y - bubbleVolumeOff.getHeight(),null); break; case VOLUMEVIBRATE: canvas.drawBitmap(bubbleVolumeeVibrate, screenCoords.x - bubbleVolumeeVibrate.getWidth()/2, screenCoords.y - bubbleVolumeeVibrate.getHeight(),null); break; default: canvas.drawBitmap(bubbleIcon, screenCoords.x - bubbleIcon.getWidth()/2, screenCoords.y - bubbleIcon.getHeight(),null); break; } } } } } public Paint getInnerPaint() {if ( innerPaint == null) {innerPaint = new Paint();innerPaint.setARGB(225, 75, 75, 75); //grayinnerPaint.setAntiAlias(true);}return innerPaint;}public Paint getBorderPaint() {if ( borderPaint == null) {borderPaint = new Paint();borderPaint.setARGB(255, 255, 255, 255);borderPaint.setAntiAlias(true);borderPaint.setStyle(Style.STROKE);borderPaint.setStrokeWidth(2);}return borderPaint;}public Paint getTextPaint() {if ( textPaint == null) {textPaint = new Paint();textPaint.setARGB(255, 255, 255, 255);textPaint.setAntiAlias(true);}return textPaint;}?注:这里可能有些函数是无用的,因为这个类还实现在Mapview上出现infowindow的效果。不过这里为了简化起见我就删了。
?
?
最后总结一下:其实开发一个应用,我都是先从view开始,然后更具应用需要的,进行单个功能的开发,最后就是ctrl+c和V了呵呵。
但这里正好是反过来了。想从易道难成列。。。哈哈毕竟是新手,第一次写这种文章,大家见谅吧。
?
这个应用只有一个activity,既只有一个view。在这个view中有Mapview。
而使用Google map 基本上就是让这个activity继承MapActivity,然后对这个Mapview对象进行操作了。
这个应用通过两个service分别运行在后台,其一实时更新用户的位置,其二实时跟新手机的重力状态。进而发送相应的intent广播,而这个intent广播携带了情景模式的信息,当boardcastreceiver(广播接收器)接受到这个广播后就调用相应函数并根据intent携带的信息改变手机的情景。而用户每次记录的地点和情景,则使用了XML文件进行读写。
在mapview上的自定义标记采用了重写ondraw方法的方式,在底层自己绘制。
?
1 楼 android_mini 2010-07-31 哈哈 ,不错,我也刚写了一篇博文,你去看看哈 2 楼 nonoh2006 2010-08-02 你好,我的一个程序之中也需要使用的传感器和GPS相关信息的实施传递,从你的代码中,我没能了解到在activity 中怎么样接受 service 中的数据, 请问下 能不能发一下该工程的源代码
或者能不能给我相信说下 service的数据接收 谢谢 我的邮箱zswenchao2002@163.com 3 楼 ec256 2010-10-22 你好,我有个问题想请教,Sensor 在service中可以正常监听吗,是不是还需要什么权限啊,能否把你的源代码给我 啊 ec256@163.com 谢谢 4 楼 yjdzh 2010-12-09 可以共享一下代码嘛 5 楼 左手风袖 2011-04-04 能否共享一下代码?