最近参加小挑战杯,我们队的产品也地图有关,其中有个需求就是在地图上显示当前发布任务的用户的头像,而且头像圆形显示,咋一看,没啥太多难度,可其中遇到各种问题,多线程同步,异步加载,自定义view,数据检索,垃圾自动回收机制。最后做出来时候,有点小激动。下面详细和记录我的解决方案。
首先看看效果图
首先,我用的百度地图,百度地图实现定位,添加覆盖物,周边检索,poi,路线规划都做的挺好了。可以参考百度地图开发者平台,其中在地图上添加用户头像其实就是在地图上添加覆盖物marker。我大致先顺一遍开发思路。首先从后台获取附近10km内所有任务封装在任务集合中(其中任务是个实体类),之后通过任务去后台去查询发布任务人的信息,发布人的名字,地点......其中要检索到发布人头像的url,并通过头像url,在客户端用异步加载机制ImageLoader来加载头像,ImageLoader反馈一个Bitmap头像信息。将所有头像Bitmap异步加载下来存起来,之后根据从后台获取的任务集合,来循环添加头像到地图上,其中需要坐标,覆盖物marker,具体所需参数参考百度地图demo。
<span style="font-size:18px;">static String avaterURL;
static BitmapDescriptor bitmapDescriptor;
/**
*
* @param publisherName
* 发布人姓名
*/
public static void getNearbyTaskAvaters(final String publisherName) {
AVQuery<AVObject> query = new AVQuery<AVObject>("Gender");
query.whereEqualTo("username", publisherName);
query.findInBackground(new FindCallback<AVObject>() {
@Override
public void done(List<AVObject> arg0, AVException arg1) {
Log.e("avaterURL", "共有" + arg0.size() + "个任务");
if (arg0 != null && arg0.size() != 0) {
AVObject publisher = arg0.get(arg0.size() - 1);
AVFile avaterFile = publisher.getAVFile("avater");
avaterURL = avaterFile.getUrl();
Message msg = Message.obtain();
Log.e("avaterURL", avaterURL + "");
msg.obj = avaterURL;
msg.what = 2;
handler.sendMessage(msg);
// bitmapDescriptor=load();
// Log.e("avaterURL", "load完了");
}
}
});
}
private static Handler handler = new Handler() {
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case 1:
bitmapDescriptor = load();
break;
case 2:
bitmap= loadToBitmap();
break;
default:
break;
}
};
};
private static Bitmap bitmap;
public static Bitmap loadToBitmap() {
DisplayImageOptions options = new DisplayImageOptions.Builder()
.showImageForEmptyUri(R.drawable.default_load)// 设置图片Uri为空或是错误的时候显示的图片
.showImageOnFail(R.drawable.default_load)// 设置图片加载或解码过程中发生错误显示的图片
.bitmapConfig(Bitmap.Config.RGB_565).build();
ImageLoader.getInstance().loadImage(avaterURL, options,
new ImageLoadingListener() {
@Override
public void onLoadingStarted(String arg0, View arg1) {
}
@Override
public void onLoadingFailed(String arg0, View arg1,
FailReason arg2) {
}
@Override
public void onLoadingComplete(String arg0, View arg1,
Bitmap arg2) {
bitmap=arg2;
}
@Override
public void onLoadingCancelled(String arg0, View arg1) {
}
});
return bitmap;
}
public static Bitmap getBitmap(){
return bitmap;
}
public static BitmapDescriptor getBitmapDescriper() {
Log.e("bitmapDescriptor", bitmapDescriptor + "");
return bitmapDescriptor;
}</span>
上面代码实现了从后台获取头像,以bitmap来返回,其中用到了开源异步加载库,ImageLoader,使用前需要配置,不清楚的请自行百度
<span style="font-size:18px;">/**
* 查找附近的服务
*/
public void findTaskNearBy() {
taskNearBy.clear();
// initMarker();
new Thread(new Runnable() {
@Override
public void run() {
AVQuery<AVObject> query = new AVQuery<>("Task");
// 查找附近10km内的任务
query.whereWithinKilometers("geoPoint", mMyPoint, 10);
// query.whereNotEqualTo("publisherName", mUsername);
try {
List<AVObject> taskList = query.find();
Task taskBean = null;
for (AVObject task : taskList) {
taskBean = new Task();
taskBean.setPublisherName(task
.getString("publisherName"));
taskBean.setAccepted(false);
taskBean.setAccomplished(false);
taskBean.setEndTime(task.getString("endTime"));
taskBean.setPrice(task.getString("price"));
taskBean.setTheme(task.getString("theme"));
taskBean.setTaskDescription(task
.getString("TaskDescription"));
taskBean.setType(task.getString("service_task"));
taskBean.setLatitude(task.getAVGeoPoint("geoPoint")
.getLatitude());
taskBean.setLongitude(task.getAVGeoPoint("geoPoint")
.getLongitude());
taskBean.setLocation(task.getString("location"));
taskBean.setType(task.getString("service_type"));
taskNearBy.add(taskBean);
}
// mHandler.obtainMessage(1).sendToTarget();
loadAllAvaters();
Log.e("task", taskNearBy.size() + "");
Log.e("task", taskNearBy.toString());
} catch (AVException e) {
e.printStackTrace();
}
}
}).start();
Log.e("ShowNearMenMapActivity", "findTaskNearBy被执行");
}</span>
以上代码实现从数据库检索附近所有任务,封装到一个集合中
<span style="font-size:18px;">/**
* 异步加载所有的头像
*/
public void loadAllAvaters(){
for(int i=0;i<taskNearBy.size();i++){
AVService.getNearbyTaskAvaters(taskNearBy.get(i).getPublisherName());
//主线程跑的太快,让他等子线程异步加载完头像信息,不然获取的头像都为空
//sb线程跑的太快了,等等imageloader
try {
Thread.sleep(600);
} catch (InterruptedException e) {
e.printStackTrace();
}
Bitmap bitmap= AVService.getBitmap();
if(bitmap!=null){
bitMaps.put(taskNearBy.get(i).getPublisherName(),
bitmap);
}
}
Log.e("avaterMarkers", avaterMarkers.size()+"\n"+avaterMarkers.toString());
Log.e("loadAllAvaters", "方法被执行");
showAllMarkersOnMap();
}</span>
这儿就是异步加载所有头像,然后保存到一个map中,现在所有头像都存起来啦。
<span style="font-size:18px;">/**
* 将所有任务以发布人头像显示在地图上
*/
private void showAllMarkersOnMap(){
mBaiduMap.clear();
Marker marker = null;
LatLng latLng = null;
OverlayOptions options;
for(int i=0;i<taskNearBy.size();i++){
latLng = new LatLng(taskNearBy.get(i).getLatitude(), taskNearBy.get(i).getLongitude());
// options = new MarkerOptions().position(latLng)
// .icon(avaterMarkers.get(taskNearBy.get(i).getPublisherName())).zIndex(5);
initMarker();
Bitmap bitmap=Bitmap.createBitmap(bitMaps.get(taskNearBy.get(i).getPublisherName()));
circleImageView.setImageBitmap(bitmap);
circleImageView.setImageAlpha(0);
mMarkDescriptor = BitmapDescriptorFactory
.fromView(circleImageView);
options = new MarkerOptions().position(latLng)
.icon(mMarkDescriptor).zIndex(5);
marker = (Marker) mBaiduMap.addOverlay(options);
marker = (Marker) mBaiduMap.addOverlay(options);
Bundle arg0 = new Bundle();
arg0.putSerializable("info", taskNearBy.get(i));
marker.setExtraInfo(arg0);
}
MapStatusUpdate msu = MapStatusUpdateFactory.newLatLng(latLng);
mBaiduMap.setMapStatus(msu);
} </span>
现在最后一步,就是遍历任务,根据发布任务人的地理位置,发布人的头像,将头像显示在地图上。其中圆形头像是通过一个开源库实现,叫CircleImageview,其中circleimageview设置属性时候需要设置透明度为0,不然会出现这种效果
好了,大概的实现思路就是这样,其实一开始我不是这么实现的,我是每下载一个头像就去添加到地图上,通过一个view来承载所有的头像,最后导致地图上所有头像都相同。想看源代码的话私聊我吧,因为软件还没完工。
每天记录成长一点一滴