使用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); }