Android 百度地图的应用

最近在搞一个地图应用,主要也没什么技术难点,主要就是定位,还有就是对应的信息显示,这里就介绍一下百度的地图应用吧,有兴趣的同学可以看一下百度API Android开发里面的例子,里面的代码主要就是写得有点乱,这里自己做一下总结。

首先我们来看一下效果图:如下

Android 百度地图的应用_第1张图片

要实现如上图这样的效果,接下来我们一步一步来实现:

首先要注册百度服务,这个我就不说了,大家可以百度一下,网上有很多的。

http://developer.baidu.com/map/sdk-android.htm

接下来下载百度Android SDK

http://developer.baidu.com/map/sdkandev-download.htm

我们下载Android SDKv2.1.1这个包

直接解压BaiduMap_AndroidSDK_v2.1.1_Sample.zip这个压缩包,把包里的libs目录下的所有文件都拷到我们自己的工程的libs里

这里面包含了定位跟地图调用的方法。接下来就是给我们的工程加入一些权限。(权限不知道在哪设?Oh,my God)

那好吧,我来说一下吧,把Sample工程里的AndroidManifest.xml中的

    <uses-permission android:name="android.permission.GET_ACCOUNTS" />
    <uses-permission android:name="android.permission.USE_CREDENTIALS" />
    <uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
    <uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />

    <permission android:name="android.permission.BAIDU_LOCATION_SERVICE" >
    </permission>

    <uses-permission android:name="android.permission.BAIDU_LOCATION_SERVICE" >
    </uses-permission>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" >
    </uses-permission>
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" >
    </uses-permission>
    <uses-permission android:name="android.permission.INTERNET" >
    </uses-permission>
    <uses-permission android:name="android.permission.ACCES_MOCK_LOCATION" >
    </uses-permission>
    <!-- <uses-permission android:name="android.permission.WRITE_APN_SETTINGS"></uses-permission> -->
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" >
    </uses-permission>
    <uses-permission android:name="com.android.launcher.permission.READ_SETTINGS" />
    <uses-permission android:name="android.permission.WAKE_LOCK" >
    </uses-permission>
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.ACCESS_GPS" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.READ_CONTACTS" />
    <uses-permission android:name="android.permission.CALL_PHONE" />
    <uses-permission android:name="android.permission.READ_SMS" />
    <uses-permission android:name="android.permission.SEND_SMS" />
    <!-- SDK1.5需要android.permission.GET_TASKS权限判断本程序是否为当前运行的应用? -->
    <uses-permission android:name="android.permission.GET_TASKS" />
    <uses-permission android:name="android.permission.CAMERA" >
    </uses-permission>
    <uses-permission android:name="android.permission.RECORD_AUDIO" >
    </uses-permission>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" >
    </uses-permission>
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    <uses-permission android:name="android.permission.BROADCAST_STICKY" />
    <uses-permission android:name="android.permission.WRITE_SETTINGS" />
    <!-- 来电消音 -->
    <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" >
    </uses-permission>
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
都拷到我们自己的AndroidManifest.xml中。(拷贝,粘贴总会了吧)

如果要用到定位服务的话,还要把

<service
            android:name="com.baidu.location.f"
            android:enabled="true"
            android:process=":remote" >
 </service>
这个服务加上,开始的时候没注意,老是定位不到自己所处的方位,加上这个就OK了,百度这方面做得还是不错的。定位精度也不错。

好了,都加好了,接下来就是编码了

