osmdroid API解读(四)

osmdroid API解读(四)

osmdroid-android模块 org.osmdroid.tileprovider包(一)

1.MapTile

地图瓦片使用观察者模式分割,瓦片由tile provider下发。本类必须保持不变,因为其备用于缓存hash map的key

public class MapTile {

    public static final int MAPTILE_SUCCESS_ID = 0;
    public static final int MAPTILE_FAIL_ID = MAPTILE_SUCCESS_ID + 1;

    private final int x;//瓦片的坐标位置x
    private final int y;//瓦片的坐标位置y
    private final int zoomLevel;//该瓦片缩放等级
    private Date expires;//瓦片到期时间

    public MapTile(final int zoomLevel, final int tileX, final int tileY) {
        this.zoomLevel = zoomLevel;
        this.x = tileX;
        this.y = tileY;
    }

    public Date getExpires() {
        return expires;
    }

    public void setExpires(Date expires) {
        this.expires = expires;
    }

    public int getZoomLevel() {
        return zoomLevel;
    }

    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }

    @Override
    public String toString() {
        return "/" + zoomLevel + "/" + x + "/" + y;
    }

    @Override
    public boolean equals(final Object obj) {
        if (obj == null)
            return false;
        if (obj == this)
            return true;
        if (!(obj instanceof MapTile))
            return false;
        final MapTile rhs = (MapTile) obj;
        return zoomLevel == rhs.zoomLevel && x == rhs.x && y == rhs.y;
    }

    @Override
    public int hashCode() {
        int code = 17;
        code *= 37 + zoomLevel;
        code *= 37 + x;
        code *= 37 + y;
        return code;
    }
}

1.1 LRUMapTileCache

瓦片集合缓存,继承自LinkedHashMap,以MapTile(用于定位图片位置)为key,Drawable为value。用于管理一系列的瓦片。

public class LRUMapTileCache extends LinkedHashMap<MapTile, Drawable> {

    public interface TileRemovedListener {
        void onTileRemoved(MapTile mapTile);
    }

    private static final long serialVersionUID = -541142277575493335L;

    private int mCapacity;//瓦片容量
    private TileRemovedListener mTileRemovedListener;//瓦片移除监听器

    public LRUMapTileCache(final int aCapacity) {
        super(aCapacity + 2, 0.1f, true);
        mCapacity = aCapacity;
    }

    public void ensureCapacity(final int aCapacity) {
        if (aCapacity > mCapacity) {
            Log.i(IMapView.LOGTAG, "Tile cache increased from " + mCapacity + " to " + aCapacity);
            mCapacity = aCapacity;
        }
    }

    @Override//移除瓦片
    public Drawable remove(final Object aKey) {
        final Drawable drawable = super.remove(aKey);
        // Only recycle if we are running on a project less than 2.3.3 Gingerbread.
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.GINGERBREAD) {
            if (drawable instanceof BitmapDrawable) {
                final Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();
                if (bitmap != null) {
                    bitmap.recycle();
                }
            }
        }
        if (getTileRemovedListener() != null && aKey instanceof MapTile)
            getTileRemovedListener().onTileRemoved((MapTile) aKey);
        if (drawable instanceof ReusableBitmapDrawable)
            BitmapPool.getInstance().returnDrawableToPool((ReusableBitmapDrawable) drawable);
        return drawable;
    }

    @Override//清除所有瓦片
    public void clear() {
        // remove them all individually so that they get recycled
        while (!isEmpty()) {
            remove(keySet().iterator().next());
        }

        // and then clear
        super.clear();
    }

    @Override
    protected boolean removeEldestEntry(final java.util.Map.Entry<MapTile, Drawable> aEldest) {
        if (size() > mCapacity) {
            final MapTile eldest = aEldest.getKey();
            if (Configuration.getInstance().isDebugMode()) {
                    Log.d(IMapView.LOGTAG,"LRU Remove old tile: " + eldest);
            }
            remove(eldest);
            // don't return true because we've already removed it
        }
        return false;
    }

    public TileRemovedListener getTileRemovedListener() {
        return mTileRemovedListener;
    }

    public void setTileRemovedListener(TileRemovedListener tileRemovedListener) {
        mTileRemovedListener = tileRemovedListener;
    }
}

