วิธีดาวน์โหลดและบันทึกภาพใน Android


คำตอบ:


224

แก้ไข ณ วันที่ 30.12.2015 - สุดยอดคำแนะนำในการดาวน์โหลดรูปภาพ


การอัปเดตที่สำคัญล่าสุด: 31 มีนาคม 2559


TL; DR aka หยุดพูดแค่ให้รหัส !!

ข้ามไปที่ด้านล่างของโพสต์นี้คัดลอกBasicImageDownloader(รุ่น javadoc ที่นี่ ) ลงในโปรเจ็กต์ของคุณใช้OnImageLoaderListenerอินเทอร์เฟซเท่านี้ก็เสร็จเรียบร้อย

หมายเหตุ : แม้ว่าBasicImageDownloaderข้อผิดพลาดที่อาจเกิดขึ้นได้และจะป้องกันไม่ให้แอปของคุณหยุดทำงานในกรณีที่มีข้อผิดพลาดเกิดขึ้น แต่จะไม่ดำเนินการหลังการประมวลผลใด ๆ (เช่นการลดขนาด) ในBitmapsแอป


เนื่องจากโพสต์นี้ได้รับความสนใจค่อนข้างมากฉันจึงตัดสินใจทำใหม่ทั้งหมดเพื่อป้องกันไม่ให้ผู้คนใช้เทคโนโลยีที่เลิกใช้งานการเขียนโปรแกรมที่ไม่ดีหรือเพียงแค่ทำเรื่องโง่ ๆ เช่นกำลังมองหา "แฮ็ก" เพื่อเรียกใช้เครือข่ายในเธรดหลักหรือ ยอมรับใบรับรอง SSL ทั้งหมด

ฉันได้สร้างโปรเจ็กต์สาธิตชื่อ "Image Downloader" ซึ่งสาธิตวิธีดาวน์โหลด (และบันทึก) รูปภาพโดยใช้การติดตั้งโปรแกรมดาวน์โหลดของฉันเอง, แอนดรอยด์ในตัวและDownloadManagerไลบรารีโอเพนซอร์สยอดนิยมบางรายการ คุณสามารถดูรหัสต้นฉบับที่สมบูรณ์หรือดาวน์โหลดโครงการบน GitHub

หมายเหตุ : ฉันยังไม่ได้ปรับการจัดการสิทธิ์สำหรับ SDK 23+ (Marshmallow) ดังนั้นโครงการจึงกำหนดเป้าหมายไปที่ SDK 22 (Lollipop)

ในบทสรุปของฉันในตอนท้ายของโพสต์นี้ฉันจะแบ่งปันความคิดเห็นอันต่ำต้อยของฉันเกี่ยวกับกรณีการใช้งานที่เหมาะสมสำหรับวิธีการดาวน์โหลดภาพแต่ละวิธีที่ฉันได้กล่าวถึง

เริ่มต้นด้วยการใช้งานของตัวเอง (คุณสามารถดูรหัสได้ที่ท้ายโพสต์) ก่อนอื่นนี่คือBasic ImageDownloader และนั่นแหล่ะ เพียงแค่เชื่อมต่อกับ url ที่กำหนดอ่านข้อมูลและพยายามถอดรหัสเป็น a Bitmapเรียกใช้OnImageLoaderListenerอินเทอร์เฟซเรียกกลับตามความเหมาะสม ข้อดีของแนวทางนี้ - ง่ายและคุณมีภาพรวมที่ชัดเจนว่าเกิดอะไรขึ้น วิธีที่ดีหากสิ่งที่คุณต้องการคือการดาวน์โหลด / แสดงและบันทึกภาพบางภาพในขณะที่คุณไม่สนใจเกี่ยวกับการดูแลหน่วยความจำ / ดิสก์แคช

หมายเหตุ: ในกรณีของภาพขนาดใหญ่คุณอาจจำเป็นต้องปรับขนาดพวกเขาลง

-

Android DownloadManagerเป็นวิธีที่จะให้ระบบจัดการการดาวน์โหลดให้คุณ มันสามารถดาวน์โหลดไฟล์ได้ทุกประเภทไม่ใช่แค่รูปภาพเท่านั้น คุณอาจปล่อยให้การดาวน์โหลดของคุณเกิดขึ้นโดยเงียบและผู้ใช้มองไม่เห็นหรือคุณสามารถเปิดให้ผู้ใช้เห็นการดาวน์โหลดในพื้นที่แจ้งเตือน คุณยังสามารถลงทะเบียนBroadcastReceiverเพื่อรับการแจ้งเตือนหลังจากดาวน์โหลดเสร็จสิ้น การตั้งค่าค่อนข้างตรงไปตรงมาดูโครงการที่เชื่อมโยงสำหรับโค้ดตัวอย่าง

โดยDownloadManagerทั่วไปการใช้สิ่งนี้ไม่ใช่ความคิดที่ดีหากคุณต้องการแสดงภาพด้วยเนื่องจากคุณจำเป็นต้องอ่านและถอดรหัสไฟล์ที่บันทึกไว้แทนที่จะตั้งค่าไฟล์ที่ดาวน์โหลดBitmapมาเป็นImageViewไฟล์. DownloadManagerยังไม่ได้ให้ API ใด ๆ สำหรับคุณ app เพื่อติดตามความคืบหน้าการดาวน์โหลด

-

ตอนนี้การแนะนำสิ่งที่ยอดเยี่ยมนั่นคือห้องสมุด พวกเขาสามารถทำอะไรได้มากกว่าการดาวน์โหลดและแสดงภาพรวมถึงการสร้างและจัดการแคชของหน่วยความจำ / ดิสก์การปรับขนาดภาพการเปลี่ยนแปลงและอื่น ๆ

ฉันจะเริ่มต้นด้วยVolleyห้องสมุดอันทรงพลังที่ Google สร้างขึ้นและครอบคลุมโดยเอกสารอย่างเป็นทางการ ในขณะที่เป็นไลบรารีเครือข่ายที่ใช้งานทั่วไปซึ่งไม่ได้เชี่ยวชาญด้านรูปภาพ แต่ Volley มี API ที่ทรงพลังสำหรับจัดการรูปภาพ

คุณจะต้องใช้คลาสSingletonเพื่อจัดการคำขอวอลเลย์และคุณก็พร้อมที่จะไป

