项目中单例模式的使用
2017-07-14 本文已影响0人
墨色尘埃
面向接口编程
为什么使用单例模式
对于为什么使用单例模式还是很模糊,先记下来自己的理解。比如重复点击某个按钮需要进入某个类时,肯定是new xx类,xx类每次进入都会被初始化,但是功能要求不能被初始化因为还要用到上一次进入的数据,所以这时候应该使用单例模式,保证该类只有一个实例。
例子一:当手机地图滑动的时候,需要向地图中添加屏幕外的点,但是手机每滑动一次就需要重新进入一个类,不能说我滑动一次之前屏幕内的点都消失对吧,所以要想保证上次的数据还在,这个类只能有一个实例。
/**
* Created by HASEE on 2017/5/22 17:43
*/
public class BaiduMapUse implements IMapUse {
private BaiduMap baiduMap;
private Map<String, Marker> map;
private static BaiduMapUse instance;
private Context context;
/**
* 单例模式
*
* @param baiduMap
* @return
*/
public static BaiduMapUse getInstance(Context context, BaiduMap baiduMap) {
if (instance == null) {
instance = new BaiduMapUse(context, baiduMap);
} else { //如果是单例模式,当activity销毁的时候这里的instance不为空,导致baiduMap还存在
//但是其实当activity销毁的时候BaiduMap也销毁了,所以会导致图标不显示
instance.baiduMap = baiduMap;
instance.context = context;
}
return instance;
}
public BaiduMapUse(Context context, BaiduMap baiduMap) {
this.baiduMap = baiduMap;
this.context = context;
map = new HashMap<>(); //如果不是单例模式,每次构造函数时候map都会重新,会造成空指针异常
}
/**
* 在方法中传参数,这个方法的作用是添加站点到地图上,所以传点的信息。
* 不要在构造函数中传,因为这个和构造函数没什么关系
*
* @param basePointInfo
*/
@Override
public void addBasePoint(BasePointInfo basePointInfo) {
//将站点添加到地图上
double latitude = Double.valueOf(basePointInfo.getLatitude());
double longitude = Double.valueOf(basePointInfo.getLongitude());
LatLng latLng = new LatLng(latitude, longitude);
Bitmap bitmap = basePointInfo.getIcon();
BitmapDescriptor descriptor = BitmapDescriptorFactory.fromBitmap(bitmap);
// BitmapDescriptor descriptor = BitmapDescriptorFactory.fromResource(R.mipmap.icon_markh);
OverlayOptions options = new MarkerOptions().position(latLng).icon(descriptor);
Marker marker = (Marker) baiduMap.addOverlay(options);
Log.e("MainActivity", marker.getTitle()+"/"+marker.toString().getBytes()+"/"+bitmap.toString());
String id = basePointInfo.getLayerId() + "_" + basePointInfo.getPointId();
map.put(id, marker);
Bundle b = new Bundle();
b.putSerializable("data", basePointInfo);
MapUtils.saveDataWithOverlay(marker, b);
}
@Override
public void deleteBasePoint(BasePointInfo basePointInfo) {
String id = basePointInfo.getLayerId() + "_" + basePointInfo.getPointId();
Marker marker = map.get(id);
marker.remove();
}
}
例子二:当点击“测量”按钮时,需要在地图中绘制轨迹,如果此时地图中存在轨迹则先清空;当点击“坐标获取”按钮时,也需要在地图中设置一个marker图标显示位置,如果此时地图中存在marker则先清空。每次点击按钮的时候都是跳转到相对应的功能类MeasureBar和CoordinaterBar中,不能每次进入类中都重新初始化百度地图的逻辑类MeasureBarLogic,那样就不能执行清空操作了(类似在不同的图层上,当然这样说是不对的只是为了方便理解)。所以就需要在同一个MeasureBarLogic中执行,这样MeasureBarLogic类只能有一个,就需要用到单例模式了。
/**
* 测量工具调用示例
*/
testButton.setOnClickListener(view -> (new MeasureBar(MainActivity.this, baiduMap, MainActivity.this,
rootLayout)).init());
/**
* 坐标获取示例
*/
Button getCoordinateBtn = (Button) findViewById(R.id.get_coordinate_btn);
getCoordinateBtn.setOnClickListener(v -> new CoordinaterBar(MainActivity.this, baiduMap, MainActivity.this,
rootLayout).init());
MeasureBar
public class MeasureBar extends LinearLayout implements BaiduMap.OnMapClickListener, View.OnClickListener {
/**
* 常量定义
*/
public static String MEASURE_DIST = "距离:";
public static String MEASURE_AREA = "面积:";
public static String MEASURE_ANG = "角度:";
/**
* 全局变量
*
* @param context
*/
Context myContext;
ViewGroup fatherContainer;
BaiduMap myBaiduMap;
String curState = MEASURE_DIST;
MeasureBarLogic measureBarLogic;
BaiduMap.OnMapClickListener originListener;
private TextView measureResult;
private ImageView measureBack;
private ImageView measureClose;
private ImageView measureClear;
private TextView measureType;
public MeasureBar(Context context, BaiduMap baiduMap, BaiduMap.OnMapClickListener oldListener, ViewGroup fatherView) {
super(context);
myContext = context;
fatherContainer = fatherView;
myBaiduMap = baiduMap;
originListener = oldListener;
// measureBarLogic = new MeasureBarLogic(baiduMap);
measureBarLogic = MeasureBarLogic.getInstance(baiduMap);
// myBaiduMap.setOnMapClickListener(this);
}
public void init() {
View view = fatherContainer.findViewById(R.id.measure_bar);
// if(view != null) return;
if (view != null) {
view = null;
measureBarLogic.ClearAll();
}
measureBarLogic.removeMarker();
/**
* initview
*/
LinearLayout thisLayout = (LinearLayout) LayoutInflater.from(myContext).inflate(R.layout.measure_bar, this);
measureResult = (TextView) thisLayout.findViewById(R.id.measure_result);
measureBack = (ImageView) thisLayout.findViewById(R.id.measure_back);
measureBack.setOnClickListener(this);
measureClose = (ImageView) thisLayout.findViewById(R.id.measure_close);
measureClose.setOnClickListener(this);
measureClear = (ImageView) thisLayout.findViewById(R.id.measure_clear);
measureClear.setOnClickListener(this);
measureType = (TextView) thisLayout.findViewById(R.id.measure_type);
measureType.setOnClickListener(this);
measureType.setText(MEASURE_DIST);
/**
* 设置布局并加入到父容器中
*/
if (fatherContainer instanceof ConstraintLayout) {
int fatherId = fatherContainer.getId();
ConstraintLayout.LayoutParams layoutParams = new ConstraintLayout.LayoutParams(ConstraintLayout.LayoutParams.MATCH_PARENT, ConstraintLayout.LayoutParams.WRAP_CONTENT);
layoutParams.leftToLeft = fatherId;
layoutParams.rightToRight = fatherId;
layoutParams.topToTop = fatherId;
layoutParams.setMargins(0, 20, 0, 0);
fatherContainer.addView(this, layoutParams);
}
else if(fatherContainer instanceof RelativeLayout){
//相对布局
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT
, ViewGroup.LayoutParams.WRAP_CONTENT);
params.addRule(RelativeLayout.CENTER_HORIZONTAL);
params.setMargins(0, 20, 0, 0);
fatherContainer.addView(this, params);
}
/**
* 修改百度地图对象的监听事件
*/
myBaiduMap.setOnMapClickListener(this);
}
/**
* 实现mapClicker接口
*
* @param latLng
*/
@Override
public void onMapClick(LatLng latLng) {
if (curState.equals(MEASURE_DIST)) {
double allDist = measureBarLogic.CalDist(latLng);
String showDist = String.format("%.2f", allDist) + "m";
measureResult.setText(showDist);
}
else if (curState.equals(MEASURE_AREA)) {
double allArea = measureBarLogic.CalArea(latLng);
String showArea = String.format("%.2f", allArea) + "m2";
measureResult.setText(showArea);
}
else if (curState.equals(MEASURE_ANG)) {
double allAng = measureBarLogic.CalAng(latLng);
String showAng = String.format("%.2f", allAng) + "m2";
measureResult.setText(showAng);
}
}
@Override
public boolean onMapPoiClick(MapPoi mapPoi) {
onMapClick(mapPoi.getPosition());
return false;
}
/**
* 实现点击
*
* @param view
*/
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.measure_clear:
measureBarLogic.ClearAll();
break;
case R.id.measure_back:
measureBarLogic.BackOneStep();
break;
case R.id.measure_close:
measureBarLogic.ClearAll();
fatherContainer.removeView(this);
if (originListener != null) myBaiduMap.setOnMapClickListener(originListener);
break;
case R.id.measure_type:
measureBarLogic.ClearAll();
if(measureType.getText().equals(MEASURE_DIST)){
measureType.setText(MEASURE_AREA);
curState = MEASURE_AREA;
Toast.makeText(myContext,"面积测量,请点击屏幕选取",Toast.LENGTH_SHORT).show();
}
else if(measureType.getText().equals(MEASURE_AREA)) {
measureType.setText(MEASURE_ANG);
curState = MEASURE_ANG;
Toast.makeText(myContext,"角度测量,请点击屏幕选取",Toast.LENGTH_SHORT).show();
}
else if(measureType.getText().equals(MEASURE_ANG)) {
measureType.setText(MEASURE_DIST);
curState = MEASURE_DIST;
Toast.makeText(myContext,"距离测量,请点击屏幕选取",Toast.LENGTH_SHORT).show();
}
break;
default:
break;
}
}
}
CoordinaterBar
public class CoordinaterBar extends LinearLayout implements BaiduMap.OnMapClickListener, View.OnClickListener {
/**
* 常量定义
*/
public static String MEASURE_DIST = "坐标:";
/**
* 全局变量
*
* @param context
*/
Context myContext;
ViewGroup fatherContainer;
BaiduMap myBaiduMap;
String curState = MEASURE_DIST;
MeasureBarLogic measureBarLogic;
static BaiduMap.OnMapClickListener originListener;
private TextView measureResult;
private ImageView measureBack;
private ImageView measureClose;
private ImageView measureClear;
private TextView measureType;
private Marker mLocMark; // 我的坐标覆盖物
public CoordinaterBar(Context context, BaiduMap baiduMap, BaiduMap.OnMapClickListener oldListener, ViewGroup
fatherView) {
super(context);
myContext = context;
fatherContainer = fatherView;
myBaiduMap = baiduMap;
originListener = oldListener;
// measureBarLogic = new MeasureBarLogic(baiduMap);
measureBarLogic = MeasureBarLogic.getInstance(baiduMap);
}
public void init() {
View view = fatherContainer.findViewById(R.id.measure_bar);
// if (view != null) return;
if (view != null) {
view = null;
measureBarLogic.ClearAll();
}
measureBarLogic.removeMarker(); // 清除已有覆盖物
// if (null != mLocMark){
// mLocMark.remove(); // 清除已有覆盖物
// mLocMark = null;
// }
LinearLayout thisLayout = (LinearLayout) LayoutInflater.from(myContext).inflate(R.layout.measure_bar, this);
measureResult = (TextView) thisLayout.findViewById(R.id.measure_result);
measureResult.setText("坐标经纬度");
// measureResult.setTextSize(12);
measureBack = (ImageView) thisLayout.findViewById(R.id.measure_back);
// measureBack.setOnClickListener(this);
measureBack.setVisibility(GONE);
measureClose = (ImageView) thisLayout.findViewById(R.id.measure_close);
measureClose.setOnClickListener(this);
measureClear = (ImageView) thisLayout.findViewById(R.id.measure_clear);
// measureClear.setOnClickListener(this);
measureClear.setVisibility(GONE);
measureType = (TextView) thisLayout.findViewById(R.id.measure_type);
// measureType.setOnClickListener(this);
measureType.setText(MEASURE_DIST);
/**
* 设置布局并加入到父容器中
*/
if (fatherContainer instanceof ConstraintLayout) {
int fatherId = fatherContainer.getId();
ConstraintLayout.LayoutParams layoutParams = new ConstraintLayout.LayoutParams(ConstraintLayout
.LayoutParams.MATCH_PARENT, ConstraintLayout.LayoutParams.WRAP_CONTENT);
layoutParams.leftToLeft = fatherId;
layoutParams.rightToRight = fatherId;
layoutParams.topToTop = fatherId;
layoutParams.setMargins(0, 20, 0, 0);
fatherContainer.addView(this, layoutParams);
} else if (fatherContainer instanceof RelativeLayout) {
//相对布局
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams
.WRAP_CONTENT
, ViewGroup.LayoutParams.WRAP_CONTENT);
params.addRule(RelativeLayout.CENTER_HORIZONTAL);
params.setMargins(0, 20, 0, 0);
fatherContainer.addView(this, params);
}
/**
* 修改百度地图对象的监听事件
*/
myBaiduMap.setOnMapClickListener(this);
}
/**
* 实现mapClicker接口
*
* @param latLng
*/
@Override
public void onMapClick(LatLng latLng) {
getCoordinate(myBaiduMap, latLng);
}
@Override
public boolean onMapPoiClick(MapPoi mapPoi) {
onMapClick(mapPoi.getPosition());
return false;
}
/**
* 实现点击
*
* @param view
*/
@Override
public void onClick(View view) {
switch (view.getId()) {
// case R.id.measure_clear:
// measureBarLogic.ClearAll();
// break;
// case R.id.measure_back:
// measureBarLogic.BackOneStep();
// break;
case R.id.measure_close:
measureBarLogic.ClearAll();
fatherContainer.removeView(this);
if (originListener != null) myBaiduMap.setOnMapClickListener(originListener);
break;
// case R.id.measure_type:
// measureBarLogic.ClearAll();
// if (measureType.getText().equals(MEASURE_DIST)) {
// measureType.setText(MEASURE_AREA);
// curState = MEASURE_AREA;
// Toast.makeText(myContext, "面积测量,请点击屏幕选取", Toast.LENGTH_SHORT).show();
// } else if (measureType.getText().equals(MEASURE_AREA)) {
// measureType.setText(MEASURE_ANG);
// curState = MEASURE_ANG;
// Toast.makeText(myContext, "角度测量,请点击屏幕选取", Toast.LENGTH_SHORT).show();
//
// } else if (measureType.getText().equals(MEASURE_ANG)) {
// measureType.setText(MEASURE_DIST);
// curState = MEASURE_DIST;
// Toast.makeText(myContext, "距离测量,请点击屏幕选取", Toast.LENGTH_SHORT).show();
// }
// break;
default:
break;
}
}
public void getCoordinate(BaiduMap mBaiduMap, LatLng latLng) {
measureBarLogic.setMarker(latLng);
LatLng newLl = CommonUtils.BaiDuToWGS84(latLng);
String showLoc = String.format("%.5f", newLl.longitude) + "," + String.format("%.5f", newLl.latitude);
measureResult.setText(showLoc);
}
}
MeasureBarLogic
/**
* Created by lw on 2016/4/26.
* 地图计算功能类
*/
public class MeasureBarLogic {
private final BaiduMap mBdMap;
private List<LatLng> mPoints = new ArrayList<LatLng>();
private Polyline thisPline = null; //活动多义线
private Polygon thisPolygon = null; //活动多边形状
private List<Dot> dotList;
private static MeasureBarLogic measureBarLogic;
public MeasureBarLogic(BaiduMap thisBdMap) {
mBdMap = thisBdMap;
}
public static MeasureBarLogic getInstance(BaiduMap baiduMap) {
if (measureBarLogic == null) {
measureBarLogic = new MeasureBarLogic(baiduMap);
}
return measureBarLogic;
}
/**
* 清除地图上的覆盖物和点
*/
public void ClearAll() {
mPoints.clear();
if (null != dotList) {
for (Dot dot : dotList) {
dot.remove();
}
}
if (null != thisPline) {
thisPline.remove();
thisPline = null;
}
if (null != thisPolygon) {
thisPolygon.remove();
thisPolygon = null;
}
}
public double BackOneStep() {
/**移除一个点*/
if (dotList != null && dotList.size() > 0) {
mPoints.remove(mPoints.size() - 1);
dotList.get(dotList.size() - 1).remove();
dotList.remove(dotList.size() - 1);
}
/**移除多义线*/
if (thisPline != null) {
if (mPoints.size() > 1) {
thisPline.setPoints(mPoints);
return CalDistByPline(thisPline);
} else {
thisPline.remove();
thisPline = null;
return 0.0;
}
}
/**移除多边形线*/
if (thisPolygon != null) {
if (mPoints.size() > 2) {
thisPolygon.setPoints(mPoints);
return CalPolygonArea(thisPolygon);
} else {
thisPolygon.remove();
thisPolygon = null;
return 0.0;
}
}
return 0.0;
}
private void DrawDot(LatLng ll) {
/**增加圆点*/
if (dotList == null) dotList = new ArrayList<>();
DotOptions dotOptions = new DotOptions().color(0xffFF0033).center(ll).radius(8);
Dot dot = (Dot) mBdMap.addOverlay(dotOptions);
dotList.add(dot);
if(mPoints == null) mPoints = new ArrayList<>();
mPoints.add(ll);
}
/**
* 测量距离
*
* @param ll
*/
public double CalDist(LatLng ll) {
DrawDot(ll);
/**画多义线*/
if (mPoints.size() > 1) {
if (null == thisPline) {
thisPline = addPolylineToMap(mBdMap, mPoints,5, R.color.mediumpurple);
} else {
thisPline.setPoints(mPoints);
}
return CalDistByPline(thisPline);
} else {
return 0;
}
}
/**
* 测量面积
*
* @param ll
*/
public double CalArea(LatLng ll) {
DrawDot(ll);
if (mPoints.size() > 2) {
if (null == thisPolygon) {
thisPolygon = addPolygonToMap(mBdMap, mPoints, 5, R.color.mediumpurple, Color.parseColor("#50000000"));
} else {
thisPolygon.setPoints(mPoints);
}
return CalPolygonArea(thisPolygon);
} else {
return 0;
}
}
/**
* 测量角度
* @param ll
* @return
*/
public double CalAng(LatLng ll){
return 0.0;
}
/**
* 计算多义线的总距离
*
* @param pl
* @return
*/
public double CalDistByPline(Polyline pl) {
List<LatLng> ptList = pl.getPoints();
return getAllDist(ptList);
}
public static double getAllDist(List<LatLng> ptList){
double totalDist = 0;
for (int i = 1; i < ptList.size(); i++) {
double tempDist = DistanceUtil.getDistance(ptList.get(i - 1), ptList.get(i));
totalDist += tempDist;
}
return totalDist;
}
/**
* 计算多边形的面积
*
* @param plg
* @return
*/
public double CalPolygonArea(Polygon plg) {
return AreaUtils.CalPolygonArea(plg.getPoints());
}
private Marker mLocMark; // 我的坐标覆盖物
/**
* 移除坐标获取图标
*/
public void removeMarker() {
if (null != mLocMark){
mLocMark.remove(); // 清除已有覆盖物
mLocMark = null;
}
}
/**
* 设置坐标到百度地图
*/
public void setMarker(LatLng latLng) {
if (null != mLocMark)
mLocMark.remove(); // 清除已有覆盖物
mLocMark = null;
if (null == mLocMark) {
mLocMark = MapUtils.addOverlayToMap(mBdMap, latLng,
BitmapDescriptorFactory.fromResource(R.drawable.home_location_red));
} else {
mLocMark.setPosition(latLng);
}
}
}


