简体   繁体   English

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

[英]Android download image from server and save to sdcard without using BitmapFactory

I am trying to create an application that use to download image from server and show it into listview. 我正在尝试创建一个用于从服务器下载图像并将其显示到listview的应用程序。 The problem that I made was the leak of memory and make my application crash. 我做的问题是内存泄漏并使我的应用程序崩溃。 I was searching in Android blog such as this link , it show a great idea but it still not enough to do it with multiple thread. 我在Android博客中搜索此链接 ,它显示了一个好主意,但仍然不足以用多个线程来做。 Some device of android can work with it but some device can only handle in the single thread and sometimes it cannot work at all. android的某些设备可以使用它,但有些设备只能在单个线程中处理,有时它根本无法工作。

My application has many activity and each of them has a Listview that need to display image quick as possible. 我的应用程序有很多活动,每个活动都有一个Listview,需要尽快显示图像。 Through the Google IO 2012 they use buffer to save the original image to SD Card and it solve the problem Leak memory but it make loading so slow since the image that need to download was too big. 通过Google IO 2012,他们使用缓冲区将原始图像保存到SD卡,它解决了泄漏内存问题,但由于需要下载的图像太大,导致加载速度变慢。

My question is: Is there any way to scale image together with write image to SD Card? 我的问题是: 有没有办法将图像与写入SD卡一起缩放? I figure out some possible solution is to use Skip byte in the inputstream object and I was able to find Width and Height also Bit per pixel of the image that I need to download. 我想出一些可能的解决方案是在输入流对象中使用跳过字节,我能够找到我需要下载的图像的每像素的宽度和高度。

The following code was use in Google IO 2012 and it work well with multiple threading, in my case I have 4 thread running in the background. 以下代码在Google IO 2012中使用,它适用于多线程,在我的情况下,我有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) use the following code before setting your images to free the native object associated with this bitmap, and clear the reference to the pixel data. 1)在设置图像之前使用以下代码释放与此位图关联的本机对象,并清除对像素数据的引用。 It simply allows it to be garbage collected if there are no other references. 如果没有其他引用,它只是允许它被垃圾收集。

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

2) use this method to reduce the size of bitmap in memory: 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;
}

You can use this. 你可以用它。

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

} }

This code download the images without using bitmap factory,its not working in emulator,use any android phones 此代码不使用位图工厂下载图像,它不在模拟器中工作,使用任何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 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 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>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM