java - Android 高效地从 Drawable 加载图像

标签 java android image memory android-studio

我是 Android 开发新手,在弄清楚如何有效加载图像方面遇到了很多困难。我的问题的简短版本如下:我的 res/drawable 文件夹中有一些 png 图像。如何将这些图像加载到 Android 设备上而不会有 OutOfMemory 错误的风险?

以下是有关我的问题以及我尝试解决该问题的更多详细信息:

我编写了一个非常简单的程序,仅显示一张图像。代码如下:

public class TitleScreenActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_title_screen);
}

这是 R.layout.activity_title_screen 中的代码:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:background="@color/white"
    android:layout_height="match_parent">

    <ImageView
        android:id="@+id/title_screen_logo"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:adjustViewBounds="true"
        android:maxWidth="20000dp"
        android:maxHeight="20000dp"
        android:scaleType="fitCenter"
        android:contentDescription="@string/accessibility"
        android:src="@drawable/title_screen_logo" />
</RelativeLayout>

不幸的是,当我在模拟器上运行这个程序时,我收到了 java.lang.outOfMemoryError。我确定此错误的原因是我从 R.drawable.title_screen_logo 加载的图像,因为当我加载不同的图像时程序运行正常。令人困惑的是,考虑到我只加载一个图像,该图像的大小非常合理:183KB。由于我只加载一张图像,因此我不明白为什么会导致此错误。该错误是否是由图像大小以外的属性引起的?

我花了几天时间研究这个问题,并找到了一些不太好的解决方案,但没有一个能完美地工作。我尝试使用 Picasso 并对我的 Activity 进行了以下修改:

public class TitleScreenActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_title_screen);
        ImageView imageView = (ImageView) findViewById(R.id.title_screen_logo);
        DisplayMetrics displayMetrics = new DisplayMetrics();
        WindowManager wm = (WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
        wm.getDefaultDisplay().getMetrics(displayMetrics);
        int width = displayMetrics.widthPixels;
        Picasso.with(this)
                .load(R.drawable.title_screen)
                .resize(width, (int) ((width) *  0.736284058685735))
                .into(imageView);
}

基本上,这段代码的作用是找到设备的宽度,然后调整图像大小以具有该宽度和适当的高度(0.736284058685735 是图像的高度:宽度比率。这段代码可以工作,但我有很多问题这种方法:

  1. 在运行时为我想要加载的每个图像执行此操作似乎过多/不必要。使用这种方法会大大降低我的代码的可读性。
  2. 我必须删除 ImageView 上的 android:src 属性,以便在代码的 Picasso 部分运行之前不会使内存过载。这意味着在 Picasso 将某些内容放入 ImageView 之前,ImageView 不会显示任何内容,这实际上会产生短暂但明显的延迟,在程序打开后屏幕会变成空白。
  3. 这实际上似乎并没有完全解决问题;如果我使用 Picasso 将图像宽度缩小到屏幕宽度的一半(然后让 ImageView 的缩放属性将其放大),它会起作用,但如果我只将图像缩小到屏幕的整个宽度。虽然缩放到屏幕宽度的一半可以加载,但它会造成明显的质量损失,而且看起来像是一个任意数字;我无法保证内存较少的设备能够加载缩放到其宽度一半的版本。

由于这些问题,我现在正在考虑制作一堆不同的图像,这些图像只是适合每个 Android 指定的屏幕尺寸和密度(hdpi、mdpi、小、正常等)所需的最小尺寸和分辨率。 )但是,我不确定这是否能解决问题,因为图像一开始就很小。我不确定在降低质量之前我真的可以将其缩小多少,而且我也不确定需要将其缩小多少才能避免内存错误。我觉得一定有更好的方法,但我一辈子都找不到......

最佳答案

您应该使用此链接转换您的 png 图像(xxhdpi、mdpi 等..) https://romannurik.github.io/AndroidAssetStudio/nine-patches.html 根据您的设备自动更改图像

关于java - Android 高效地从 Drawable 加载图像,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32665582/

相关文章:

java - Eclipse 编译器从 protected 源读取 Java 依赖项

android - retrofit api中的任意属性通过json反序列化获取

javascript - 如何使用 Javascript 获取 'css-pixel'(媒体查询)宽度?

java - 表达式树和访问者模式的实现

java - Tomcat - 将 war 部署到远程 tomcat 时出现 NoClassDefFoundError

java - 使用 MySql 和 PHP 进行 Android 登录

html - 为什么我的图像忽略了其包含元素的大小(高度)?

python-3.x - 在不重新压缩 JPEG 图像的情况下更改 exif 数据

c# - Silverlight/C# 图像未找到异常处理

java - Guava 可选与 Bean 验证