1.2 MapTileCache

持有瓦片集合LRUMapTileCache,并有相应的瓦片操作方法

public class MapTileCache {

    protected final Object mCachedTilesLockObject = new Object();
    protected LRUMapTileCache mCachedTiles;//持有的瓦片集合

    public MapTileCache() {
        this(Configuration.getInstance().getCacheMapTileCount());
    }

    //最大缓存尺寸
    public MapTileCache(final int aMaximumCacheSize) {
        this.mCachedTiles = new LRUMapTileCache(aMaximumCacheSize);
    }

    public void ensureCapacity(final int aCapacity) {
        synchronized (mCachedTilesLockObject) {
            mCachedTiles.ensureCapacity(aCapacity);
        }
    }

    public Drawable getMapTile(final MapTile aTile) {
        synchronized (mCachedTilesLockObject) {
            return this.mCachedTiles.get(aTile);
        }
    }

    public void putTile(final MapTile aTile, final Drawable aDrawable) {
        if (aDrawable != null) {
            synchronized (mCachedTilesLockObject) {
                this.mCachedTiles.put(aTile, aDrawable);
            }
        }
    }

    public boolean containsTile(final MapTile aTile) {
        synchronized (mCachedTilesLockObject) {
            return this.mCachedTiles.containsKey(aTile);
        }
    }

    public void clear() {
        synchronized (mCachedTilesLockObject) {
            this.mCachedTiles.clear();
        }
    }
}

2.ExpirableBitmapDrawable

可过期图片,提供了不同的时间状态(更新状态 过期 缩放 没有发现 等状态)。

public class ExpirableBitmapDrawable extends BitmapDrawable {
    //状态
    public static final int UP_TO_DATE  = -1;
    public static final int EXPIRED     = -2;
    public static final int SCALED      = -3;
    public static final int NOT_FOUND   = -4;
    private static final int defaultStatus  = UP_TO_DATE;

    private static final int[] settableStatuses = new int[] {EXPIRED, SCALED, NOT_FOUND};

    private int[] mState;

    public ExpirableBitmapDrawable(final Bitmap pBitmap) {
        super(pBitmap);
        mState = new int[0];
    }

    @Override
    public int[] getState() {
        return mState;
    }

    @Override
    public boolean isStateful() {
        return mState.length > 0;
    }

    @Override
    public boolean setState(final int[] pStateSet) {
        mState = pStateSet;
        return true;
    }

    @Deprecated
    public static boolean isDrawableExpired(final Drawable pTile) {
        return getState(pTile) == EXPIRED;
    }

    public static int getState(final Drawable pTile) {
        for(final int statusItem : pTile.getState()) {
            for (final int statusReference : settableStatuses) {
                if (statusItem == statusReference) {
                    return statusItem;
                }
            }
        }
        return defaultStatus;
    }

    /**
     * @deprecated use {@link #setState(Drawable, int)} instead
     */
    @Deprecated
    public static void setDrawableExpired(final Drawable pTile) {
        setState(pTile, EXPIRED);
    }

    public static void setState(final Drawable pTile, final int status) {
        pTile.setState(new int[]{status});
    }
}

2.1 ReusableBitmapDrawable

继承自ExpirableBitmapDrawable,保持对图片使用引用跟踪。具体看内部方法。

public class ReusableBitmapDrawable extends ExpirableBitmapDrawable {

    private boolean mBitmapRecycled = false;
    private int mUsageRefCount = 0;

    public ReusableBitmapDrawable(Bitmap pBitmap) {
        super(pBitmap);
    }
    //开始使用图片
    public void beginUsingDrawable() {
        synchronized (this) {
            mUsageRefCount++;
        }
    }
    //结束使用图片
    public void finishUsingDrawable() {
        synchronized (this) {
            mUsageRefCount--;
            if (mUsageRefCount < 0)
                throw new IllegalStateException("Unbalanced endUsingDrawable() called.");
        }
    }
    //回收
    public Bitmap tryRecycle() {
        synchronized (this) {
            if (mUsageRefCount == 0) {
                mBitmapRecycled = true;
                return getBitmap();
            }
        }
        return null;
    }
    //检测是否有效
    public boolean isBitmapValid() {
        synchronized (this) {
            return !mBitmapRecycled;
        }
    }
}

