Android'de bir resim nasıl indirilir ve kaydedilir


Yanıtlar:


224

30.12.2015 itibarıyla düzenleyin - Görüntü indirme için Nihai Kılavuz


son büyük güncelleme: 31 Mart 2016


TL; DR aka konuşmayı bırak, sadece bana kodu ver !!

Bu BasicImageDownloaderyazının altına atlayın, (javadoc sürümünü buradan ) projenize kopyalayın , OnImageLoaderListenerarayüzü uygulayın ve bitirdiniz.

Not : BasicImageDownloaderOlası hataları ele almasına ve herhangi bir terslik olması durumunda uygulamanızın kilitlenmesini önlese de, indirilen üzerinde herhangi bir son işlem (örneğin küçültme) gerçekleştirmeyecektir Bitmaps.


Bu gönderi oldukça fazla ilgi gördüğü için, insanların kullanımdan kaldırılmış teknolojileri, kötü programlama uygulamalarını kullanmasını veya sadece aptalca şeyler yapmasını engellemek için tamamen yeniden çalışmaya karar verdim - ana iş parçacığı üzerinde ağı çalıştırmak için "hackler" aramak veya tüm SSL sertifikalarını kabul edin.

Kendi indirme uygulamamı, Android'in yerleşik uygulamasını DownloadManagerve bazı popüler açık kaynak kitaplıklarını kullanarak bir görüntünün nasıl indirileceğini (ve kaydedileceğini) gösteren "Resim İndirici" adlı bir demo proje oluşturdum . Tam kaynak kodunu görüntüleyebilir veya projeyi GitHub'dan indirebilirsiniz .

Not : SDK 23+ (Marshmallow) için izin yönetimini henüz ayarlamadım, bu nedenle proje SDK 22'yi (Lollipop) hedefliyor.

Bu yazının sonundaki sonucumda , bahsettiğim her belirli görüntü indirme yolu için uygun kullanım durumu hakkındaki mütevazı görüşümü paylaşacağım .

Kendi uygulamayla başlayalım (kodu yazının sonunda bulabilirsiniz). Her şeyden önce, bu bir Basic ImageDownloader ve hepsi bu. Tek yaptığı, verilen url'ye bağlanmak, verileri okumak ve onu bir olarak çözmeye çalışmak Bitmap, OnImageLoaderListeneruygun olduğunda arayüz geri aramalarını tetiklemektir . Bu yaklaşımın avantajı - basittir ve neler olduğuna dair net bir genel bakışa sahipsiniz. İhtiyacınız olan tek şey, bir bellek / disk önbelleğini korumayı umursamadan, bazı görüntüleri indirmek / görüntülemek ve kaydetmekse, gitmenin iyi bir yolu.

Not: Büyük resimler olması durumunda, onları küçültmeniz gerekebilir .

-

Android DownloadManager , sistemin indirmeyi sizin için yapmasına izin vermenin bir yoludur. Aslında sadece görüntüleri değil, her türlü dosyayı indirebilir. İndirmenizin kullanıcı tarafından sessiz ve görünmez olmasına izin verebilir veya kullanıcının bildirim alanında indirmeyi görmesini sağlayabilirsiniz. BroadcastReceiverİndirme işlemi tamamlandıktan sonra bildirim almak için bir de kayıt olabilirsiniz . Kurulum oldukça basittir, örnek kod için bağlantılı projeye bakın.

Kullanımı DownloadManagerda görüntüyü görüntülemek istiyorsanız okumak ve sadece indirilen ayarlamak yerine kaydedilen dosyayı deşifre gerekiyordu çünkü genellikle iyi bir fikir değildir Bitmapbir içine ImageView. DownloadManagerEğer indirme işlemini takip app için ayrıca herhangi bir API sağlamaz.

-

Şimdi harika şeylerin tanıtımı - kütüphaneler. Görüntüleri indirmekten ve görüntülemekten çok daha fazlasını yapabilirler: bellek / disk önbelleğini oluşturma ve yönetme, görüntüleri yeniden boyutlandırma, dönüştürme ve daha fazlası.

