这几天在做图记的时候遇第一次遇到了OOM,好激动~~

追究原因,是因为在ListView中加载的图片太大造成的,因为我使用的都是手机相机直接拍摄的照片,图片都比较大,所以在加载的时候会出现内存溢出,那么我们就需要将图片压缩显示了。

首先,我们可以通过Bitmap.getWidth和 Bitmap.getHeight来获取一张图片的实际宽和高

MainActivity.java

package com.example.test3;

import java.io.IOException;
import java.io.InputStream; import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.view.Display;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast; public class MainActivity extends Activity { private ImageView iv;
private Button bt;
private int screenWidth, screenHeigh; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); bt = (Button) findViewById(R.id.bt);
iv = (ImageView) findViewById(R.id.img); // 获取屏幕信息
WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
screenWidth = display.getWidth();
screenHeigh = display.getHeight(); bt.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
try {
InputStream is = getAssets().open("pic.jpg");
Bitmap bitmap = BitmapFactory.decodeStream(is);
iv.setImageBitmap(bitmap);
int realWidth = bitmap.getWidth();
int realHeight = bitmap.getHeight();
Toast.makeText(MainActivity.this, "真实图片的宽:" + realWidth + ",真实图片的高:" + realHeight + "\n 屏幕宽度:"
+ screenWidth + ",屏幕高度:" + screenHeigh, Toast.LENGTH_SHORT).show();
is.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
}

运行结果:

当我们使用ListView来加载这些大图的时候,往往会出现内存溢出的情况,譬如下面:

MainActivity.java

package com.example.test3;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List; import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView; public class MainActivity extends Activity { private ListView lv;
private List list = new ArrayList(); @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); addItem(); lv = (ListView) findViewById(R.id.lv);
MyAdapter adapter = new MyAdapter(list, MainActivity.this);
lv.setAdapter(adapter);
} private void addItem() {
list.add("");
list.add("");
list.add("");
list.add("");
} class MyAdapter extends BaseAdapter { private List mList;
private Context mContext; public MyAdapter(List list, Context context) {
this.mList = list;
this.mContext = context;
} @Override
public int getCount() {
// TODO Auto-generated method stub
return mList.size();
} @Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return mList.get(position);
} @Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
} @Override
public View getView(int position, View convertView, ViewGroup parent) { View view = LayoutInflater.from(mContext).inflate(R.layout.item, null);
ImageView iv = (ImageView) view.findViewById(R.id.image);
try {
InputStream is = getAssets().open("pic.jpg");
Bitmap bitmap = BitmapFactory.decodeStream(is);
is.close();
iv.setImageBitmap(bitmap);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return view;
} }
}

因为我们没有对adapter做任何优化,所以我们每次滑动界面的时候,都会调用getView方法然后加载图片,这个时候就会出现OOM异常:

虽然出现OOM异常的原因有N多种,但就上个例子中,我们只需要将图片按照一定比例去缩小,然后在ListView中加载缩略图,就可以解决掉。

在Android的BitmapFactory.Options类,可以帮助我们对图片进行一系列的配置(不知道这个表述是否正确)

该类有一个成员变量inJustDecodeBounds,源码中对该变量的描述如下

If set to true, the decoder will return null (no bitmap), but the out... fields will still be set, allowing the caller to query the bitmap without having to allocate the memory for its pixels.

如果将其设置为true,那么在BitmapFactory.decodeXXX的时候将返回为null(不返回bitmap),但是允许调用者在不给这些bitmap分配内存的情况下查询该bitmap的信息。

那么我们就可以在不将其加载到内存的情况下,获取到该图片的宽高,我们修改getView方法中的代码:

        public View getView(int position, View convertView, ViewGroup parent) {

            View view = LayoutInflater.from(mContext).inflate(R.layout.item, null);
ImageView iv = (ImageView) view.findViewById(R.id.image); BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true; try {
InputStream is = getAssets().open("pic.jpg");
Bitmap bitmap = BitmapFactory.decodeStream(is, null, options);
int width = options.outWidth;
int height = options.outHeight;
Log.d("TTTT", "width=" + width + ",height=" + height);
is.close();
iv.setImageBitmap(bitmap);
} catch (IOException e) {
e.printStackTrace();
} return view;
}

