Android从服务器下载图像并保存到SD卡而不使用BitmapFactory

我正在尝试创建一个用于从服务器下载图像并将其显示到listview的应用程序。 我做的问题是内存泄漏并使我的应用程序崩溃。 我在Android博客中搜索此链接 ,它显示了一个好主意,但仍然不足以用多个线程来做。 android的某些设备可以使用它,但有些设备只能在单个线程中处理,有时它根本无法工作。

我的应用程序有很多活动,每个活动都有一个Listview,需要尽可能快地显示图像。 通过Google IO 2012,他们使用缓冲区将原始图像保存到SD卡,它解决了泄漏内存的问题,但由于需要下载的图像太大,导致加载速度变慢。

我的问题是: 有没有办法将图像与写入SD卡一起缩放? 我想出一些可能的解决方案是在输入流对象中使用跳过字节,我能够找到Width和Height以及我需要下载的图像的每像素位数。

以下代码在Google IO 2012中使用,它适用于multithreading,在我的情况下,我有4个线程在后台运行。

private void downloadAndWriteFile(final String url, final File file) throws OutOfMemoryError { BufferedOutputStream out = null; try { HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection(); conn.setDoInput(true); conn.connect(); final InputStream in = new BufferedInputStream(conn.getInputStream(), IO_BUFFER_SIZE_BYTES); // buffer size 1KB out = new BufferedOutputStream(new FileOutputStream(file), IO_BUFFER_SIZE_BYTES); int b; while ((b = in.read()) != -1) { out.write(b); } out.close(); conn.disconnect(); } catch (Exception e) { Log.e(TAG, "!!downloadAndWriteFile " + e.getMessage()); file.delete(); } } 

1)在设置图像之前使用以下代码释放与此位图关联的本机对象,并清除对像素数据的引用。 如果没有其他引用,它只是允许它被垃圾收集。

 BitmapDrawable drawable = (BitmapDrawable) myImage.getDrawable(); Bitmap bitmap = drawable.getBitmap(); if (bitmap != null) { bitmap.recycle(); } 

2)使用此方法减小内存中位图的大小:

 /** * decodes image and scales it to reduce memory consumption * * @param file * @param requiredSize * @return */ public static Bitmap decodeFile(File file, int requiredSize) { try { // Decode image size BitmapFactory.Options o = new BitmapFactory.Options(); o.inJustDecodeBounds = true; BitmapFactory.decodeStream(new FileInputStream(file), null, o); // The new size we want to scale to // Find the correct scale value. It should be the power of 2. int width_tmp = o.outWidth, height_tmp = o.outHeight; int scale = 1; while (true) { if (width_tmp / 2 < requiredSize || height_tmp / 2 < requiredSize) break; width_tmp /= 2; height_tmp /= 2; scale *= 2; } // Decode with inSampleSize BitmapFactory.Options o2 = new BitmapFactory.Options(); o2.inSampleSize = scale; Bitmap bmp = BitmapFactory.decodeStream(new FileInputStream(file), null, o2); return bmp; } catch (FileNotFoundException e) { } finally { System.gc(); } return null; } 

你可以用它。

 private void downloadImagesToSdCard(String downloadUrl,String imageName) { try { URL url = new URL(downloadUrl); //you can write here any link File myDir = new File("/sdcard"+"/"+Constants.imageFolder); //Something like ("/sdcard/file.mp3") if (!myDir.exists()) { myDir.mkdir(); Log.v("", "inside mkdir"); } Random generator = new Random(); int n = 10000; n = generator.nextInt(n); String fname = imageName; File file = new File (myDir, fname); if (file.exists ()) file.delete (); /* Open a connection to that URL. */ URLConnection ucon = url.openConnection(); InputStream inputStream = null; HttpURLConnection httpConn = (HttpURLConnection)ucon; httpConn.setRequestMethod("GET"); httpConn.connect(); if (httpConn.getResponseCode() == HttpURLConnection.HTTP_OK) { inputStream = httpConn.getInputStream(); } /* * Define InputStreams to read from the URLConnection. */ // InputStream is = ucon.getInputStream(); /* * Read bytes to the Buffer until there is nothing more to read(-1). */ FileOutputStream fos = new FileOutputStream(file); int size = 1024*1024; byte[] buf = new byte[size]; int byteRead; while (((byteRead = inputStream.read(buf)) != -1)) { fos.write(buf, 0, byteRead); bytesDownloaded += byteRead; } /* Convert the Bytes read to a String. */ fos.close(); } catch(IOException io) { networkException = true; continueRestore = false; } catch(Exception e) { continueRestore = false; e.printStackTrace(); } 

}

此代码不使用位图工厂下载图像,它不在模拟器中工作,使用任何Android手机

 package com.example.filedownload; import org.apache.http.util.ByteArrayBuffer; import android.os.Bundle; import android.app.Activity; import android.util.Log; import android.view.Menu; import android.view.View; import android.widget.Button; import android.content.*; import android.app.*; import android.net.*; import android.app.DownloadManager.Request; import android.os.Environment; public class MainActivity extends Activity { public long reference; BroadcastReceiver receiver; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button button=(Button)findViewById(R.id.button1); button.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { String file = "http://sofzh.miximages.com/java/Beauty-of-nature-random-4884759-1280-800.jpg"; String serviceString = Context.DOWNLOAD_SERVICE; DownloadManager downloadManager; downloadManager = (DownloadManager)getSystemService(serviceString); Uri uri = Uri.parse(file); DownloadManager.Request request ; request = new Request(uri); request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "accel.jpg"); reference = downloadManager.enqueue(request); } }); IntentFilter filter = new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE); receiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { long ref = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1); if (reference == ref) { setContentView(R.layout.finalscreen); unregister(); } } }; registerReceiver(receiver, filter); } public void unregister(){ unregisterReceiver(receiver); } } 

activity_main.xml中

               

finalscreen.xml