在图片下载中,有时候图片太大会出现OOM(out of memory)异常,为了解决这个异常,我们需要对图片进行二次采样,也就是对图片进行压缩。
示例:对图片二次采样后显示在ListView上
ImageThread
package com.example.imageload;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.os.Message;
import android.widget.ImageView;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
/**
* 执行图片的下载和二次采样
* Created by 张样 on 2016/11/9.
*/
public class ImageThread implements Runnable{
/**
* 规定图片的最大值,高和宽的像素最大是100像素
*/
public static final int MAX_WIDTH = 100;
public static final int MAX_HEIGHT = 100;
/**
* 图片的地址
*/
private String imagePath;
private ImageView mImageView;
public ImageThread(String imagePath, ImageView mImageView) {
this.imagePath = imagePath;
this.mImageView = mImageView;
mImageView.setTag(imagePath);
}
private Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
//防止因为ListView的Item复用导致的图片出现跳动BUG
if (mImageView.getTag().equals(imagePath)){
Bitmap bitmap= (Bitmap) msg.obj;
mImageView.setImageBitmap(bitmap);
}
}
};
@Override
public void run() {
InputStream inputStream = null;
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
try {
//网络请求
URL url = new URL(imagePath);
HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
httpURLConnection.connect();
//请求成功
if (httpURLConnection.getResponseCode() == HttpURLConnection.HTTP_OK){
inputStream = httpURLConnection.getInputStream();
int len = 0;
byte[] buffer = new byte[1024];
while ((len = inputStream.read(buffer)) != -1){
outputStream.write(buffer,0,len);
}
outputStream.flush();
//讲图片流转换成Bitmap对象
byte[] bytes = outputStream.toByteArray();
//二次采样
BitmapFactory.Options options = new BitmapFactory.Options();
//options.inJustDecodeBounds为true表示仅仅获取图片的大小属性
options.inJustDecodeBounds = true;
//获取图片的大小,不加载图片的内容
BitmapFactory.decodeByteArray(bytes,0,bytes.length,options);
int outWidth = options.outWidth;
int outHeight = options.outHeight;
//计算压缩比
int widthRatio = outWidth/MAX_WIDTH ;
int heightRatio = outHeight/MAX_HEIGHT;
int ratio = widthRatio > heightRatio ? widthRatio : heightRatio;
//加载图片的内容,并且对图片按照比率进行压缩
options.inJustDecodeBounds = false;
//配置图片的压缩比
options.inSampleSize = ratio;
//图片转化
Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options);
//将Bitmap对象传递到主线程
Message message = mHandler.obtainMessage();
message.obj = bitmap;
mHandler.sendMessage(message);
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
inputStream.close();
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
ImageLoader
package com.example.imageload;
import android.widget.ImageView;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 开线程池执行图片加载
* Created by 张样 on 2016/11/9.
*/
public class ImageLoader {
private static ExecutorService executorService;
public static void load(String path, ImageView imageView){
init();
executorService.execute(new ImageThread(path,imageView));
}
private static void init(){
if (executorService == null){
executorService = Executors.newFixedThreadPool(5);
}
}
}
ImageAdapter
package com.example.imageload;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import java.util.List;
/**
* ListView适配器,在ListView上加载一张图片
* Created by 张样 on 2016/11/10.
*/
public class ImageAdaptet extends BaseAdapter {
private List<String> datas;
private Context context;
public ImageAdaptet(List<String> datas, Context context) {
this.datas = datas;
this.context = context;
}
@Override
public int getCount() {
return datas == null ? 0 :datas.size();
}
@Override
public Object getItem(int position) {
return position;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView = (ImageView) convertView;
if (imageView == null){
imageView = new ImageView(context);
}
//图片加载
String path = datas.get(position);
ImageLoader.load(path,imageView);
return imageView;
}
}
MainActivity
package com.example.imageload;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.ListView;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private List<String> paths = new ArrayList<>();
private ListView mListView;
private ImageAdaptet imageAdaptet;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initDatas();
initView();
}
private void initView() {
mListView = (ListView) findViewById(R.id.main_list_view);
imageAdaptet = new ImageAdaptet(paths,this);
mListView.setAdapter(imageAdaptet);
}
/**
* 加载网址
*/
private void initDatas() {
paths.add("http://www.1688wan.com/allimgs/img_iapp/201505/_1431668017101.jpg");
paths.add("http://www.1688wan.com/allimgs/img_iapp/201605/_1463125483599.png");
paths.add("http://www.1688wan.com/allimgs/img_iapp/201505/_1431668017101.jpg");
paths.add("http://www.1688wan.com/allimgs/img_iapp/201605/_1463125483599.png");
paths.add("http://www.1688wan.com/allimgs/img_iapp/201609/_1474445209925.jpg");
paths.add("http://www.1688wan.com/allimgs/img_iapp/201609/_1475201359049.png");
paths.add("http://www.1688wan.com/allimgs/img_iapp/201609/_1473834636728.png");
paths.add("http://www.1688wan.com/allimgs/img_iapp/201609/_1475201359049.png");
paths.add("http://www.1688wan.com/allimgs/img_iapp/201505/_1431668017101.jpg");
paths.add("http://www.1688wan.com/allimgs/img_iapp/201605/_1463125483599.png");
paths.add("http://www.1688wan.com/allimgs/img_iapp/201505/_1431668017101.jpg");
paths.add("http://www.1688wan.com/allimgs/img_iapp/201605/_1463125483599.png");
paths.add("http://www.1688wan.com/allimgs/img_iapp/201609/_1474445209925.jpg");
paths.add("http://www.1688wan.com/allimgs/img_iapp/201609/_1475201359049.png");
paths.add("http://www.1688wan.com/allimgs/img_iapp/201609/_1473834636728.png");
paths.add("http://www.1688wan.com/allimgs/img_iapp/201609/_1475201359049.png");
}
}
xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.imageload.MainActivity">
<ListView
android:id="@+id/main_list_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</RelativeLayout>
原理:BitmapFactory内部的图片解码,形成Bitmap是通过底层C/C++来实现的,有专门的图片界面库,可以通过参数来获取图片的尺寸,以及设置针对颜色加载的采样比率,采样比率就是把多个像素采样成一个像素,图片自然就变小了,最终传递给Java级别的对象,内存就变小了,图片也就变小了。