【问题标题】:NoSuchMethodError using LruCache in Android在 Android 中使用 LruCache 的 NoSuchMethodError
【发布时间】:2012-05-22 17:15:35
【问题描述】:

我在使用从 Android 中的 LruCache 继承的自定义类时出错。 它应该下载图像并缓存它们;昨天,它正在工作,但今天早上我遇到了这个问题。

这是类的代码:

public class LruMemoryCache extends LruCache<String, Bitmap> {
    private final Context context;
    private static LruMemoryCache instance;

    private LruMemoryCache(Context context) {
//      super(1024 * 1024 * (((ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE)).getMemoryClass()) / 8);
        super(5 * 1024 * 1024);
        this.context = context;
    }

    public static synchronized LruMemoryCache getInstance(Context context) {
        if (instance == null) {
            instance = new LruMemoryCache(context);

        }
        return instance;
    }

    @Override
    protected int sizeOf(String key, Bitmap value) {
        return value.getByteCount();
    }

    public void loadBitmap(String url, ImageView imageView) {
        final String imageKey = url;
        final Bitmap bitmap = get(imageKey);
        if (bitmap != null) {
            imageView.setImageBitmap(bitmap);
        } else {
            BitmapWorkerTask task = new BitmapWorkerTask(imageView);
            task.execute(url);
        }
    }

    class BitmapWorkerTask extends AsyncTask<String, Void, Bitmap> {
        Bitmap myBitmap;
        ImageView mImageView;

        public BitmapWorkerTask(ImageView imageView) {
            mImageView = imageView;
        }

        @Override
        protected Bitmap doInBackground(String... params) {
            try {
                URL url = new URL("http://www.google.com/logos/classicplus.png");
                HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                connection.setDoInput(true);
                connection.connect();
                InputStream input = connection.getInputStream();
                myBitmap = BitmapFactory.decodeStream(input);
            } catch (IOException e) {
                e.printStackTrace();
            }

            put(params[0], myBitmap);
            return myBitmap;
        }

        @Override
        protected void onPostExecute(Bitmap result) {
            super.onPostExecute(result);
            mImageView.setImageBitmap(result);
        }
    }
}

这是来自 LogCat 的错误:

05-15 08:02:08.639: E/AndroidRuntime(12818): FATAL EXCEPTION: AsyncTask #2
05-15 08:02:08.639: E/AndroidRuntime(12818): java.lang.RuntimeException: An error occured while executing doInBackground()
05-15 08:02:08.639: E/AndroidRuntime(12818):    at android.os.AsyncTask$3.done(AsyncTask.java:200)
05-15 08:02:08.639: E/AndroidRuntime(12818):    at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:274)
05-15 08:02:08.639: E/AndroidRuntime(12818):    at java.util.concurrent.FutureTask.setException(FutureTask.java:125)
05-15 08:02:08.639: E/AndroidRuntime(12818):    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:308)
05-15 08:02:08.639: E/AndroidRuntime(12818):    at java.util.concurrent.FutureTask.run(FutureTask.java:138)
05-15 08:02:08.639: E/AndroidRuntime(12818):    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1088)
05-15 08:02:08.639: E/AndroidRuntime(12818):    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:581)
05-15 08:02:08.639: E/AndroidRuntime(12818):    at java.lang.Thread.run(Thread.java:1019)
05-15 08:02:08.639: E/AndroidRuntime(12818): Caused by: java.lang.NoSuchMethodError: getByteCount
05-15 08:02:08.639: E/AndroidRuntime(12818):    at com.xs2theworld.sundio.caching.LruMemoryCache.sizeOf(LruMemoryCache.java:36)
05-15 08:02:08.639: E/AndroidRuntime(12818):    at com.xs2theworld.sundio.caching.LruMemoryCache.sizeOf(LruMemoryCache.java:1)
05-15 08:02:08.639: E/AndroidRuntime(12818):    at android.support.v4.util.LruCache.safeSizeOf(LruCache.java:230)
05-15 08:02:08.639: E/AndroidRuntime(12818):    at android.support.v4.util.LruCache.put(LruCache.java:123)
05-15 08:02:08.639: E/AndroidRuntime(12818):    at com.xs2theworld.sundio.caching.LruMemoryCache$BitmapWorkerTask.doInBackground(LruMemoryCache.java:72)
05-15 08:02:08.639: E/AndroidRuntime(12818):    at com.xs2theworld.sundio.caching.LruMemoryCache$BitmapWorkerTask.doInBackground(LruMemoryCache.java:1)
05-15 08:02:08.639: E/AndroidRuntime(12818):    at android.os.AsyncTask$2.call(AsyncTask.java:185)
05-15 08:02:08.639: E/AndroidRuntime(12818):    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:306)
05-15 08:02:08.639: E/AndroidRuntime(12818):    ... 4 more