Google tarafından oluşturulan ve resmi belgelerle kapsanan güçlü bir kitaplık olan Volley ile başlayacağım . Volley, görüntüler üzerinde uzmanlaşmayan genel amaçlı bir ağ kitaplığı olmasına rağmen, görüntüleri yönetmek için oldukça güçlü bir API'ye sahiptir.

Volley isteklerini yönetmek için bir Singleton sınıfı uygulamanız gerekecek ve gitmekte fayda var .

ImageViewKendi'nizi Volley's ile değiştirmek isteyebilirsiniz NetworkImageView, böylece indirme temelde tek satırlık bir hale gelir:

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

Daha fazla kontrole ihtiyacınız varsa ImageRequest, Volley ile bir oluşturmak nasıl görünür :

     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'in, bir hatanın VolleyErrorkesin nedenini belirlemenize yardımcı olan sınıfı sağlayarak mükemmel bir hata işleme mekanizmasına sahip olduğunu belirtmekte fayda var . Uygulamanız çok fazla ağ oluşturuyorsa ve ana amacı görüntüleri yönetmek değilse Volley sizin için mükemmel bir seçimdir.

-

Square's Picasso , sizin için tüm resim yükleme işlerini yapacak tanınmış bir kütüphanedir. Picasso kullanarak bir görseli görüntülemek şu kadar basit:

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

Varsayılan olarak, Picasso disk / bellek önbelleğini yönetir, böylece endişelenmenize gerek kalmaz. Daha fazla kontrol için Targetarayüzü uygulayabilir ve görüntünüzü içine yüklemek için kullanabilirsiniz - bu, Volley örneğine benzer geri aramalar sağlayacaktır. Örnekler için demo projesine bakın.

Picasso ayrıca indirilen görüntüye dönüşümler uygulamanıza izin verir ve çevresinde bu API'yi genişleten başka kitaplıklar da vardır . Ayrıca RecyclerView/ ListView/ 'da çok iyi çalışıyor GridView.

-

Universal Image Loader , görüntü yönetimi amacına hizmet eden çok popüler bir kitaplıktır. ImageLoaderGörüntüleri tek bir kod satırında indirmek için kullanılabilen (başlatıldığında) küresel bir örneğe sahip olan kendi kullanır :

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

İndirme ilerlemesini izlemek veya indirilen dosyaya erişmek istiyorsanız 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
                }
            });

optsBu örnekte bağımsız değişkeni olan DisplayImageOptionsnesne. Daha fazla bilgi edinmek için demo projesine bakın.

Volley'e benzer şekilde, UIL FailReasonindirme başarısızlığında neyin yanlış gittiğini kontrol etmenizi sağlayan sınıfı sağlar. Varsayılan olarak, eğer açıkça yapmamasını söylemediğiniz takdirde UIL bir bellek / disk önbelleği tutar.

Not : yazar 27 Kasım 2015 itibariyle artık projeyi sürdürmediğini belirtti. Ancak birçok katılımcı olduğu için Universal Image Loader'ın devam edeceğini umabiliriz.

-

Facebook'un Fresco'su , görüntü yönetimini yeni bir düzeye taşıyan en yeni ve (IMO) en gelişmiş kitaplıktır: Bitmapsjava yığınından (Lollipop'tan önce), animasyonlu formatları desteklemeye ve aşamalı JPEG akışına kadar .

Fresco'nun arkasındaki fikir ve teknikler hakkında daha fazla bilgi edinmek için bu gönderiye bakın .

Temel kullanım oldukça basittir. Sınıfta Fresco.initialize(Context);tercihen yalnızca bir kez aramanız gerekeceğini unutmayın Application. Fresco'nun birden fazla kez başlatılması, öngörülemeyen davranışlara ve OOM hatalarına neden olabilir.

Fresco, Draweegörüntüleri görüntülemek için s kullanır , bunları şu şekilde düşünebilirsiniz 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" />

Gördüğünüz gibi, birçok şey (dönüştürme seçenekleri dahil) XML'de zaten tanımlanmıştır, bu nedenle bir görüntüyü görüntülemek için tek yapmanız gereken tek satırlık bir programdır:

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

Fresco, koşullar altında oldukça karmaşık olabilen ve kullanıcının belgeleri dikkatlice okumasını gerektiren genişletilmiş bir özelleştirme API'si sağlar (evet, bazen RTFM'ye ihtiyaç duyarsınız ).