2.2 BitmapPool

持有并管理所有的瓦片图片。

public class BitmapPool {
    final LinkedList<Bitmap> mPool = new LinkedList<Bitmap>();

    private static BitmapPool sInstance;

    public static BitmapPool getInstance() {
        if (sInstance == null)
            sInstance = new BitmapPool();

        return sInstance;
    }

    public void returnDrawableToPool(ReusableBitmapDrawable drawable) {
        Bitmap b = drawable.tryRecycle();
        if (b != null && b.isMutable())
            synchronized (mPool) {
                mPool.addLast(b);
            }
    }

    public void applyReusableOptions(final BitmapFactory.Options aBitmapOptions) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
            aBitmapOptions.inBitmap = obtainBitmapFromPool();
            aBitmapOptions.inSampleSize = 1;
            aBitmapOptions.inMutable = true;
        }
    }

    public Bitmap obtainBitmapFromPool() {
        synchronized (mPool) {
            if (mPool.isEmpty()) {
                return null;
            } else {
                final Bitmap bitmap = mPool.removeFirst();
                if (bitmap.isRecycled()) {
                    return obtainBitmapFromPool(); // recurse
                } else {
                    return bitmap;
                }
            }
        }
    }

    public Bitmap obtainSizedBitmapFromPool(final int aWidth, final int aHeight) {
        synchronized (mPool) {
            if (mPool.isEmpty()) {
                return null;
            } else {
                for (final Bitmap bitmap : mPool) {
                    if (bitmap.isRecycled()) {
                        mPool.remove(bitmap);
                        return obtainSizedBitmapFromPool(aWidth, aHeight); // recurse to prevent ConcurrentModificationException
                    } else if (bitmap.getWidth() == aWidth && bitmap.getHeight() == aHeight) {
                        mPool.remove(bitmap);
                        return bitmap;
                    }
                }
            }
        }

        return null;
    }

    public void clearBitmapPool() {
        synchronized (sInstance.mPool) {
            while (!sInstance.mPool.isEmpty()) {
                Bitmap bitmap = sInstance.mPool.remove();
                bitmap.recycle();
            }
        }
    }
}
OSMDroid 是一个开源的 Android 地图库,它允许开发者在 Android 应用程序中嵌入 OpenStreetMap 数据和地图功能。与原生 Google Maps API 不同,OSMDroid 是基于轻量级的 OSM 数据,这意味着它可以提供更好的离线地图支持,并且对隐私更加友好。 防止内存泄露(Memory Leaks)是 Android 开发中非常重要的一环,特别是在处理地图相关组件时,因为地图数据加载和绘制可能会占用大量内存。以下是一些避免 OSMDroid 防止内存泄露的方法: 1. **及时释放资源**:确保每次不再使用地图视图(MapView)、图层(Overlay)或数据源(TileProvider)时,调用相应的 `dispose()` 或 `removeAllOverlays()` 方法释放它们。 2. **使用弱引用**:对于持有地图对象的引用,可以考虑使用 WeakReference,这样即使其他强引用消失,弱引用也不会阻止垃圾回收。 3. **监听生命周期**:地图视图的 `OnDestroy()` 或 `onSaveInstanceState()` 方法中,记得清除地图相关的回调和监听器,以防止内存泄漏。 4. **批处理操作**:尽量减少在主线程执行耗时的操作,如绘制大图层或加载大量数据,可以使用异步任务或者 `AsyncTask` 来处理。 5. **使用 LruCache**:对于频繁访问但占用空间较大的地图数据,可以使用 LruCache 来缓存,当内存不足时自动清理最久未使用的数据。 6. **跟踪内存使用**:利用 Android 的内存分析工具(如 Android Studio 的 Memory Profiler 或第三方库如 LeakCanary)定期检查应用内存状况,找出可能的泄漏点。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值