【发布时间】:2015-09-19 07:32:00
【问题描述】:
我是 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 是图像的高度:宽度比。这段代码有效,但我有很多问题这种方法:
- 对于我要加载的每个图像,在运行时都需要这样做似乎过多/不必要。使用这种方法会大大降低我的代码的可读性。
- 我必须在我的 ImageView 上删除 android:src 属性,这样它才不会在代码的 Picasso 部分运行之前使内存过载。这意味着 ImageView 在 Picasso 放入某些内容之前不会显示任何内容,这实际上会造成短暂但明显的延迟,在该延迟中,程序打开后屏幕只是空白。
- 这实际上似乎并没有完全解决问题;如果我使用 Picasso 将图像宽度缩小到屏幕宽度的一半(然后让 ImageView 的缩放属性将其放大),它会起作用,但如果我只将图像缩小到屏幕的整个宽度。虽然缩放到屏幕宽度的一半会使其加载,但它会造成明显的质量损失,并且看起来像是一个任意数字;我不能保证内存较少的设备能够加载缩放到其宽度一半的版本。
由于这些问题,我现在正在考虑制作一堆不同的图像,这些图像只是适合每个 Android 指定的屏幕尺寸和密度(hdpi、mdpi、小、正常等)所需的最小尺寸和分辨率。 )但是,我不确定这是否会解决问题,因为图像一开始就很小。我不确定在降低质量之前我真的能把它缩小多少,我也不确定我需要把它缩小多少才能避免内存错误。我觉得一定有更好的方法,但对于我的生活我找不到它......
【问题讨论】:
-
这里你可以参考android官方文档来高效处理位图developer.android.com/training/displaying-bitmaps/index.html你也可以找缓存
-
为什么只使用 Drawable 目录而不使用 drawable-ldpi/hdpi/xhdpi 等目录以便更好地使用?
-
为什么你给imageview的宽度和高度这么多的值“20000dp”,尝试使用'match parent'
标签: java android image memory android-studio