Örnek projeye aşamalı JPEG'ler ve hareketli görüntüler için örnekler ekledim.


Sonuç - "Harika şeyler öğrendim, şimdi ne kullanmalıyım?"

Aşağıdaki metnin kişisel görüşümü yansıttığını ve bir varsayım olarak alınmaması gerektiğini unutmayın.

  • Yalnızca bazı görüntüleri indirmeniz / kaydetmeniz / görüntülemeniz gerekiyorsa, bunları bir arada kullanmayı planlamayın Recycler-/Grid-/ListViewve görüntülemeye hazır olması için bir sürü görüntüye ihtiyacınız yoksa, BasicImageDownloader ihtiyaçlarınızı karşılamalıdır.
  • Uygulamanız, bir kullanıcının veya otomatik bir işlemin sonucu olarak görüntüleri (veya diğer dosyaları) kaydediyorsa ve görüntülerin sık görüntülenmesine ihtiyacınız yoksa, Android DownloadManager'ı kullanın .
  • Uygulamanız çok fazla ağ bağlantısı kurarsa, JSONveri iletir / alır , resimlerle çalışır, ancak bunlar uygulamanın ana amacı değilse Volley ile gidin .
  • Uygulamanız görüntü / medya odaklıdır, görüntülere bazı dönüşümler uygulamak ve karmaşık API ile uğraşmak istemezsiniz: Picasso (Not: ara indirme durumunu izlemek için herhangi bir API sağlamaz) veya Universal Image kullanın Yükleyici
  • Uygulamanız tamamen resimlerle ilgiliyse, animasyonlu formatları görüntüleme gibi gelişmiş özelliklere ihtiyacınız var ve belgeleri okumaya hazırsınız, Fresco ile gidin .

Bunu kaçırdıysanız , demo projesi için Github bağlantısı .


Ve işte 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;
        }
      }
   }

Resmi bayt [] olarak veren onPictureTaken () geri aramasına ne dersiniz, bu resmin URL'sini doğrudan kameradan alabilirsiniz? Ya da temel eski outputStream () yerleşik amaç kullanılmadan bir kamera tarafından çekilen bir resmi kaydetmenin Android'deki tek yolu mu? Bu garip görünüyor, çünkü onPictureTaken'den sonra yapılacak doğal şey elbette onu kurtarmaktır. Bunu yapmak için özel bir destek yok mu?
Tombola

2
@Tombola Merhaba! Bu gönderi, web'den bir resim indirmek hakkındadır. Ancak sorunuzu yanıtlamak için (anladığım kadarıyla): Bir kamera resmini kaydetmenin yaygın yolu, yolunu Cursor( onActivityResult()yöntemde) ' den almak ve sonra Bitmapbu yolu kullanarak bir yol oluşturmaktır . Ve evet, bu görüntüyü SD'ye kaydetmek istiyorsanız a FileOutputStreamve a kullanmaktan kurtulamayacaksınız ByteArrayOutputStream.
Droidman

@BartBurg bu soru bir görüntüyü indirmek ve kaydetmekle ilgilidir. Ama bir noktada haklısın, bir yazma yöntemi olduğu için, bütünlük adına bir okuma yöntemi de olmalı. Yakında bu gönderiye bir sonraki güncellemede ekleyeceğim.
Droidman

Lütfen bu BasicImageDownloader'ı kullanarak bir örnek verebilir misiniz?
Jaydev