首先要定义一个主要的程序运行环境,这里Demo里有一个DemoApplication.java,这个类继承了Application,一般写程序都会在程序启动的时候加载一些数据或配置,都可以写在这个类里,而且这个类作为程序的主运行类,只要程序不退出,这个类是不会被销毁的,所以可以把一些全局的方法也写在这个类里。

    private static DemoApplication mInstance = null; //单例
    public boolean m_bKeyRight = true;
    BMapManager mBMapManager = null;

    public static final String strKey = "请输入你的key";
	
	@Override
    public void onCreate() {
	    super.onCreate();
		mInstance = this;
		initEngineManager(this); //初始化百度引擎
	}
	
	@Override
	//建议在您app的退出之前调用mapadpi的destroy()函数,避免重复初始化带来的时间消耗
	public void onTerminate() {
		// TODO Auto-generated method stub
	    if (mBMapManager != null) {
            mBMapManager.destroy();
            mBMapManager = null;
        }
		super.onTerminate();
	}
	
	public void initEngineManager(Context context) {
        if (mBMapManager == null) {
            mBMapManager = new BMapManager(context);
        }

        if (!mBMapManager.init(strKey,new MyGeneralListener())) {
            Toast.makeText(DemoApplication.getInstance().getApplicationContext(), 
                    "BMapManager  初始化错误!", Toast.LENGTH_LONG).show();
        }
	}
	
	public static DemoApplication getInstance() {
		return mInstance;
	}
	
	
	// 常用事件监听,用来处理通常的网络错误,授权验证错误等
    static class MyGeneralListener implements MKGeneralListener {
        
        @Override
        public void onGetNetworkState(int iError) {
            if (iError == MKEvent.ERROR_NETWORK_CONNECT) {
                Toast.makeText(DemoApplication.getInstance().getApplicationContext(), "您的网络出错啦!",
                    Toast.LENGTH_LONG).show();
            }
            else if (iError == MKEvent.ERROR_NETWORK_DATA) {
                Toast.makeText(DemoApplication.getInstance().getApplicationContext(), "输入正确的检索条件!",
                        Toast.LENGTH_LONG).show();
            }
            // ...
        }

        @Override
        public void onGetPermissionState(int iError) {
            if (iError ==  MKEvent.ERROR_PERMISSION_DENIED) {
                //授权Key错误:
                Toast.makeText(DemoApplication.getInstance().getApplicationContext(), 
                        "请在 DemoApplication.java文件输入正确的授权Key!", Toast.LENGTH_LONG).show();
                DemoApplication.getInstance().m_bKeyRight = false;
            }
        }
    }

这里DemoApplication里的代码,不多,我们可以将代码拷贝到我们自己的Application里,我们也可以把我们的定位程序写在这里,这样我们程序一启动,就可以定位到我们的位置。(如果再进一步,启动的时候就开启一个Service,就可以不停地把我们的坐标发送到我们自己的服务器了,这样你的一举一动就都在服务器记录了)呵呵,这是后话,当然,我个人是不建议这样做的。

接下来就是百度地图Activity了

这里百度地图Activity就是继承了普通的Activity,这里需要说一下的是,现在Google建议开发程序的时候尽量用Fragment,但我试了老半天,也没办法把百度Activity放入Fragment,可能是我的水平还有限,呵呵,如果可以将百度地图做为一个Fragment的话,那就可以更灵活地使用百度地图了。希望百度地图在以后能改进,Google地图倒是用的Fragment。这个我们以后再说。

在Activity的onCreate里

        DemoApplication app = (DemoApplication)this.getApplication();
        if (app.mBMapManager == null) {
            app.mBMapManager = new BMapManager(this);
            app.mBMapManager.init(DemoApplication.strKey,new DemoApplication.MyGeneralListener());
        }
        setContentView(R.layout.activity_itemizedoverlay);
        // 取得地图控件
        mMapView = (MapView) findViewById(R.id.bmapView);
        mMapView.setLongClickable(true);
        //设定地图显示放大缩小控件
        mMapView.setBuiltInZoomControls(true);
        // 取得地图控制器
        mMapController=mMapView.getController();
        // 设置地图中心
        mMapController.setCenter(INIT_POINT); 
        // INIT_POINT = new GeoPoint((int) (31.57942800 * 1e6), (int) (120.30795300 * 1e6));    //这里初始化了显示中心,一启动就以当前位置为中心显示地图
        //设置地图显示级别,一般13,14就是显示道路名称了
        mMapController.setZoom(14);
        //地图可以单击
        mMapController.enableClick(true);

这样基本地图就能显示出来了,接下来要加入图层,其实地图上显示的信息都是往地图层上加图层,也不是特别深奥的知识。

这里我们尽量用异步来计算坐标,加载图层。

        /**
	 * 将信息加入图层
	 * 
	 * @param list
	 * @return
	 */
	private Overlay getOverlay(List<Info> list) {
		// 标记图片
		Drawable dr = getResources().getDrawable(R.drawable.icon_marka);
		Overlay ov = new Overlay(dr, this);
		
		int lat, lon;
		Info item;
		for (Info info : list) {
			lat = (int) (info.getLat() * 1e6);
			lon = (int) (info.getLon() * 1e6);
			item = new InfoItem(new GeoPoint(lat, lon),
					info.getName(), info.getAddress(),
					info.getsex(),
					info.getNum());
			item.setMarker(dr);
			ov.addItem(item);
		}
		return ov;
	}
这里将从网络获取的列表转换成Overlay层,然后将获取的层加入mapView中

mMapView.getOverlays().add(overlay);
这个层类在这里给出
static class Overlay extends ItemizedOverlay<InfoItem> {
		public List<InfoItem> mGeoList = new ArrayList<InfoItem>();
		private Context mContext = null;
		static PopupOverlay pop = null;
		private View popView = null;
		private InfoItem mItem;
		private Bitmap map;