คุณอาจต้องการแทนที่ของคุณImageViewด้วย Volley's NetworkImageViewดังนั้นการดาวน์โหลดโดยทั่วไปจะกลายเป็นซับเดียว:

((NetworkImageView) findViewById(R.id.myNIV)).setImageUrl(url, MySingleton.getInstance(this).getImageLoader());

หากคุณต้องการการควบคุมที่มากขึ้นนี่คือสิ่งที่ดูเหมือนว่าจะสร้างImageRequestด้วยวอลเลย์:

     ImageRequest imgRequest = new ImageRequest(url, new Response.Listener<Bitmap>() {
             @Override
             public void onResponse(Bitmap response) {
                    //do stuff
                }
            }, 0, 0, ImageView.ScaleType.CENTER_CROP, Bitmap.Config.ARGB_8888, 
             new Response.ErrorListener() {
             @Override
             public void onErrorResponse(VolleyError error) {
                   //do stuff
                }
            });

เป็นมูลค่าการกล่าวขวัญว่า Volley มีกลไกการจัดการข้อผิดพลาดที่ยอดเยี่ยมโดยการจัดเตรียมVolleyErrorคลาสที่ช่วยให้คุณระบุสาเหตุที่แท้จริงของข้อผิดพลาด หากแอปของคุณสร้างเครือข่ายจำนวนมากและการจัดการรูปภาพไม่ใช่จุดประสงค์หลักแสดงว่า Volley เหมาะสำหรับคุณ

-

Picassoของ Square เป็นห้องสมุดที่มีชื่อเสียงซึ่งจะทำหน้าที่โหลดรูปภาพทั้งหมดให้คุณ เพียงแค่แสดงภาพโดยใช้ Picasso ก็ทำได้ง่ายๆดังนี้:

 Picasso.with(myContext)
       .load(url)
       .into(myImageView); 

ตามค่าเริ่มต้น Picasso จะจัดการแคชของดิสก์ / หน่วยความจำดังนั้นคุณจึงไม่ต้องกังวลเรื่องนี้ สำหรับการควบคุมที่มากขึ้นคุณสามารถใช้Targetอินเทอร์เฟซและใช้อินเทอร์เฟซเพื่อโหลดรูปภาพของคุณ - สิ่งนี้จะให้การเรียกกลับที่คล้ายกับตัวอย่างของวอลเลย์ ตรวจสอบโครงการสาธิตเพื่อดูตัวอย่าง

Picasso ยังให้คุณใช้การแปลงกับรูปภาพที่ดาวน์โหลดมาและยังมีไลบรารีอื่นๆ ที่ขยาย API เหล่านั้นอีกด้วย นอกจากนี้ยังทำงานได้เป็นอย่างดีในRecyclerView/ /ListViewGridView

-

Universal Image Loaderเป็นอีกหนึ่งไลบรารีที่ได้รับความนิยมอย่างมากเพื่อจุดประสงค์ในการจัดการรูปภาพ มันใช้ของตัวเองImageLoaderที่ (เมื่อเริ่มต้นแล้ว) มีอินสแตนซ์ส่วนกลางซึ่งสามารถใช้เพื่อดาวน์โหลดภาพในโค้ดบรรทัดเดียว:

  ImageLoader.getInstance().displayImage(url, myImageView);

หากคุณต้องการติดตามความคืบหน้าในการดาวน์โหลดหรือเข้าถึงสิ่งที่ดาวน์โหลดมาBitmap:

 ImageLoader.getInstance().displayImage(url, myImageView, opts, 
 new ImageLoadingListener() {
     @Override
     public void onLoadingStarted(String imageUri, View view) {
                     //do stuff
                }

      @Override
      public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
                   //do stuff
                }

      @Override
      public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
                   //do stuff
                }

      @Override
      public void onLoadingCancelled(String imageUri, View view) {
                   //do stuff
                }
            }, new ImageLoadingProgressListener() {
      @Override
      public void onProgressUpdate(String imageUri, View view, int current, int total) {
                   //do stuff
                }
            });

optsโต้แย้งในตัวอย่างนี้เป็นDisplayImageOptionsวัตถุ อ้างถึงโครงการสาธิตเพื่อเรียนรู้เพิ่มเติม

เช่นเดียวกับ Volley UIL มีFailReasonคลาสที่ให้คุณตรวจสอบสิ่งที่ผิดพลาดจากความล้มเหลวในการดาวน์โหลด ตามค่าเริ่มต้น UIL จะเก็บรักษาหน่วยความจำ / ดิสก์แคชหากคุณไม่ได้บอกอย่างชัดเจนว่าไม่ทำเช่นนั้น

หมายเหตุ : ผู้เขียนได้กล่าวว่าเขาไม่ได้ดูแลโครงการอีกต่อไป ณ วันที่ 27 พฤศจิกายน 2015 แต่เนื่องจากมีผู้ร่วมให้ข้อมูลจำนวนมากเราหวังว่า Universal Image Loader จะใช้งานได้

-

ของ Facebook Frescoเป็นรุ่นใหม่ล่าสุดและ (IMO) ห้องสมุดที่ทันสมัยที่สุดที่จะจัดการภาพไปยังระดับใหม่: จากการรักษาBitmapsออกกองจาวา (ก่อนที่จะอมยิ้ม) จะให้การสนับสนุนรูปแบบภาพเคลื่อนไหวและความก้าวหน้า JPEG สตรีมมิ่ง

หากต้องการเรียนรู้เพิ่มเติมเกี่ยวกับแนวคิดและเทคนิคเบื้องหลัง Fresco โปรดดูที่โพสต์นี้

การใช้งานพื้นฐานค่อนข้างง่าย โปรดทราบว่าคุณจะต้องโทร Fresco.initialize(Context);เพียงครั้งเดียวดีกว่าในApplicationชั้นเรียน การเริ่มต้น Fresco มากกว่าหนึ่งครั้งอาจทำให้เกิดพฤติกรรมที่คาดเดาไม่ได้และข้อผิดพลาด OOM

