当前位置: 首页 > 面试题库 >

如何将位图缓存到本机内存中

仲孙飞文
2023-03-14
问题内容

对于我的10,000点,我决定在这个很酷的网站上做出一些贡献:一种将位图缓存在本机内存中的机制。

背景
Android设备为每个应用程序分配的内存非常有限-堆的范围从16MB到128MB,具体取决于各种参数。

如果超过此限制,则会得到OOM,并且在使用位图时可能会发生多次。

很多时候,应用可能需要克服这些限制,对巨大的位图执行繁重的操作,或者只是将其存储以备后用,而您需要

我想出的是一个简单的Java类,它将使实现这些目的变得容易一些。

它使用JNI来存储位图数据,并能够在需要时进行还原。

为了支持该类的多个实例,我不得不使用发现的技巧(here)。

重要笔记
数据仍存储在RAM中,因此,如果设备没有足够的RAM,则该应用可能会被杀死。

记住要尽快释放内存。这不仅是为了避免内存泄漏,而且还是为了避免一旦您的应用程序出现在后台时被系统优先处理。

如果您不想忘记释放内存,则可以在每次还原位图时释放它,或者使该类实现Closable。

为了安全起见,我已使其在finalize()方法中自动释放其本机内存,但不要让它负责这项工作。太冒险了。当发生这种情况时,我也已将其写入日志。

它的工作方式是将整个数据复制到JNI对象中,并且为了还原,它从头开始创建位图并将数据放入其中。

正在使用和还原的位图为ARGB_8888格式。当然,您可以将其更改为所需的任何内容,只是不要忘记更改代码…

大的位图可能需要花费一些时间来存储和恢复,因此在后台线程上进行操作可能是明智的。

这不是完整的OOM解决方案,但可能会有所帮助。例如,您可以将其与您自己的LruCache结合使用,同时避免将堆内存用于缓存本身。

代码仅用于存储和还原。如果需要执行某些操作,则需要进行一些研究。openCV可能是答案,但是如果您希望执行一些基本的工作,则可以自己实现它们(这是使用JNI的可旋转大图像的示例)。如果您知道其他选择,请在此处告诉我。

希望这对某些人有用。请写下您的评论。

另外,如果您发现代码有任何问题或改进建议,请告诉我。


问题答案:

说明示例代码显示了如何存储2个不同的位图(较小的位图,但这只是一个演示),回收原始的Java位图,然后将它们还原为Java实例并使用它们。

您可能会猜到,该布局有2个imageViews。我没有在代码中包含它,因为它很明显。

请记住,如果需要,可以将代码更改为您自己的软件包,否则将无法正常工作。

MainActivity.java-如何使用:

package com.example.jnibitmapstoragetest;
...
public class MainActivity extends Activity
  {
  @Override
  protected void onCreate(final Bundle savedInstanceState)
    {
    super.onCreate(savedInstanceState);
    //
    Bitmap bitmap=BitmapFactory.decodeResource(getResources(),R.drawable.ic_launcher);
    final JniBitmapHolder bitmapHolder=new JniBitmapHolder(bitmap);
    bitmap.recycle();
    //
    Bitmap bitmap2=BitmapFactory.decodeResource(getResources(),android.R.drawable.sym_action_call);
    final JniBitmapHolder bitmapHolder2=new JniBitmapHolder(bitmap2);
    bitmap2.recycle();
    //
    setContentView(R.layout.activity_main);
      {
      bitmap=bitmapHolder.getBitmapAndFree();
      final ImageView imageView=(ImageView)findViewById(R.id.imageView1);
      imageView.setImageBitmap(bitmap);
      }
      {
      bitmap2=bitmapHolder2.getBitmapAndFree();
      final ImageView imageView=(ImageView)findViewById(R.id.imageView2);
      imageView.setImageBitmap(bitmap2);
      }
    }
  }

JniBitmapHolder.java-JNI和JAVA之间的“桥梁”:

package com.example.jnibitmapstoragetest;
...
public class JniBitmapHolder
  {
  ByteBuffer _handler =null;
  static
    {
    System.loadLibrary("JniBitmapStorageTest");
    }

  private native ByteBuffer jniStoreBitmapData(Bitmap bitmap);

  private native Bitmap jniGetBitmapFromStoredBitmapData(ByteBuffer handler);

  private native void jniFreeBitmapData(ByteBuffer handler);

  public JniBitmapHolder()
    {}

  public JniBitmapHolder(final Bitmap bitmap)
    {
    storeBitmap(bitmap);
    }

  public void storeBitmap(final Bitmap bitmap)
    {
    if(_handler!=null)
      freeBitmap();
    _handler=jniStoreBitmapData(bitmap);
    }

  public Bitmap getBitmap()
    {
    if(_handler==null)
      return null;
    return jniGetBitmapFromStoredBitmapData(_handler);
    }

  public Bitmap getBitmapAndFree()
    {
    final Bitmap bitmap=getBitmap();
    freeBitmap();
    return bitmap;
    }

  public void freeBitmap()
    {
    if(_handler==null)
      return;
    jniFreeBitmapData(_handler);
    _handler=null;
    }

  @Override
  protected void finalize() throws Throwable
    {
    super.finalize();
    if(_handler==null)
      return;
    Log.w("DEBUG","JNI bitmap wasn't freed nicely.please rememeber to free the bitmap as soon as you can");
    freeBitmap();
    }
  }

Android.mk-JNI的属性文件:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := JniBitmapStorageTest
LOCAL_SRC_FILES := JniBitmapStorageTest.cpp
LOCAL_LDLIBS := -llog
LOCAL_LDFLAGS += -ljnigraphics

include $(BUILD_SHARED_LIBRARY)
APP_OPTIM := debug
LOCAL_CFLAGS := -g

JniBitmapStorageTest.cpp-“神奇”的东西在这里:

#include <jni.h>
#include <jni.h>
#include <android/log.h>
#include <stdio.h>
#include <android/bitmap.h>
#include <cstring>
#include <unistd.h>

#define  LOG_TAG    "DEBUG"
#define  LOGD(...)  __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)
#define  LOGE(...)  __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)

extern "C"
  {
  JNIEXPORT jobject JNICALL Java_com_example_jnibitmapstoragetest_JniBitmapHolder_jniStoreBitmapData(JNIEnv * env, jobject obj, jobject bitmap);
  JNIEXPORT jobject JNICALL Java_com_example_jnibitmapstoragetest_JniBitmapHolder_jniGetBitmapFromStoredBitmapData(JNIEnv * env, jobject obj, jobject handle);
  JNIEXPORT void JNICALL Java_com_example_jnibitmapstoragetest_JniBitmapHolder_jniFreeBitmapData(JNIEnv * env, jobject obj, jobject handle);
  }

class JniBitmap
  {
  public:
    uint32_t* _storedBitmapPixels;
    AndroidBitmapInfo _bitmapInfo;
    JniBitmap()
      {
      _storedBitmapPixels = NULL;
      }
  };

JNIEXPORT void JNICALL Java_com_example_jnibitmapstoragetest_JniBitmapHolder_jniFreeBitmapData(JNIEnv * env, jobject obj, jobject handle)
  {
  JniBitmap* jniBitmap = (JniBitmap*) env->GetDirectBufferAddress(handle);
  if (jniBitmap->_storedBitmapPixels == NULL)


 类似资料:
  • 我创建了一个简单的应用程序,裁剪图像。现在我想保存这个图像到消防基地。 如何将此图像保存到Firebase。我尝试了很多教程,但都没有成功。请用简单的代码验证。

  • 问题内容: 我是所有内存管理主题的新手,所以有很多我不了解的事情。 我正在尝试将图像缓存在我的应用程序中,但是我在内存消耗方面遇到了麻烦: 所有的Bitmap Chaching代码都可以从此处复制粘贴:http : //developer.android.com/training/displaying- bitmaps/index.html 我调试了代码,并在Eclipse的DDMS视图中检查了堆

  • 在服务器重置缓存数据保存在磁盘存储后。但在服务器启动后不使用缓存数据。所以我想加载磁盘存储内容到memory.How做到这一点?在这个堆栈问题加载EhCache磁盘存储内容到内存中使用BootstrapCacheLoaderFactory但不为我出现。

  • 本文向大家介绍Android图片三级缓存策略(网络、本地、内存缓存),包括了Android图片三级缓存策略(网络、本地、内存缓存)的使用技巧和注意事项,需要的朋友参考一下 一、简介 现在的Android应用程序中,不可避免的都会使用到图片,如果每次加载图片的时候都要从网络重新拉取,这样不但很耗费用户的流量,而且图片加载的也会很慢,用户体验很不好。所以一个应用的图片缓存策略是很重要的。通常情况下,A

  • 我用ReactJS构建了一个渐进式Web应用程序,但遇到了一个问题。我正在使用mockApi获取数据。脱机时,我的应用程序不工作,因为服务人员只缓存静态资产。 如何将HTTP GET调用从mockApi保存到缓存存储?

  • 问题内容: 如何在WAMP中安装内存缓存? 我在中找不到任何php_memche 。 现在我该怎么做? @瑞安 感谢您的步骤,现在在WAMP中启用了内存缓存,我也已经在PHPINFO中进行了交叉检查。正在显示内存缓存。 我已经尝试过以下示例Memcache示例。但是抛出错误。 收到以下通知错误。 我错过了… 问题答案: 以下是对我有用的步骤: 所需文件 直接链接 Windows DLL文件 适用于