使用HttpClient方式从网络上下载一张大的图片的Bitmap对象,用ImageView显示出来,运行下面的代码会下面的错误:
05-10 13:42:57.206: D/skia(2250): --- SkImageDecoder::Factory returned null
代码:
package com.test.demo;
import java.io.InputStream;
import java.sql.Date;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Rect;
import android.util.Log;
public class ImageUtil {
public static Bitmap decodeSampledBitmapFromResource(Resources res,
int resId, int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth,
reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}
public static Bitmap decodeSampledBitmapFromStream(InputStream is,
int reqWidth, int reqHeight, Rect outPadding){
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(is, outPadding, options);
options.inSampleSize = calculateInSampleSize(options, reqWidth,
reqHeight);
options.inJustDecodeBounds = false;
Log.i("outPadding", "---------");
return BitmapFactory.decodeStream(is, outPadding, options);
}
public static Bitmap decodeSampledBitmapFromByteArray(byte[]data,
int reqWidth, int reqHeight, Rect outPadding){
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeByteArray(data, 0, data.length, options);
options.inSampleSize = calculateInSampleSize(options, reqWidth,
reqHeight);
options.inJustDecodeBounds = false;
Log.i("outPadding", "---------");
return BitmapFactory.decodeByteArray(data, 0, data.length, options);
}
public static int calculateInSampleSize(BitmapFactory.Options options,
int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
// Calculate the largest inSampleSize value that is a power of 2 and
// keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) > reqHeight
&& (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
}
package com.test.demo;
import java.io.IOException;
import java.io.InputStream;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.entity.BufferedHttpEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.ImageView;
public class LoadbigimageActivity extends Activity {
private ImageView imageView;
private DownloadTask task;
private ImageUtil util;
private String url = "https://unsplash.imgix.net/photo-1430132594682-16e1185b17c5?fit=crop&fm=jpg&h=700&q=75&w=1050";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_loadbigimage);
imageView = (ImageView) findViewById(R.id.imageView1);
util = new ImageUtil();
task = new DownloadTask();
Matrix matrix = imageView.getImageMatrix();
Log.i("outPadding", matrix.toString());
task.execute(url);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.loadbigimage, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
private class DownloadTask extends AsyncTask<String, Void, Bitmap> {
@Override
protected Bitmap doInBackground(String... params) {
// TODO Auto-generated method stub
Bitmap bitmap = null;
HttpClient httpClient = new DefaultHttpClient();
HttpGet get = new HttpGet(params[0]);
try {
HttpResponse response = httpClient.execute(get);
if (response.getStatusLine().getStatusCode() == 200) {
BufferedHttpEntity bufEntity = new BufferedHttpEntity(
response.getEntity());
InputStream inputStream = bufEntity.getContent();
Rect outPadding = new Rect();
byte[] data = EntityUtils.toByteArray(bufEntity);
bitmap = ImageUtil.decodeSampledBitmapFromStream(
inputStream, 100, 100, outPadding);
// bitmap = ImageUtil.decodeSampledBitmapFromByteArray(data,
// 100, 100, outPadding);
Log.i("outPadding", outPadding.toString());
} else {
Log.i("outPadding", "network error");
}
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return bitmap;
}
@Override
protected void onPostExecute(Bitmap result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
imageView.setImageBitmap(result);
}
}
}
解决方法一:不使用decodeStream,而是使用decodeByteArray方式进行获取Bitmap.
bitmap = ImageUtil.decodeSampledBitmapFromByteArray(data,100, 100, outPadding);
解决方法二:
stackverflow相关讨论:
http://stackoverflow.com/questions/12006785/android-skimagedecoder-factory-returned-null
按照下面的思路
I have encountered the same problem. And also I make sure the url is correct to download the image. By debugging the code, I found the variable of position in inputstream was set to 1024 after the first decode. So I add inputstream.reset() before the second decode. That works. Hope can help others.
修改decodeSampledBitmapFromStream函数,在第一次decodeStream后面调用InputStream的reset(),问题解决。
修正后代码如下
public static Bitmap decodeSampledBitmapFromStream(InputStream is,
int reqWidth, int reqHeight, Rect outPadding){
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(is, outPadding, options);
try {
is.reset();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
options.inSampleSize = calculateInSampleSize(options, reqWidth,
reqHeight);
options.inJustDecodeBounds = false;
Log.i("outPadding", "---------");
return BitmapFactory.decodeStream(is, outPadding, options);
}