输出结果为:

并且在程序界面并没有显示图片,因为decodeStream返回值为null

继续修改getView方法,这次我们加载一张5000*5000的大图

@Override
public View getView(int position, View convertView, ViewGroup parent) { View view = LayoutInflater.from(mContext).inflate(R.layout.item, null);
ImageView iv = (ImageView) view.findViewById(R.id.image); BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true; try {
inputStream = getAssets().open("big_pic.png");
BitmapFactory.decodeStream(inputStream, null, options);
// 图片真实宽高
int picWidth = options.outWidth;
int picHeight = options.outHeight;
Log.d("TTTT", "图片的真实width:" + picWidth + ",图片的真实height:" + picHeight);
// 手机屏幕宽高
WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
int screenWidth = display.getWidth();
int screenHeight = display.getHeight();
Log.d("TTTT", "屏幕的width:" + screenWidth + ",屏幕的height:" + screenHeight); // 获取缩放比例
int scaleX = picWidth / screenWidth;
int scaleY = picHeight / screenHeight;
// 设置默认缩放比例为1
int scale = 1;
if (scaleX >= scaleY & scaleY >= 1) {
scale = scaleX;
} else if (scaleY >= scaleX & scaleX >= 1) {
scale = scaleY;
}
Log.d("TTTT", "缩放比例为:" + scale);
options.inJustDecodeBounds = false;
options.inSampleSize = scale;
inputStream = getAssets().open("big_pic.png");
Bitmap bitmap = BitmapFactory.decodeStream(inputStream, null, options);
Log.d("TTTT", "缩放后的width:" + bitmap.getWidth() + ",缩放后的height:" + bitmap.getHeight());
inputStream.close();
iv.setImageBitmap(bitmap);
} catch (IOException e) {
e.printStackTrace();
}
return view;
}

再次运行:

系统提示:

图片的真实width:5000,图片的真实height:5000
屏幕的width:1080,屏幕的height:1776
缩放比例为:4
缩放后的width:1250,缩放后的height:1250

在上面的代码中我们可以看到,我们讲injust inJustDecodeBounds设置为了false,表示我们要将bitmap加载到内存中去了,并且我们使用inSampleSize来设置了缩放比例

至此,图片缩放完成