Fresco ใช้Drawees ในการแสดงภาพคุณสามารถคิดImageViewได้ดังนี้:

    <com.facebook.drawee.view.SimpleDraweeView
    android:id="@+id/drawee"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    fresco:fadeDuration="500"
    fresco:actualImageScaleType="centerCrop"
    fresco:placeholderImage="@drawable/placeholder_grey"
    fresco:failureImage="@drawable/error_orange"
    fresco:placeholderImageScaleType="fitCenter"
    fresco:failureImageScaleType="centerInside"
    fresco:retryImageScaleType="centerCrop"
    fresco:progressBarImageScaleType="centerInside"
    fresco:progressBarAutoRotateInterval="1000"
    fresco:roundAsCircle="false" />

อย่างที่คุณเห็นมีหลายสิ่ง (รวมถึงตัวเลือกการเปลี่ยนแปลง) ได้รับการกำหนดไว้แล้วใน XML ดังนั้นสิ่งที่คุณต้องทำเพื่อแสดงภาพคือซับเดียว:

 mDrawee.setImageURI(Uri.parse(url));

Fresco มี API การปรับแต่งเพิ่มเติมซึ่งในบางสถานการณ์อาจค่อนข้างซับซ้อนและต้องการให้ผู้ใช้อ่านเอกสารอย่างรอบคอบ (ใช่บางครั้งคุณต้องใช้ RTFM)

ฉันได้รวมตัวอย่างสำหรับภาพ JPEG และภาพเคลื่อนไหวแบบโปรเกรสซีฟไว้ในโครงการตัวอย่าง


สรุป - "ฉันได้เรียนรู้เกี่ยวกับสิ่งที่ยอดเยี่ยมตอนนี้ฉันควรใช้อะไร"

โปรดทราบว่าข้อความต่อไปนี้สะท้อนถึงความคิดเห็นส่วนตัวของฉันและไม่ควรนำมาเป็นสมมติฐาน

  • หากคุณต้องการเพียงดาวน์โหลด / บันทึก / แสดงภาพบางภาพอย่าวางแผนที่จะใช้ใน a Recycler-/Grid-/ListViewและไม่จำเป็นต้องมีภาพจำนวนมากเพื่อพร้อมแสดงผลBasicImageDownloaderควรตรงกับความต้องการของคุณ
  • ถ้า app ของคุณบันทึกภาพ (หรือไฟล์อื่น ๆ ) เป็นผลมาจากผู้ใช้หรือการกระทำโดยอัตโนมัติและคุณไม่จำเป็นต้องภาพที่จะแสดงมักจะใช้ Android DownloadManager
  • ในกรณีของแอปไม่มากของเครือข่ายการถ่ายทอด / ได้รับJSONข้อมูลการทำงานร่วมกับภาพ แต่ผู้ที่ไม่ได้เป็นวัตถุประสงค์หลักของแอปไปกับวอลเล่ย์
  • แอปของคุณเน้นรูปภาพ / สื่อคุณต้องการใช้การเปลี่ยนแปลงบางอย่างกับรูปภาพและไม่ต้องการยุ่งยากกับ API ที่ซับซ้อน: ใช้Picasso (หมายเหตุ: ไม่มี API ใด ๆ เพื่อติดตามสถานะการดาวน์โหลดระดับกลาง) หรือรูปภาพสากล รถตัก
  • ถ้า app ของคุณเป็นข้อมูลเกี่ยวกับภาพที่คุณต้องการคุณสมบัติขั้นสูงเช่นการแสดงรูปแบบภาพเคลื่อนไหวและคุณพร้อมที่จะอ่านเอกสารไปกับFresco

ในกรณีที่คุณพลาดลิงก์ Githubสำหรับโครงการสาธิต


และนี่คือไฟล์ BasicImageDownloader.java

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.support.annotation.NonNull;
import android.util.Log;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.HashSet;
import java.util.Set;

public class BasicImageDownloader {

    private OnImageLoaderListener mImageLoaderListener;
    private Set<String> mUrlsInProgress = new HashSet<>();
    private final String TAG = this.getClass().getSimpleName();

    public BasicImageDownloader(@NonNull OnImageLoaderListener listener) {
        this.mImageLoaderListener = listener;
    }

    public interface OnImageLoaderListener {
        void onError(ImageError error);      
        void onProgressChange(int percent);
        void onComplete(Bitmap result);
    }