1
@JaydevKalivarapu lütfen GitHub'daki demo uygulamasını kontrol edin ( örnek içeren kaynak sınıf )
Droidman

35

Bu sorunu çözmekten yeni geldim ve indirebilen, sdcard'a kaydedebilen (ve dosya adını gizleyen) ve görüntüleri alabilen ve sonunda görüntünün zaten orada olup olmadığını kontrol edebilen kodun tamamını paylaşmak istiyorum. URL, veritabanından gelir, böylece dosya adı, kimlik kullanılarak benzersiz bir şekilde kolayca yapılabilir.

ilk indirilen resimler

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

Ardından dosyaları kaydetmek ve almak için bir sınıf oluşturun

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

Ardından, görüntülere erişmek için, önce orada olup olmadığını kontrol edin, ardından indirin

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

Not : Bu örnek genel olarak işe yarayabilirken, herhangi bir hata işleme sağlamaz ve aynı zamanda bazı temel AsyncTaskavantajları (parametreleştirmenin doğru kullanımı, paralel yürütme ..) sahip değildir. Ayrıntılar için lütfen aşağıdaki örneklerime bakın. PS . Bunu herhangi bir nedenle kendi kodumu tanıtmak için yazdığımı düşünenler için: hayır, sadece verilen örnekte görebildiğim konulara işaret ediyorum.
Droidman

Evet Droidman, sana katılıyorum. Bu kod parçası bir tamplate olarak alınmalı ve hata işleme dahil olmak üzere kişinin kendi başına tamamlaması gerekir. Bu arada, kodunuz da hata işlemeden yoksundur. IOException durumunda bağlantınıza ve akışlarınıza ne olacak?
Androider

@Androider lütfen benim downloadyöntemime, özellikle de doInBackgroundkullandığım görevin yöntemine daha yakından bakın . Bir IOExceptionde toprak olacaktır catch (Throwable e)bir sonuçlanan bloğun ImageErroriade edilen ve onError()geri arama tetiklenen. ImageErrorNesne, orijinal yığın izleme ve meydana nedenini içerecektirException
Droidman

1
Evet, ancak bağlantınız
kesilmeyecek

@Androider ah, amacını anlıyorum. Test cihazlarımda herhangi bir şüpheli sızıntı fark etmemiş olsam da, bu davranış diğer cihazlarda farklı olabilir. İpucu için teşekkürler - Kodu güncelledim
Droidman

33

İndirmek için neden gerçekten kendi kodunuza ihtiyacınız var? URI'nizi İndirme yöneticisine aktarmaya ne dersiniz?

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 için mükemmel örnek.
Jeeten Parmar

Kodunuz tek bir görüntü için mükemmel çalışıyor! Sunucumdaki resimler dosyamdan daha fazla (100 resim) indirmek istersem ne yapabilirim ???
Kostantinos Ibra

Dosyanın hasar gördüğünü belirten bir mesaj aldım!
Anup

2
Belki, .setDestinationInExternalPublicDir ("/ AnhsirkDasarp", "dosyaAdı.jpg");
Uzman

2
Başarıyla indirilip indirilmediğini nasıl
anlarız

12

sana yardımcı olabilir ..

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

Mükemmel çalışan basit bir çözümüm var. Kod benim değil, bu linkte buldum . İşte izlenecek adımlar:

1. Görüntüyü indirmeden önce, bitmap'i android dahili depolama alanındaki bir görüntü dosyasına kaydetmek için bir yöntem yazalım. Geçişin getApplicationContext () tarafından uygulama bağlamında kullanılması daha iyi bir bağlam gerektirir. Bu yöntem Aktivite sınıfınıza veya diğer kullanım sınıflarına aktarılabilir.

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. Şimdi bitmap'i andorid'deki bir görüntü dosyasına kaydetmek için bir yöntemimiz var, görüntüleri url ile indirmek için AsyncTask yazalım. Bu özel sınıfın Aktivite sınıfınıza bir alt sınıf olarak yerleştirilmesi gerekir. Görüntü indirildikten sonra, onPostExecute yönteminde, görüntüyü kaydetmek için yukarıda tanımlanan saveImage yöntemini çağırır. Görüntü adının “my_image.png” olarak sabit kodlandığını unutmayın.

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. Görüntüyü indirmek için AsyncTask tanımlanmıştır, ancak bu AsyncTask'ı çalıştırmak için onu yürütmemiz gerekir. Bunu yapmak için, bu satırı Activity sınıfınızdaki onCreate yönteminize veya bir düğmenin onClick yöntemine veya uygun gördüğünüz diğer yerlere yazın.

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

Görüntü /data/data/your.app.packagename/files/my_image.jpeg içine kaydedilmelidir, bu dizine cihazınızdan erişmek için bu gönderiyi kontrol edin.

IMO bu sorunu çözer! Görüntüyü yüklemek gibi başka adımlar istiyorsanız, şu ekstra adımları uygulayabilirsiniz:

4. Görüntü indirildikten sonra, görüntü bit eşlemini dahili depolamadan yüklemek için bir yola ihtiyacımız var, böylece onu kullanabiliriz. Görüntü bitmapini yükleme yöntemini yazalım. Bu yöntem iki parametre alır, bir bağlam ve bir görüntü dosyası adı, tam yol olmadan, context.openFileInput (imageName), bu dosya adı yukarıdaki saveImage yönteminde kaydedildiğinde dosyayı kaydetme dizininde arayacaktır.

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. Artık bir ImageView görüntüsünü veya görseli kullanmak istediğiniz diğer Görünümleri ayarlamak için ihtiyacımız olan her şeye sahibiz. Görüntüyü kaydettiğimizde, görüntü adını “my_image.jpeg” olarak kodladık, şimdi bu görüntü adını yukarıdaki loadImageBitmap yöntemine geçerek bitmap'i alıp bir ImageView olarak ayarlayabiliriz.

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

6. Görüntünün tam yolunu görüntü adına göre almak için.

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

7. Görüntü dosyasının var olup olmadığını kontrol edin.

Dosya dosyası =

getApplicationContext().getFileStreamPath("my_image.jpeg");
if (file.exists()) Log.d("file", "my_image.jpeg exists!");
  1. Görüntü dosyasını silmek için.

    Dosya dosyası = getApplicationContext (). GetFileStreamPath ("my_image.jpeg"); if (file.delete ()) Log.d ("dosya", "resmim.jpeg silindi!");


0

bu kod projemde mükemmel çalışıyor

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
merhaba, katkılarınız için teşekkürler. Yukarıdaki görüntüyü uygulamanın özel depolama alanına kaydetme yaklaşımının 2 dezavantajı olduğunu unutmayın: 1) görüntü yalnızca uygulamanızda kullanılabilir olacaktır ve 2) büyük içerik için tasarlanmadığı için görüntüleri uygulamanın özel belleğine kaydetmekten kaçınmalısınız.
Droidman

0

Bunu dene

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

ÇIKTIgörüntü açıklamasını buraya girin

Belleğe veri yazma izni eklediğinizden emin olun

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

0

@Droidman gönderisi oldukça kapsamlı. Volley, birkaç kbaytlık küçük verilerle iyi çalışıyor. 'BasicImageDownloader.java'yı kullanmaya çalıştığımda Android Studio, AsyncTask sınıfının statik olması gerektiği veya sızıntıların olabileceği konusunda bana uyarı verdi. Volley'i başka bir test uygulamasında kullandım ve bu sızıntılardan dolayı çökmeye devam etti, bu yüzden resim indirici için Volley kullanmaktan endişeleniyorum (görüntüler birkaç 100 kB olabilir).

Picasso kullandım ve iyi çalıştı, yukarıda yayınlananlardan küçük bir değişiklik (muhtemelen Picasso'da bir güncelleme) var. Aşağıdaki kod benim için çalıştı:

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

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.