Android笔记(七十五) Android中的图片压缩的更多相关文章

  1. Android笔记(六十五) android中的动画——属性动画(propertyanimation)

    补间动画只能定义起始和结束两个帧在“透明度”.“旋转”.“倾斜”.“位移”4个方面的变化,逐帧动画也只能是播放多个图片,无法满足我们日常复杂的动画需求,所以谷歌在3.0开始,推出了属性动画(prope ...

  2. Android笔记(十五) Android中的基本组件——单选框和复选框

    单选框和多选框通常用来在设置用户个人资料时候,选择性别.爱好等,不需要用户直接输入,直接在备选选项中选择,简单方便. 直接看代码: <?xml version="1.0" e ...

  3. Android笔记(七十六) 点菜DEMO

    一个朋友让看一下他的代码,一个点菜的功能,他和我一样,初学者,代码比我的都混乱,也是醉了,干脆想着自己写个demo给他看,原本想着听简单,半个小时应该就可以搞定,真正写的时候,画了3h+,汗颜... ...

  4. Android笔记(七十四) 详解Intent

    我们最常使用Intent来实现Activity之间的转跳,最近做一个app用到从系统搜索图片的功能,使用到了intent的 setType 方法和 setAction 方法,网上搜索一番,发现实现转跳 ...

  5. Android笔记(七十二) Style和Theme

    我们尝尝需要使用setText.setColor.setTextSize等属性来设置控件的样式,但是每个控件都需要设置这些属性,工作量无疑是巨大的,并且后期维护起来也不方便. Style Androi ...

  6. Android笔记(六十六) android中的动画——XML文件定义属性动画

    除了直接在java代码中定义动画之外,还可以使用xml文件定义动画,以便重用. 如果想要使用XML来编写动画,首先要在res目录下面新建一个animator文件夹,所有属性动画的XML文件都应该存放在 ...

  7. Android笔记(十) Android中的布局——表格布局

    TableLayout运行我们使用表格的方式来排列控件,它的本质依然是线性布局.表格布局采用行.列的形式来管理控件,TableLayout并不需要明确的声明包含多少行多少列,而是通过添加TableRo ...

  8. Android笔记(七十) AlertDialog

    alertdialog可以在当前界面中弹出一个对话框,这个对话框在界面所有元素之上,可以屏蔽掉其他控件的交互能力,因此alertdialog常用于一些重要的内容警告. 使用AlertDialog.Bu ...

  9. Android笔记(六十四) android中的动画——补间动画(tweened animation)

    补间动画就是只需要定义动画开始和结束的位置,动画中间的变化由系统去补齐. 补间动画由一下四种方式: 1.AplhaAnimation——透明度动画效果 2.ScaleAnimation ——缩放动画效 ...

随机推荐

  1. mark_Linux_wc

    Linux wc命令 Linux wc命令用于计算字数. 利用wc指令我们可以计算文件的Byte数.字数.或是列数,若不指定文件名称.或是所给予的文件名为"-",则wc指令会从标准 ...

  2. visual studio 2019 error MSB3073 exited with code 1

    在用vs2019编译C++工程时,出现错误. 原因是设置的命令没有运行成功,需要将这条命令关闭.不编译就行了. 解决方法,打开property manager,打开property pages,将其中 ...

  3. IDEA强制清除Maven缓存

    目录 重新导入依赖的常见方式 存在的问题 彻底清除IDEA缓存的方式 重新导入依赖的常见方式 下面图中的刷新按钮,在我的机器上,并不能每次都正确导入pom.xml中写的依赖项,而是导入之前pom.xm ...

  4. PHPExcel 导出数据(xls或xlsx)- 助手类(函数)

    本文链接:https://www.cnblogs.com/tujia/p/11358096.html 说明:简单好用的导出助手,轻松导出数据到 excel !! 使用示例: Example: Exce ...

  5. Spring MVC -- 下载文件

    像图片或者HTML文件这样的静态资源,在浏览器中打开正确的URL即可下载,只要该资源是放在应用程序的目录下,或者放在应用程序目录的子目录下,而不是放在WEB-INF下,tomcat服务器就会将该资源发 ...

  6. makefile那些事儿

    一.好处 自动化编译,一条make命令,整个工程可以完全自动编译,make命令是构建大型项目的首选方案. makefile就像一个shell脚本一样,用来定义规则,一个名称包含一条或多条命令,在终端m ...

  7. 你该怎么学习C++——思想层面

    Javascript是世界上最受误解的语言,其实C++何尝不是.坊间流传的错误的C++学习方法一抓就是一大把.我自己在学习C++的过程中也走了许多弯路,浪费了不少时间. 为什么会存在这么多错误认识?原 ...

  8. Centos7安装部署Rabbitmq教程

    依赖关系: 版本依赖一定要提前看清楚. RabbitMQ相关版本依赖关系查看 https://www.rabbitmq.com/which-erlang.html 可以看到要求版本Erlang21.3 ...

  9. (二)Python的应用领域

    Python 的应用领域主要有如下几个: Web应用开发 Python 经常被用于 Web 开发,尽管目前 PHP.JS 依然是 Web 开发的主流语言,但 Python 上升势头更劲.尤其随着 Py ...

  10. CentOS7-Docker 搭建Maven私服

    使用Docker搭建Maven私服 前言本文主要介绍,使用Docker创建一个nexus私服,然后编写一个Library,上传到私服,然后使用demo工程依赖. 本文不对Maven.Nexus.私服等 ...