    public void download(@NonNull final String imageUrl, final boolean displayProgress) {
        if (mUrlsInProgress.contains(imageUrl)) {
            Log.w(TAG, "a download for this url is already running, " +
                    "no further download will be started");
            return;
        }

        new AsyncTask<Void, Integer, Bitmap>() {

            private ImageError error;

            @Override
            protected void onPreExecute() {
                mUrlsInProgress.add(imageUrl);
                Log.d(TAG, "starting download");
            }

            @Override
            protected void onCancelled() {
                mUrlsInProgress.remove(imageUrl);
                mImageLoaderListener.onError(error);
            }

            @Override
            protected void onProgressUpdate(Integer... values) {
                mImageLoaderListener.onProgressChange(values[0]);
            }

        @Override
        protected Bitmap doInBackground(Void... params) {
            Bitmap bitmap = null;
            HttpURLConnection connection = null;
            InputStream is = null;
            ByteArrayOutputStream out = null;
            try {
                connection = (HttpURLConnection) new URL(imageUrl).openConnection();
                if (displayProgress) {
                    connection.connect();
                    final int length = connection.getContentLength();
                    if (length <= 0) {
                        error = new ImageError("Invalid content length. The URL is probably not pointing to a file")
                                .setErrorCode(ImageError.ERROR_INVALID_FILE);
                        this.cancel(true);
                    }
                    is = new BufferedInputStream(connection.getInputStream(), 8192);
                    out = new ByteArrayOutputStream();
                    byte bytes[] = new byte[8192];
                    int count;
                    long read = 0;
                    while ((count = is.read(bytes)) != -1) {
                        read += count;
                        out.write(bytes, 0, count);
                        publishProgress((int) ((read * 100) / length));
                    }
                    bitmap = BitmapFactory.decodeByteArray(out.toByteArray(), 0, out.size());
                } else {
                    is = connection.getInputStream();
                    bitmap = BitmapFactory.decodeStream(is);
                }
            } catch (Throwable e) {
                if (!this.isCancelled()) {
                    error = new ImageError(e).setErrorCode(ImageError.ERROR_GENERAL_EXCEPTION);
                    this.cancel(true);
                }
            } finally {
                try {
                    if (connection != null)
                        connection.disconnect();
                    if (out != null) {
                        out.flush();
                        out.close();
                    }
                    if (is != null)
                        is.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            return bitmap;
        }

            @Override
            protected void onPostExecute(Bitmap result) {
                if (result == null) {
                    Log.e(TAG, "factory returned a null result");
                    mImageLoaderListener.onError(new ImageError("downloaded file could not be decoded as bitmap")
                            .setErrorCode(ImageError.ERROR_DECODE_FAILED));
                } else {
                    Log.d(TAG, "download complete, " + result.getByteCount() +
                            " bytes transferred");
                    mImageLoaderListener.onComplete(result);
                }
                mUrlsInProgress.remove(imageUrl);
                System.gc();
            }
        }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
    }

    public interface OnBitmapSaveListener {
        void onBitmapSaved();
        void onBitmapSaveError(ImageError error);
    }


    public static void writeToDisk(@NonNull final File imageFile, @NonNull final Bitmap image,
                               @NonNull final OnBitmapSaveListener listener,
                               @NonNull final Bitmap.CompressFormat format, boolean shouldOverwrite) {

    if (imageFile.isDirectory()) {
        listener.onBitmapSaveError(new ImageError("the specified path points to a directory, " +
                "should be a file").setErrorCode(ImageError.ERROR_IS_DIRECTORY));
        return;
    }

    if (imageFile.exists()) {
        if (!shouldOverwrite) {
            listener.onBitmapSaveError(new ImageError("file already exists, " +
                    "write operation cancelled").setErrorCode(ImageError.ERROR_FILE_EXISTS));
            return;
        } else if (!imageFile.delete()) {
            listener.onBitmapSaveError(new ImageError("could not delete existing file, " +
                    "most likely the write permission was denied")
                    .setErrorCode(ImageError.ERROR_PERMISSION_DENIED));
            return;
        }
    }

    File parent = imageFile.getParentFile();
    if (!parent.exists() && !parent.mkdirs()) {
        listener.onBitmapSaveError(new ImageError("could not create parent directory")
                .setErrorCode(ImageError.ERROR_PERMISSION_DENIED));
        return;
    }

    try {
        if (!imageFile.createNewFile()) {
            listener.onBitmapSaveError(new ImageError("could not create file")
                    .setErrorCode(ImageError.ERROR_PERMISSION_DENIED));
            return;
        }
    } catch (IOException e) {
        listener.onBitmapSaveError(new ImageError(e).setErrorCode(ImageError.ERROR_GENERAL_EXCEPTION));
        return;
    }

    new AsyncTask<Void, Void, Void>() {

        private ImageError error;

        @Override
        protected Void doInBackground(Void... params) {
            FileOutputStream fos = null;
            try {
                fos = new FileOutputStream(imageFile);
                image.compress(format, 100, fos);
            } catch (IOException e) {
                error = new ImageError(e).setErrorCode(ImageError.ERROR_GENERAL_EXCEPTION);
                this.cancel(true);
            } finally {
                if (fos != null) {
                    try {
                        fos.flush();
                        fos.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
            return null;
        }

        @Override
        protected void onCancelled() {
            listener.onBitmapSaveError(error);
        }

        @Override
        protected void onPostExecute(Void result) {
            listener.onBitmapSaved();
        }
    }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
  }

public static Bitmap readFromDisk(@NonNull File imageFile) {
    if (!imageFile.exists() || imageFile.isDirectory()) return null;
    return BitmapFactory.decodeFile(imageFile.getAbsolutePath());
}

public interface OnImageReadListener {
    void onImageRead(Bitmap bitmap);
    void onReadFailed();
}

public static void readFromDiskAsync(@NonNull File imageFile, @NonNull final OnImageReadListener listener) {
    new AsyncTask<String, Void, Bitmap>() {
        @Override
        protected Bitmap doInBackground(String... params) {
            return BitmapFactory.decodeFile(params[0]);
        }

        @Override
        protected void onPostExecute(Bitmap bitmap) {
            if (bitmap != null)
                listener.onImageRead(bitmap);
            else
                listener.onReadFailed();
        }
    }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, imageFile.getAbsolutePath());
}

    public static final class ImageError extends Throwable {

        private int errorCode;
        public static final int ERROR_GENERAL_EXCEPTION = -1;
        public static final int ERROR_INVALID_FILE = 0;
        public static final int ERROR_DECODE_FAILED = 1;
        public static final int ERROR_FILE_EXISTS = 2;
        public static final int ERROR_PERMISSION_DENIED = 3;
        public static final int ERROR_IS_DIRECTORY = 4;


        public ImageError(@NonNull String message) {
            super(message);
        }

        public ImageError(@NonNull Throwable error) {
            super(error.getMessage(), error.getCause());
            this.setStackTrace(error.getStackTrace());
        }

        public ImageError setErrorCode(int code) {
            this.errorCode = code;
            return this;
        }

        public int getErrorCode() {
            return errorCode;
        }
      }
   }

สิ่งที่เกี่ยวกับการเรียกกลับ onPictureTaken () ที่ให้ภาพเป็นไบต์ [] เราสามารถรับ URL ของรูปภาพนั้นได้โดยตรงจากกล้องหรือไม่? หรือเอาท์พุทสตรีมแบบเก่าพื้นฐาน () เป็นวิธีเดียวใน Android ที่จะบันทึกภาพที่ถ่ายโดยกล้องโดยไม่ใช้เจตนาในตัว? ดูเหมือนจะแปลกเพราะสิ่งที่ต้องทำหลังจาก onPictureTaken นั้นเป็นเรื่องธรรมดาที่ต้องบันทึกไว้ ไม่มีการสนับสนุนโดยเฉพาะสำหรับการทำเช่นนั้นหรือไม่?
Tombola

2
@Tombola ไฮ! โพสต์นี้เกี่ยวกับการดาวน์โหลดรูปภาพจากเว็บ แต่เพื่อตอบคำถามของคุณ (เท่าที่ฉันเข้าใจ): วิธีทั่วไปในการบันทึกภาพจากกล้องคือการหาเส้นทางจากCursor(ในonActivityResult()วิธีการ) จากนั้นสร้างBitmapโดยใช้เส้นทางนั้น และใช่คุณจะไม่หนีจากการใช้ a FileOutputStreamand a ByteArrayOutputStreamถ้าคุณต้องการบันทึกภาพนี้ลงใน SD
Droidman

@BartBurg คำถามนี้เกี่ยวกับการดาวน์โหลดและบันทึกภาพ แต่คุณพูดถูกในบางประเด็นเนื่องจากมีวิธีการเขียนจึงควรมีวิธีการอ่านเพื่อความสมบูรณ์ ฉันจะเพิ่มในการอัปเดตครั้งต่อไปในโพสต์นี้เร็ว ๆ นี้
Droidman

คุณช่วยยกตัวอย่างโดยใช้ BasicImageDownloader นี้ได้ไหม
Jaydev

1
@JaydevKalivarapu โปรดตรวจสอบแอปสาธิตบน GitHub ( คลาสซอร์สที่มีตัวอย่าง )
Droidman

35

ฉันเพิ่งมาจากการแก้ปัญหานี้และฉันต้องการแบ่งปันรหัสทั้งหมดที่สามารถดาวน์โหลดบันทึกลงใน sdcard (และซ่อนชื่อไฟล์) และดึงภาพและในที่สุดก็ตรวจสอบว่ามีภาพอยู่หรือไม่ url มาจากฐานข้อมูลดังนั้นชื่อไฟล์จึงไม่ซ้ำกันได้อย่างง่ายดายโดยใช้ id

ดาวน์โหลดภาพก่อน

   private class GetImages extends AsyncTask<Object, Object, Object> {
    private String requestUrl, imagename_;
    private ImageView view;
    private Bitmap bitmap ; 
      private FileOutputStream fos;
    private GetImages(String requestUrl, ImageView view, String _imagename_) {
        this.requestUrl = requestUrl;
        this.view = view;
        this.imagename_ = _imagename_ ;
    }

    @Override
    protected Object doInBackground(Object... objects) {
        try {
            URL url = new URL(requestUrl);
            URLConnection conn = url.openConnection();
            bitmap = BitmapFactory.decodeStream(conn.getInputStream());
        } catch (Exception ex) {
        }
        return null;
    }

    @Override
    protected void onPostExecute(Object o) { 
        if(!ImageStorage.checkifImageExists(imagename_))
        { 
                view.setImageBitmap(bitmap);
                ImageStorage.saveToSdCard(bitmap, imagename_); 
            }  
        }  
   }

จากนั้นสร้างคลาสสำหรับบันทึกและเรียกไฟล์

  public class ImageStorage {


public static String saveToSdCard(Bitmap bitmap, String filename) {

    String stored = null;

    File sdcard = Environment.getExternalStorageDirectory() ; 

    File folder = new File(sdcard.getAbsoluteFile(), ".your_specific_directory");//the dot makes this directory hidden to the user
    folder.mkdir(); 
    File file = new File(folder.getAbsoluteFile(), filename + ".jpg") ;
    if (file.exists())
        return stored ;

    try {
        FileOutputStream out = new FileOutputStream(file);
        bitmap.compress(Bitmap.CompressFormat.JPEG, 90, out);
        out.flush();
        out.close();
        stored = "success";
    } catch (Exception e) {
        e.printStackTrace();
    }
     return stored;
   }

public static File getImage(String imagename) {

        File mediaImage = null;
        try {
            String root = Environment.getExternalStorageDirectory().toString();
            File myDir = new File(root);
            if (!myDir.exists())
                return null;

            mediaImage = new File(myDir.getPath() + "/.your_specific_directory/"+imagename);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return mediaImage;
    }
public static boolean checkifImageExists(String imagename)
{
    Bitmap b = null ;
    File file = ImageStorage.getImage("/"+imagename+".jpg");
    String path = file.getAbsolutePath();

    if (path != null)
        b = BitmapFactory.decodeFile(path); 

    if(b == null ||  b.equals(""))
    {
        return false ;
    }
    return true ;
}
  }

จากนั้นในการเข้าถึงภาพก่อนอื่นให้ตรวจสอบว่ามีอยู่แล้วหากไม่มีให้ดาวน์โหลด

          if(ImageStorage.checkifImageExists(imagename))
            {
                File file = ImageStorage.getImage("/"+imagename+".jpg"); 
                String path = file.getAbsolutePath(); 
                if (path != null){
                    b = BitmapFactory.decodeFile(path);
                    imageView.setImageBitmap(b);
                }  
            } else { 
                new GetImages(imgurl, imageView, imagename).execute() ; 
            }

หมายเหตุ : แม้ว่าโดยทั่วไปตัวอย่างนี้จะใช้งานได้ แต่ก็ไม่ได้ให้การจัดการข้อผิดพลาดใด ๆ และยังขาดความเข้าใจพื้นฐานบางประการเกี่ยวกับAsyncTaskข้อดีของ (การใช้พาราเมตริเซชั่นอย่างเหมาะสมการดำเนินการแบบขนาน ... ) โปรดดูตัวอย่างของฉันด้านล่างสำหรับรายละเอียด ปล . สำหรับผู้ที่อาจคิดว่าฉันเขียนสิ่งนี้เพื่อโปรโมตโค้ดของตัวเองด้วยเหตุผลใดก็ตาม: ไม่ฉันแค่ชี้ประเด็นที่ฉันเห็นในตัวอย่างที่กำหนด
Droidman

ใช่ Droidman ฉันเห็นด้วยกับคุณ รหัสชิ้นนี้ควรถูกนำมาใช้เป็นตัวดัดแปลงและต้องดำเนินการให้เสร็จสิ้นด้วยตัวเองรวมถึงการจัดการข้อผิดพลาด อย่างไรก็ตามรหัสของคุณขาดการจัดการข้อผิดพลาดเช่นกัน จะเกิดอะไรขึ้นกับการเชื่อมต่อและสตรีมของคุณในกรณีของ IOException
Androider

@Androider โปรดดูdownloadวิธีการของฉันโดยเฉพาะอย่างยิ่งdoInBackgroundวิธีการของงานที่ฉันใช้ IOExceptionจะที่ดินในcatch (Throwable e)บล็อกส่งผลให้ImageErrorถูกส่งกลับและonError()โทรกลับถูกเรียก ImageErrorวัตถุจะมีกองติดตามเดิมและสาเหตุของเกิดขึ้นException
Droidman

1
ใช่ แต่การเชื่อมต่อของคุณจะไม่ถูกตัดการเชื่อมต่อและสตรีมของคุณจะไม่ถูกปิด
Androider

@Androider อาฉันเห็นจุดของคุณ แม้ว่าฉันจะไม่เคยสังเกตเห็นการรั่วไหลที่น่าสงสัยในอุปกรณ์ทดสอบของฉัน แต่พฤติกรรมนี้อาจแตกต่างไปจากอุปกรณ์อื่น ๆ ขอบคุณสำหรับคำใบ้ - ฉันได้อัปเดตรหัสแล้ว
Droidman

33

ทำไมคุณต้องใช้รหัสของคุณเองเพื่อดาวน์โหลด แค่ส่ง URI ไปยัง Download manager ล่ะ

public void downloadFile(String uRl) {
    File direct = new File(Environment.getExternalStorageDirectory()
            + "/AnhsirkDasarp");

    if (!direct.exists()) {
        direct.mkdirs();
    }

    DownloadManager mgr = (DownloadManager) getActivity().getSystemService(Context.DOWNLOAD_SERVICE);

    Uri downloadUri = Uri.parse(uRl);
    DownloadManager.Request request = new DownloadManager.Request(
            downloadUri);

    request.setAllowedNetworkTypes(
            DownloadManager.Request.NETWORK_WIFI
                    | DownloadManager.Request.NETWORK_MOBILE)
            .setAllowedOverRoaming(false).setTitle("Demo")
            .setDescription("Something useful. No, really.")
            .setDestinationInExternalPublicDir("/AnhsirkDasarp", "fileName.jpg");

    mgr.enqueue(request);

}

1
ตัวอย่างที่สมบูรณ์แบบสำหรับ api> 8
Jeeten Parmar

รหัสของคุณทำงานได้สมบูรณ์แบบสำหรับภาพเดียว! ฉันจะทำอย่างไรหากต้องการดาวน์โหลดเพิ่มเติม (100 รูป) จากไฟล์ภาพในเซิร์ฟเวอร์ของฉัน ???
Kostantinos Ibra

ฉันได้รับข้อความแจ้งว่าไฟล์เสียหาย!
Anup

2
อาจจะ. setDestinationInExternalPublicDir ("/ AnhsirkDasarp", "fileName.jpg");
ผู้เชี่ยวชาญอยากเป็น

2
เราจะรู้ได้อย่างไรว่าดาวน์โหลดสำเร็จหรือล้มเหลว
Prabs

12

มันอาจช่วยคุณได้ ..

Button download_image = (Button)bigimagedialog.findViewById(R.id.btn_downloadimage);
                    download_image.setOnClickListener(new View.OnClickListener()
                    {
                        public void onClick(View v)
                        {
                            boolean success = (new File("/sdcard/dirname")).mkdir(); 
                            if (!success)
                            {
                                Log.w("directory not created", "directory not created");
                            }

                            try
                            {
                                URL url = new URL("YOUR_URL");
                                HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                                connection.setDoInput(true);
                                connection.connect();
                                InputStream input = connection.getInputStream();
                                Bitmap myBitmap = BitmapFactory.decodeStream(input);

                                String data1 = String.valueOf(String.format("/sdcard/dirname/%d.jpg",System.currentTimeMillis()));

                                FileOutputStream stream = new FileOutputStream(data1);

                                ByteArrayOutputStream outstream = new ByteArrayOutputStream();
                                myBitmap.compress(Bitmap.CompressFormat.JPEG, 85, outstream);
                                byte[] byteArray = outstream.toByteArray();

                                stream.write(byteArray);
                                stream.close();

                                Toast.makeText(getApplicationContext(), "Downloading Completed", Toast.LENGTH_SHORT).show();
                            }
                            catch (Exception e)
                            {
                                e.printStackTrace();
                            }
                        }
                    });

6

ฉันมีวิธีง่ายๆที่ทำงานได้อย่างสมบูรณ์ รหัสไม่ใช่ของฉันฉันพบมันในลิงค์นี้ ขั้นตอนดังต่อไปนี้:

1.ก่อนดาวน์โหลดภาพเรามาเขียนวิธีการบันทึกบิตแมปลงในไฟล์ภาพในที่เก็บข้อมูลภายในของ Android จำเป็นต้องมีบริบทดีกว่าที่จะใช้ pass ในบริบทของแอปพลิเคชันโดย getApplicationContext () วิธีนี้สามารถทิ้งลงในคลาสกิจกรรมของคุณหรือคลาสยูทิลอื่น ๆ

public void saveImage(Context context, Bitmap b, String imageName) 
{
    FileOutputStream foStream;
    try 
    {
        foStream = context.openFileOutput(imageName, Context.MODE_PRIVATE);
        b.compress(Bitmap.CompressFormat.PNG, 100, foStream);
        foStream.close();
    } 
    catch (Exception e) 
    {
        Log.d("saveImage", "Exception 2, Something went wrong!");
        e.printStackTrace();
    }
}

2.ตอนนี้เรามีวิธีบันทึกบิตแมปลงในไฟล์รูปภาพใน andorid มาเขียน AsyncTask เพื่อดาวน์โหลดรูปภาพตาม url คลาสส่วนตัวนี้จะต้องจัดให้อยู่ในคลาสกิจกรรมของคุณเป็นคลาสย่อย หลังจากดาวน์โหลดรูปภาพแล้วในเมธอด onPostExecute จะเรียกใช้เมธอด saveImage ที่กำหนดไว้ด้านบนเพื่อบันทึกรูปภาพ หมายเหตุชื่อรูปภาพจะถูกเข้ารหัสเป็น“ my_image.png”

private class DownloadImage extends AsyncTask<String, Void, Bitmap> {
    private String TAG = "DownloadImage";
    private Bitmap downloadImageBitmap(String sUrl) {
        Bitmap bitmap = null;
        try {
            InputStream inputStream = new URL(sUrl).openStream();   // Download Image from URL
            bitmap = BitmapFactory.decodeStream(inputStream);       // Decode Bitmap
            inputStream.close();
        } catch (Exception e) {
            Log.d(TAG, "Exception 1, Something went wrong!");
            e.printStackTrace();
        }
        return bitmap;
    }

    @Override
    protected Bitmap doInBackground(String... params) {
        return downloadImageBitmap(params[0]);
    }

    protected void onPostExecute(Bitmap result) {
        saveImage(getApplicationContext(), result, "my_image.png");
    }
}

3. AsyncTask สำหรับดาวน์โหลดภาพถูกกำหนดไว้ แต่เราจำเป็นต้องดำเนินการเพื่อเรียกใช้ AsyncTask นั้น ในการทำเช่นนั้นให้เขียนบรรทัดนี้ในเมธอด onCreate ในคลาสกิจกรรมของคุณหรือในวิธีการ onClick ของปุ่มหรือที่อื่น ๆ ที่คุณเห็นว่าเหมาะสม

new DownloadImage().execute("http://developer.android.com/images/activity_lifecycle.png");

ควรบันทึกรูปภาพใน /data/data/your.app.packagename/files/my_image.jpeg ตรวจสอบโพสต์นี้เพื่อเข้าถึงไดเรกทอรีนี้จากอุปกรณ์ของคุณ

IMO ช่วยแก้ปัญหาได้! หากคุณต้องการขั้นตอนเพิ่มเติมเช่นโหลดรูปภาพคุณสามารถทำตามขั้นตอนเพิ่มเติมเหล่านี้:

4.หลังจากดาวน์โหลดรูปภาพแล้วเราต้องการวิธีโหลดบิตแมปภาพจากที่จัดเก็บข้อมูลภายในเพื่อให้เราสามารถใช้งานได้ มาเขียนวิธีการโหลดบิตแมปภาพ วิธีนี้ใช้พารามิเตอร์สองตัวบริบทและชื่อไฟล์รูปภาพโดยไม่มีพา ธ แบบเต็ม context.openFileInput (imageName) จะค้นหาไฟล์ที่ไดเร็กทอรีบันทึกเมื่อชื่อไฟล์นี้ถูกบันทึกในเมธอด saveImage ด้านบน

public Bitmap loadImageBitmap(Context context, String imageName) {
    Bitmap bitmap = null;
    FileInputStream fiStream;
    try {
        fiStream    = context.openFileInput(imageName);
        bitmap      = BitmapFactory.decodeStream(fiStream);
        fiStream.close();
    } catch (Exception e) {
        Log.d("saveImage", "Exception 3, Something went wrong!");
        e.printStackTrace();
    }
    return bitmap;
}

5.ตอนนี้เรามีทุกสิ่งที่จำเป็นสำหรับการตั้งค่ารูปภาพของ ImageView หรือมุมมองอื่น ๆ ที่คุณต้องการใช้รูปภาพ เมื่อเราบันทึกรูปภาพเราฮาร์ดโค้ดชื่อรูปภาพเป็น“ my_image.jpeg” ตอนนี้เราสามารถส่งชื่อรูปภาพนี้ไปยังเมธอด loadImageBitmap ด้านบนเพื่อรับบิตแมปและตั้งค่าเป็น ImageView

someImageView.setImageBitmap(loadImageBitmap(getApplicationContext(), "my_image.jpeg"));

6. เพื่อให้ได้ภาพเต็มเส้นทางตามชื่อภาพ

File file            = getApplicationContext().getFileStreamPath("my_image.jpeg");
String imageFullPath = file.getAbsolutePath();

7.ตรวจสอบว่ามีไฟล์ภาพอยู่หรือไม่

ไฟล์ไฟล์ =

getApplicationContext().getFileStreamPath("my_image.jpeg");
if (file.exists()) Log.d("file", "my_image.jpeg exists!");
  1. เพื่อลบไฟล์ภาพ

    ไฟล์ไฟล์ = getApplicationContext (). getFileStreamPath ("my_image.jpeg"); ถ้า (file.delete ()) Log.d ("file", "my_image.jpeg ถูกลบ!");


0

รหัสนี้ทำงานได้อย่างสมบูรณ์แบบในโครงการของฉัน

downloadImagesToSdCard(imagepath,imagepath);

private void downloadImagesToSdCard(String downloadUrl,String imageName)
        {
            try
            {
                URL url = new URL("www.xxx.com"+downloadUrl); 
                /* making a directory in sdcard */
            //  String sdCard=Environment.getExternalStorageDirectory().toString();
                ContextWrapper cw = new ContextWrapper(getActivity());
                 // path to /data/data/yourapp/app_data/imageDir
                File directory = cw.getDir("files", Context.MODE_PRIVATE);

                File myDir = new File(directory,"folder");

                /*  if specified not exist create new */
                if(!myDir.exists())
                {
                    myDir.mkdir();
                    Log.v("", "inside mkdir");
                }

                /* checks the file and if it already exist delete */
                String fname = imageName;
                File file = new File (myDir, fname);
                Log.d("file===========path", ""+file);
                if (file.exists ()) 
                    file.delete (); 

                /* Open a connection */
                URLConnection ucon = url.openConnection();
                InputStream inputStream = null;
                HttpURLConnection httpConn = (HttpURLConnection)ucon;
                httpConn.setRequestMethod("GET");
                httpConn.connect();
                inputStream = httpConn.getInputStream();
                /*if (httpConn.getResponseCode() == HttpURLConnection.HTTP_OK) 
                {
                    inputStream = httpConn.getInputStream();
                }*/

                FileOutputStream fos = new FileOutputStream(file);  
                int totalSize = httpConn.getContentLength();
                int downloadedSize = 0;   
                byte[] buffer = new byte[1024];
                int bufferLength = 0;
                while ( (bufferLength = inputStream.read(buffer)) >0 ) 
                {                 
                    fos.write(buffer, 0, bufferLength);                  
                    downloadedSize += bufferLength;                 
                    Log.i("Progress:","downloadedSize:"+downloadedSize+"totalSize:"+ totalSize) ;
                }   

                fos.close();
                Log.d("test", "Image Saved in sdcard..");  
                viewimage();
            }
            catch(IOException io)
            {                  
                io.printStackTrace();
            }
            catch(Exception e)
            {                     
                e.printStackTrace();
            }


        } 

        public void viewimage()
        {
              String path = serialnumber+".png";
               ContextWrapper cw = new ContextWrapper(getActivity());

                //path to /data/data/yourapp/app_data/dirName
                File directory = cw.getDir("files", Context.MODE_PRIVATE);

                File mypath=new File(directory,"folder/"+path);

                Bitmap b;
                try {
                    b = BitmapFactory.decodeStream(new FileInputStream(mypath));
                //  b.compress(format, quality, stream)
                    profile_image.setImageBitmap(Bitmap.createScaledBitmap(b, 120, 120, false));
                } catch (FileNotFoundException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
        }

1
สวัสดีขอบคุณสำหรับการมีส่วนร่วม โปรดทราบว่าวิธีการข้างต้นในการบันทึกภาพในพื้นที่เก็บข้อมูลส่วนตัวของแอปมีข้อเสีย 2 ประการคือ 1) รูปภาพจะใช้ได้เฉพาะในแอปของคุณและ 2) คุณควรหลีกเลี่ยงการบันทึกภาพลงในพื้นที่เก็บข้อมูลส่วนตัวของแอปเนื่องจากไม่ได้มีไว้สำหรับเนื้อหาขนาดใหญ่
Droidman

0

ลองทำตามนี้

 try
                {
                    Bitmap bmp = null;
                    URL url = new URL("Your_URL");
                    URLConnection conn = url.openConnection();
                    bmp = BitmapFactory.decodeStream(conn.getInputStream());
                    File f = new File(Environment.getExternalStorageDirectory(),System.currentTimeMillis() + ".jpg");
                    if(f.exists())
                        f.delete();
                    f.createNewFile();
                    Bitmap bitmap = bmp;
                    ByteArrayOutputStream bos = new ByteArrayOutputStream();
                    bitmap.compress(Bitmap.CompressFormat.PNG, 0 /*ignored for PNG*/, bos);
                    byte[] bitmapdata = bos.toByteArray();
                    FileOutputStream fos = new FileOutputStream(f);
                    fos.write(bitmapdata);
                    fos.flush();
                    fos.close();
                    Log.e(TAG, "imagepath: "+f );
                }
                catch (Exception e)
                {
                    e.printStackTrace();
                }

0
public class testCrop extends AppCompatActivity {
    ImageView iv;
    String imagePath = "https://style.pk/wp-content/uploads/2015/07/omer-Shahzad-performed-umrah-600x548.jpg";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.testcrpop);
        iv = (ImageView) findViewById(R.id.testCrop);
        imageDownload image = new imageDownload(testCrop.this, iv);
        image.execute(imagePath);
    }
    class imageDownload extends AsyncTask<String, Integer, Bitmap> {
        Context context;
        ImageView imageView;
        Bitmap bitmap;
        InputStream in = null;
        int responseCode = -1;
//constructor.
        public imageDownload(Context context, ImageView imageView) {
            this.context = context;
            this.imageView = imageView;
        }
        @Override
        protected void onPreExecute() {
        }
        @Override
        protected Bitmap doInBackground(String... params) {
            try {
                URL url = new URL(params[0]);
                HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
                httpURLConnection.setDoOutput(true);
                httpURLConnection.connect();
                responseCode = httpURLConnection.getResponseCode();
                if (responseCode == HttpURLConnection.HTTP_OK) {
                    in = httpURLConnection.getInputStream();
                    bitmap = BitmapFactory.decodeStream(in);
                    in.close();
                }
            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return bitmap;
        }
        @Override
        protected void onPostExecute(Bitmap data) {
            imageView.setImageBitmap(data);
            saveImage(data);
        }

        private void saveImage(Bitmap data) {
            File createFolder = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),"test");
            createFolder.mkdir();
            File saveImage = new File(createFolder,"downloadimage.jpg");
            try {
                OutputStream outputStream = new FileOutputStream(saveImage);
                data.compress(Bitmap.CompressFormat.JPEG,100,outputStream);
                outputStream.flush();
                outputStream.close();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

เอาท์พุทใส่คำอธิบายภาพที่นี่

ตรวจสอบว่าคุณได้เพิ่มสิทธิ์ในการเขียนข้อมูลในหน่วยความจำ

 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

0

โพสต์ @Droidman ค่อนข้างครอบคลุม วอลเลย์ใช้งานได้ดีกับข้อมูลขนาดเล็กเพียงไม่กี่กิโลไบต์ เมื่อฉันพยายามใช้ 'BasicImageDownloader.java' Android Studio ได้เตือนฉันว่าคลาส AsyncTask ควรเป็นแบบคงที่หรืออาจมีการรั่วไหล ฉันใช้ Volley ในแอปทดสอบอื่นและยังคงขัดข้องเนื่องจากมีการรั่วไหลดังนั้นฉันจึงกังวลเกี่ยวกับการใช้ Volley สำหรับโปรแกรมดาวน์โหลดรูปภาพ (รูปภาพอาจมีขนาดไม่กี่ 100 kB)

ฉันใช้ Picasso และใช้งานได้ดีมีการเปลี่ยนแปลงเล็กน้อย (อาจเป็นการอัปเดตของ Picasso) จากสิ่งที่โพสต์ไว้ด้านบน รหัสด้านล่างใช้ได้กับฉัน:

    public static void imageDownload(Context ctx, String url){
    Picasso.get().load(yourURL)
            .into(getTarget(url));
}
private static Target getTarget(final String url){

    Target target2 = new Target() {
        @Override
        public void onBitmapLoaded(final Bitmap bitmap, Picasso.LoadedFrom from) {
            new Thread(new Runnable() {

                @Override
                public void run() {

                    File file = new File(localPath + "/"+"YourImageFile.jpg");
                    try {
                        file.createNewFile();
                        FileOutputStream ostream = new FileOutputStream(file);
                        bitmap.compress(Bitmap.CompressFormat.JPEG, 80, ostream);
                        ostream.flush();
                        ostream.close();
                    } catch (IOException e) {
                        Log.e("IOException", e.getLocalizedMessage());
                    }
                }
            }).start();
        }

        @Override
        public void onBitmapFailed(Exception e, Drawable errorDrawable) {
        }

        @Override
        public void onPrepareLoad(Drawable placeHolderDrawable) {
        }
    };
    return target;
}

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.