美文网首页
项目中单例模式的使用

项目中单例模式的使用

作者: 墨色尘埃 | 来源:发表于2017-07-14 11:27 被阅读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);
        }
    }
}
1.png
TIM截图20170714113102.png
TIM截图20170714113116.png

相关文章

  • Android性能优化

    项目中的单例 在分析性能优化之前偶然的看到项目中的有很多单例模式,单例模式几乎是项目中被应用最多的设计模式,不同单...

  • OC通用单例模式宏文件以及使用方法

    项目中,我们经常用到单例模式,并且不止一个类需要建立单例模式,为了方便快速创建单例模式类,编写如下宏。 使用方法很...

  • 【设计模式】单例模式

    单例模式 常用单例模式: 懒汉单例模式: 静态内部类单例模式: Android Application 中使用单例模式:

  • Kotlin设计模式-单例模式

    单例模式是项目中最常见的工具类使用模式 kotlin中单例的最佳实践方式,线程安全的懒汉模式 java中调用 ko...

  • Java设计模式——单例模式

    Java设计模式——单例模式 单例模式应该是大家最为熟知的一种设计模式了,相信大家或多或少的都在自己的项目中使用过...

  • 编程设计模式01——单例模式

    1.单例模式定义在Android中的使用 单例模式在项目中唯一持久存在的模式,而且为整个系统提供这个实例。处理一些...

  • android开发单例模式和Rxjava组合bug

    android开发单例模式和Rxjava组合bug 纪录一个关于单例模式和Rxjava组合使用的bug。项目中关于...

  • 项目中单例模式的使用

    面向接口编程为什么使用单例模式对于为什么使用单例模式还是很模糊,先记下来自己的理解。比如重复点击某个按钮需要进入某...

  • 单例模式之枚举类enum

    通过枚举实现单例模式 枚举类实现单例模式的优点 对于饿汉式单例模式和懒汉式单例模式了解的同学,使用以上两种单例模式...

  • 项目实战—那些年常用的单例模式

    常见的单例模式:饿汉式、懒汉式、双重检查锁模式、静态内部类实现单例模式、枚举单例模式,本文重点是在项目中如何实现上...

网友评论

      本文标题:项目中单例模式的使用

      本文链接:https://www.haomeiwen.com/subject/wbunhxtx.html