Download image from server and save to SD card without using BitmapFactory

I am trying to create an application that is used to download an image from a server and display it in a listview. The problem I did was memory leak and application crash. I searched on an Android blog, for example, a link, this is a great idea, but this is not enough to do this with multiple threads. Some Android device can work with it, but some device can only process one thread, and sometimes it cannot work at all.

My application has a lot of activity, and each of them has a Listview, which should be displayed as quickly as possible. Through Google IO 2012, they use a buffer to save the original image on the SD card, and it solves the problem of memory leak, but makes the download so slow that the image to be downloaded was too large.

My question is: Is there a way to scale the image along with recording the image on an SD card? I will find out some possible solution is to use a Skip byte in the input object, and I was able to find the width and height and bit per pixel of the image I need to load.

The following code was used in Google IO 2012, and it works well with multiple threads, in my case I have 4 threads running in the background.

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();
    }
}
+5
3

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;
}
+1

.

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();
}

}

0

factory, , 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://tmacfitness.com/wp-content/uploads/2013/04/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

<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"
    tools:context=".MainActivity" >

    <TableLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true" >

        <TableRow
            android:id="@+id/tableRow1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" >
        </TableRow>

        <TableRow
            android:id="@+id/tableRow2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" >

            <CheckedTextView
                android:id="@+id/checkedTextView1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Accel" />

        </TableRow>

        <TableRow
            android:id="@+id/tableRow3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" >

            <Button
                android:id="@+id/button1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Button" />

        </TableRow>

        <TableRow
            android:id="@+id/tableRow4"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" >
        </TableRow>
    </TableLayout>

</RelativeLayout>

finalscreen.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/textView1"
        android:layout_width="270dp"
        android:layout_height="wrap_content"
        android:layout_weight="2.12"
        android:text="DOWNLOAD COMPLETED" />

</LinearLayout>
0

All Articles