[英]Caching google map v2 markers bitmaps
这将需要一些时间,但是如果您能忍受我,不胜感激,并且我相信这对其他人也将是有用的。
我在我的Android应用中使用Google Map放置不同的标记。 每个标记属于一个由位图表示的类别。 我一直在使用“ 有效 显示位图”中的BitmapFun示例在我的应用程序中缓存位图,并尝试使用Google地图标记实现相同的解决方案。
我的代码已添加到示例的ImageWorker.java中,如下所示(BitmapWorkerTask已经存在,并且已更新为可以处理标记):
private static Map<Marker, BitmapWorkerTask> markerToTaskMap = new HashMap<Marker, BitmapWorkerTask>();
public void loadImage(Object data, Marker marker) {
if (data == null) {
return;
}
BitmapDrawable value = null;
if (mImageCache != null) {
value = mImageCache.getBitmapFromMemCache(String.valueOf(data));
}
if (value != null) {
// Bitmap found in memory cache
marker.setIcon(BitmapDescriptorFactory.fromBitmap(value.getBitmap()));
} else if (cancelPotentialWork(data, marker)) {
final BitmapWorkerTask task = new BitmapWorkerTask(marker);
markerToTaskMap.put(marker, task);
task.executeOnExecutor(AsyncTask.DUAL_THREAD_EXECUTOR, data);
}
}
private class BitmapWorkerTask extends AsyncTask<Object, Void, BitmapDrawable> {
private Object data;
private WeakReference<ImageView> imageViewReference = null;
private WeakReference<Marker> markerReference = null;
public BitmapWorkerTask(ImageView imageView) {
imageViewReference = new WeakReference<ImageView>(imageView);
}
public BitmapWorkerTask(Marker marker) {
markerReference = new WeakReference<Marker>(marker);
}
/**
* Background processing.
*/
@Override
protected BitmapDrawable doInBackground(Object... params) {
if (BuildConfig.DEBUG) {
Log.d(TAG, "doInBackground - starting work");
}
data = params[0];
final String dataString = String.valueOf(data);
Bitmap bitmap = null;
BitmapDrawable drawable = null;
// Wait here if work is paused and the task is not cancelled
synchronized (mPauseWorkLock) {
while (mPauseWork && !isCancelled()) {
try {
mPauseWorkLock.wait();
} catch (InterruptedException e) {}
}
}
// If the image cache is available and this task has not been cancelled by another
// thread and the ImageView that was originally bound to this task is still bound back
// to this task and our "exit early" flag is not set then try and fetch the bitmap from
// the cache
if (mImageCache != null && !isCancelled() && (getAttachedImageView() != null || getAttachedMarker() != null)
&& !mExitTasksEarly) {
bitmap = mImageCache.getBitmapFromDiskCache(dataString);
}
// If the bitmap was not found in the cache and this task has not been cancelled by
// another thread and the ImageView that was originally bound to this task is still
// bound back to this task and our "exit early" flag is not set, then call the main
// process method (as implemented by a subclass)
if (bitmap == null && !isCancelled() && (getAttachedImageView() != null || getAttachedMarker() != null)
&& !mExitTasksEarly) {
bitmap = processBitmap(params[0]);
}
// If the bitmap was processed and the image cache is available, then add the processed
// bitmap to the cache for future use. Note we don't check if the task was cancelled
// here, if it was, and the thread is still running, we may as well add the processed
// bitmap to our cache as it might be used again in the future
if (bitmap != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
// Running on Honeycomb or newer, so wrap in a standard BitmapDrawable
drawable = new BitmapDrawable(mResources, bitmap);
} else {
// Running on Gingerbread or older, so wrap in a RecyclingBitmapDrawable
// which will recycle automagically
drawable = new RecyclingBitmapDrawable(mResources, bitmap);
}
if (mImageCache != null) {
mImageCache.addBitmapToCache(dataString, drawable);
}
}
if (BuildConfig.DEBUG) {
Log.d(TAG, "doInBackground - finished work");
}
return drawable;
}
/**
* Once the image is processed, associates it to the imageView
*/
@Override
protected void onPostExecute(BitmapDrawable value) {
// if cancel was called on this task or the "exit early" flag is set then we're done
if (isCancelled() || mExitTasksEarly) {
value = null;
}
if (imageViewReference != null) {
final ImageView imageView = getAttachedImageView();
if (value != null && imageView != null) {
if (BuildConfig.DEBUG) {
Log.d(TAG, "onPostExecute - setting bitmap");
}
setImageDrawable(imageView, value);
}
} else if (markerReference != null) {
final Marker marker = getAttachedMarker();
if (value != null && marker != null) {
if (BuildConfig.DEBUG) {
Log.d(TAG, "onPostExecute - setting marker bitmap");
}
markerToTaskMap.remove(marker);
marker.setIcon(BitmapDescriptorFactory.fromBitmap(value.getBitmap()));
}
}
}
@Override
protected void onCancelled(BitmapDrawable value) {
super.onCancelled(value);
synchronized (mPauseWorkLock) {
mPauseWorkLock.notifyAll();
}
}
/**
* Returns the ImageView associated with this task as long as the ImageView's task still
* points to this task as well. Returns null otherwise.
*/
private ImageView getAttachedImageView() {
if (imageViewReference == null) {
return null;
}
final ImageView imageView = imageViewReference.get();
final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);
if (this == bitmapWorkerTask) {
return imageView;
}
return null;
}
private Marker getAttachedMarker() {
if (markerReference == null) {
return null;
}
final Marker marker = markerReference.get();
final BitmapWorkerTask bitmapWorkerTask = markerToTaskMap.get(marker); //getBitmapWorkerTask(marker);
if (this == bitmapWorkerTask) {
return marker;
}
return null;
}
}
public static boolean cancelPotentialWork(Object data, Marker marker) {
final BitmapWorkerTask bitmapWorkerTask = markerToTaskMap.get(marker);
if (bitmapWorkerTask != null) {
final Object bitmapData = bitmapWorkerTask.data;
if (bitmapData == null || !bitmapData.equals(data)) {
bitmapWorkerTask.cancel(true);
if (BuildConfig.DEBUG) {
Log.d(TAG, "cancelPotentialWork - cancelled work for " + data);
}
} else {
// The same work is already in progress.
return false;
}
}
return true;
}
如果您熟悉BitmapFun示例,则可以看到,除了使用AsyncDrawable将位图连接到其加载的AsyncTask之外,其他操作几乎与在ImageView中使用位图相同。 由于我无法扩展Marker类(这是最终的),并且没有getIcon()方法,因此我必须维护一个hashmap(markerToTaskMap)才能完成此工作。
该解决方案似乎总体上可行,除了一些小故障,即我为标记获得错误的位图。 我不知道为什么。 OOB示例代码不会发生这种情况。
感谢有人可以在这里帮助我。 谢谢。
我可以要求您不要这样做,以为您提供帮助。
如果您想进行优化,请更好地了解您的敌人。 对Google Maps Android API v2的每次调用都将涉及其他过程。 而且大多数都需要在主线程上完成。
因为对API的每次调用都同步到达其他进程,所以它将阻塞用户界面。 例如,在一个体面的电话上添加2000个标记将花费1秒(经过测试)。 另一方面,加载20个小的位图以表示onCreate
类别将花费不到100毫秒(未经声明的声明)。 因此,您的代码甚至会减慢速度,因为您至少有2个调用来添加Marker
: addMarker
和setIcon
。
只需使用BitmapDescriptorFactory.fromResource
将所有Bitmap
加载到Map<Category, BitmapDescriptor>
一次,然后在创建Marker
使用它们。
总结一下:除非有问题,否则不要进行优化。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.