Android有效地从Drawable加载图像

时间:2015-09-19 07:32:01

标签: java android image memory android-studio

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

以下是有关我的问题以及我尝试修复此问题的更多详细信息:

我写了一个非常简单的程序,只显示一个图像。这是代码:

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将不会显示任何内容,这实际上会产生一个短暂但明显的延迟,在该程序打开后屏幕只是空白。
  3. 这实际上似乎并没有完全解决问题;如果我使用Picasso将图像宽度缩小到屏幕宽度的一半(然后让ImageView的缩放属性将其缩放回来),它会起作用,但是如果我只将图像缩小到屏幕的整个宽度。当缩放到屏幕宽度的一半使其加载时,它会产生明显的质量损失,看起来像是一个任意数字;我不能保证内存较少的设备能够加载缩放到其宽度一半的版本。
  4. 由于这些问题,我现在正在考虑制作一堆不同的图像,这些图像只是满足每个Android指定的屏幕尺寸和密度(hdpi,mdpi,小,正常等)所需的最小尺寸和分辨率。 )但是,我不确定这会解决问题,因为图像开始时这么小。我不确定在降低质量之前我能做多少小,而且我也不确定为了避免内存错误我需要做多少。我觉得必须有更好的方法,但对于我的生活,我找不到它......

2 个答案:

答案 0 :(得分:1)

你应该使用这个链接转换你的png图像(xxhdpi,mdpi等..)    https://romannurik.github.io/AndroidAssetStudio/nine-patches.html     根据您的设备自动拍摄图像

答案 1 :(得分:0)

原因在于:

android:maxWidth="20000dp"
android:maxHeight="20000dp"

尝试删除这两行。您的应用只包含一个简单的图像,它与OutOfMemory错误无关。