知道为什么会发生这种情况吗?

非常感谢大家。

编辑:我刚刚意识到 Google Galaxy Nexus S 手机不会发生此错误,但 Samsun Galaxy 会发生此错误。有人知道为什么吗?

【问题讨论】:

  • 你是如何解决这个问题的,因为我在getByteCount()上仍然遇到编译时错误
  • @Hunt 检查我下面的评论,接受的答案

标签: android caching android-lru-cache


【解决方案1】:

问题是由以下原因引起的:

@Override
    protected int sizeOf(String key, Bitmap value) {
        return value.getByteCount();
    }

getByteCount() 方法只能用于 API >= 12,而三星 Galaxy 使用 API 10。

解决方案:

@Override
    protected int sizeOf(String key, Bitmap value) {
        if (Integer.valueOf(android.os.Build.VERSION.SDK_INT) >= 12)
            return value.getByteCount();
        else
            return (value.getRowBytes() * value.getHeight());
    }

【讨论】:

    【解决方案2】:

    对于LruCache,请使用google的支持库,或者获取它的原始源代码。

    通常,要理解他们在源代码上做了什么是相当复杂的,但这次很容易。

    【讨论】:

    • 我明白了,所以你应该是 android 的代码。经过一些调整(更改 map.eldest() 部分)后,这对我有用:oschina.net/code/explore/android-4.0.1/core/java/android/util/…
    • @androiddeveloper 你能告诉我你是如何摆脱map.eldest()产生的错误的吗
    • 确定。要么覆盖 LinkedHashMap 的 removeEldestEntry() ,要么使用 cacheMap.keySet().iterator().next() ,这将返回你最老的 key 。然后您可以获取它的值(如果需要)并从 LinkedHashMap 中删除键。
    • @androiddeveloper 我已将Map.Entry&lt;K, V&gt; toEvict = map.eldest(); 替换为Map.Entry&lt;K, V&gt; toEvict = (Entry&lt;K, V&gt;) map.keySet().iterator().next(); 我希望这就足够了吗?
    【解决方案3】:

    我尝试了上述所有方法,它们都很接近,但并不完全正确(至少对于我的情况而言)。

    我使用的是 bitmap.getByteCount();创建新的 LruCache 时在 sizeOf() 方法内部:

    mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
        @Override
        protected int sizeOf(String key, Bitmap bitmap) {
            return bitmap.getByteCount();
        }
    };  
    

    然后我尝试了建议的:

    return bitmap.getRowBytes() * bitmap.getHeight();
    

    这很好,但我注意到返回的值不同,当我使用上面的建议时,它甚至不会在我的设备上进行缓存。我在运行 api 3.2 的 Nexus One 和运行 4.2 的 Galaxy Nexus 上测试了返回值:

    bitmap.getByteCount(); returned-> 15  
    bitmap.getRowBytes() * bitmap.getHeight(); returned-> 15400
    

    所以为了解决我的问题,我只是这样做了:

    return (bitmap.getRowBytes() * bitmap.getHeight()) / 1000; 
    

    代替:

    return bitmap.getByteCount();  
    

    可能与您所处的情况不同,但这对我有用。

    【讨论】:

    • 我看到的每一个地方,我读到的每一个资源,我看到的都是return (bitmap.getRowBytes() * bitmap.getHeight()) / 1000;。它必须是我正在保存的文件类型或其他东西。所以下次我需要使用bitmap.getByteCount();时,我会先做一些测试,看看我需要什么值。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-07
    • 2015-10-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-29
    相关资源
    最近更新 更多