		static class ItemView { // 自定义控件集合
			public TextView NameTextView;
			public TextView SexTextView;
			public TextView NumTextView;
			public TextView AddressTextView;
		}
 
		public Overlay(Drawable marker, Context context) {
			super(marker);
			this.mContext = context;
			pop = new PopupOverlay(BaiduMap.mMapView, new PopupClickListener() {
				@Override
				public void onClickedPopup(int index) {

				}
			});
			populate();

		}
 		//图标单击事件
		protected boolean onTap(int index) {
			mOverlayItem = mGeoList.get(index);
			ItemView item = null;
			if (popView == null) {
				popView = LayoutInflater.from(mContext).inflate(
						R.layout.popup_view, null);// 获取要转换的View资源
				item = new ItemView();
				item.TitleTextView = (TextView) popView
						.findViewById(R.id.pop_title);
				item.TotalNumTextView = (TextView) popView
						.findViewById(R.id.pop_num);
				item.CurrentNumTextView = (TextView) popView
						.findViewById(R.id.pop_leftnum);
				item.AddressTextView = (TextView) popView
						.findViewById(R.id.pop_address);

				popView.setTag(item);
			} else {
				item = (ItemView) popView.getTag();
			}

			item.NameTextView.setText(mItem.getName());// 将每个点的Title在弹窗中以文本形式显示出来
			item.SexTextView.setText(mItem.getSex());
			item.NumTextView.setText(mItem.getNum());
			item.AddressTextView.setText(mItem.getSnippet());
			//图片大小,将View转换成Bitmap
			map = convertViewToBitmap(popView, 300, 200);
			// 显示pop
			pop.showPopup(map, mGeoList.get(index).getPoint(), 32);
			map.recycle();  //回收资源
			map = null;
			
			return true;
		}

		public boolean onTap(GeoPoint pt, MapView mapView) {
			if (pop != null) {
				pop.hidePop();
			}
			super.onTap(pt, mapView);
			return false;
		}

		@Override
		protected InfoItem createItem(int i) {
			return mGeoList.get(i);
		}

		@Override
		public int size() {
			return mGeoList.size();
		}

		public void addItem(InfoItem item) {
			mGeoList.add(item);
			populate();
		}

		public void removeItem(int index) {
			mGeoList.remove(index);
			populate();
		}

	}

	/**
	 * 把View绘制到Bitmap上
	 * 
	 * @param view
	 *            需要绘制的View
	 * @param width
	 *            该View的宽度
	 * @param height
	 *            该View的高度
	 * @return 返回Bitmap对象
	 */
	public static Bitmap convertViewToBitmap(View view, int width, int height) {

		int widthSpec = View.MeasureSpec.makeMeasureSpec(width,
				View.MeasureSpec.EXACTLY);
		int heightSpec = View.MeasureSpec.makeMeasureSpec(height,
				View.MeasureSpec.EXACTLY);
		view.measure(widthSpec, heightSpec);
		view.layout(0, 0, width, height);

		// Bitmap bitmap = Bitmap.createBitmap(width, height,
		// Bitmap.Config.ARGB_8888);
		// Canvas canvas = new Canvas(bitmap);
		// view.draw(canvas);

		view.clearFocus();
		view.setPressed(false);
		boolean willNotCache = view.willNotCacheDrawing();
		view.setWillNotCacheDrawing(false);
		// Reset the drawing cache background color to fully transparent
		// for the duration of this operation
		int color = view.getDrawingCacheBackgroundColor();
		view.setDrawingCacheBackgroundColor(0);
		if (color != 0) {
			view.destroyDrawingCache();
		}
		view.buildDrawingCache();

		Bitmap cacheBitmap = view.getDrawingCache();
		if (cacheBitmap == null) {
			Log.e(TAG, "failed getViewBitmap(" + view + ")",
					new RuntimeException());
			return null;
		}
		Bitmap bitmap = Bitmap.createBitmap(cacheBitmap);
		// Restore the view
		view.destroyDrawingCache();
		view.setWillNotCacheDrawing(willNotCache);
		view.setDrawingCacheBackgroundColor(color);

		return bitmap;
	}
这里要注意的是百度的 PopupOverlay只能显示Bitmap,所以我们要把View转换成Bitmap,Bitmap使用完以后要及时回收,如果图片多的话会造成out of memory的异常。

现在应该就可以显示如上的效果了,源码因为是客户的,所以没办法给出,但如果有什么问题的话,可以给我留言。谢谢。

你可能感兴趣的:(Android 百度地图的应用)