Bagaimana Anda mengunduh dan menyimpan gambar dari url tertentu di Android?
Jawaban:
pembaruan besar terakhir: 31 Maret 2016
TL; DR alias berhenti bicara, berikan saja kodenya !!
Lewati ke bagian bawah posting ini, salin
BasicImageDownloader
(versi javadoc di sini ) ke dalam proyek Anda, terapkanOnImageLoaderListener
antarmuka dan selesai.Catatan : meskipun
BasicImageDownloader
menangani kemungkinan kesalahan dan akan mencegah aplikasi Anda mogok jika terjadi kesalahan, ia tidak akan melakukan pasca-pemrosesan apa pun (misalnya, perampingan) pada unduhanBitmaps
.
Karena posting ini telah menerima cukup banyak perhatian, saya telah memutuskan untuk mengerjakannya ulang sepenuhnya untuk mencegah orang-orang menggunakan teknologi yang sudah usang, praktik pemrograman yang buruk atau hanya melakukan hal-hal konyol - seperti mencari "peretasan" untuk menjalankan jaringan di utas utama atau terima semua sertifikat SSL.
Saya telah membuat proyek demo bernama "Image Downloader" yang mendemonstrasikan cara mengunduh (dan menyimpan) gambar menggunakan implementasi pengunduh saya sendiri, bawaan Android DownloadManager
serta beberapa pustaka sumber terbuka populer. Anda dapat melihat kode sumber lengkap atau mengunduh proyek di GitHub .
Catatan : Saya belum menyesuaikan manajemen izin untuk SDK 23+ (Marshmallow), oleh karena itu proyek ini menargetkan SDK 22 (Lollipop).
Dalam kesimpulan saya di akhir posting ini, saya akan membagikan pendapat saya tentang kasus penggunaan yang tepat untuk setiap cara pengunduhan gambar tertentu yang telah saya sebutkan.
Mari kita mulai dengan implementasi sendiri (Anda dapat menemukan kode di akhir posting). Pertama-tama, ini adalah Basic ImageDownloader dan hanya itu. Yang dilakukannya hanyalah menghubungkan ke url yang diberikan, membaca data dan mencoba mendekodekannya sebagai Bitmap
, memicu OnImageLoaderListener
callback antarmuka bila perlu. Keuntungan dari pendekatan ini - sederhana dan Anda memiliki gambaran yang jelas tentang apa yang terjadi. Cara yang baik untuk pergi jika yang Anda butuhkan hanyalah mengunduh / menampilkan dan menyimpan beberapa gambar, sementara Anda tidak peduli tentang mempertahankan cache memori / disk.
Catatan: jika gambarnya besar, Anda mungkin perlu memperkecilnya .
-
Android DownloadManager adalah cara agar sistem menangani unduhan untuk Anda. Ini sebenarnya mampu mengunduh semua jenis file, bukan hanya gambar. Anda dapat membiarkan unduhan Anda terjadi secara diam-diam dan tidak terlihat oleh pengguna, atau Anda dapat mengizinkan pengguna untuk melihat unduhan di area pemberitahuan. Anda juga dapat mendaftar BroadcastReceiver
untuk mendapatkan pemberitahuan setelah pengunduhan selesai. Penyiapannya cukup mudah, lihat proyek terkait untuk kode contoh.
Menggunakan file DownloadManager
umumnya bukan ide yang baik jika Anda juga ingin menampilkan gambar, karena Anda perlu membaca dan mendekode file yang disimpan alih-alih hanya mengatur unduhan Bitmap
ke file ImageView
. The DownloadManager
juga tidak menyediakan API bagi Anda app untuk melacak kemajuan-download.
-
Sekarang pengenalan hal-hal hebat - perpustakaan. Mereka dapat melakukan lebih dari sekadar mengunduh dan menampilkan gambar, termasuk: membuat dan mengelola cache memori / disk, mengubah ukuran gambar, mengubahnya, dan banyak lagi.
Saya akan mulai dengan Volley , perpustakaan hebat yang dibuat oleh Google dan tercakup dalam dokumentasi resmi. Meskipun menjadi pustaka jaringan tujuan umum yang tidak mengkhususkan diri pada gambar, Volley memiliki API yang cukup kuat untuk mengelola gambar.
Anda perlu menerapkan kelas Singleton untuk mengelola permintaan Volley dan Anda siap melakukannya.
Anda mungkin ingin mengganti ImageView
dengan Volley's NetworkImageView
, sehingga unduhan pada dasarnya menjadi satu baris:
((NetworkImageView) findViewById(R.id.myNIV)).setImageUrl(url, MySingleton.getInstance(this).getImageLoader());
Jika Anda membutuhkan lebih banyak kontrol, seperti inilah cara membuat ImageRequest
dengan Volley:
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
}
});
Perlu disebutkan bahwa Volley memiliki mekanisme penanganan kesalahan yang sangat baik dengan menyediakan VolleyError
kelas yang membantu Anda menentukan penyebab pasti dari kesalahan. Jika aplikasi Anda melakukan banyak jaringan dan mengelola gambar bukanlah tujuan utamanya, maka Volley sangat cocok untuk Anda.
-
Square's Picasso adalah perpustakaan terkenal yang akan melakukan semua pemuatan gambar untuk Anda. Hanya menampilkan gambar menggunakan Picasso sesederhana:
Picasso.with(myContext)
.load(url)
.into(myImageView);
Secara default, Picasso mengelola cache disk / memori sehingga Anda tidak perlu mengkhawatirkannya. Untuk kontrol lebih lanjut, Anda dapat mengimplementasikan Target
antarmuka dan menggunakannya untuk memuat gambar Anda - ini akan memberikan callback yang mirip dengan contoh Volley. Lihat proyek demo sebagai contoh.
Picasso juga memungkinkan Anda menerapkan transformasi ke gambar yang diunduh dan bahkan ada perpustakaan lain di sekitarnya yang memperluas API tersebut. Juga bekerja sangat baik di a RecyclerView
/ ListView
/ GridView
.
-
Universal Image Loader adalah pustaka lain yang sangat populer yang melayani tujuan manajemen gambar. Ia menggunakan miliknya sendiri ImageLoader
yang (setelah diinisialisasi) memiliki contoh global yang dapat digunakan untuk mengunduh gambar dalam satu baris kode:
ImageLoader.getInstance().displayImage(url, myImageView);
Jika Anda ingin melacak kemajuan unduhan atau mengakses unduhan 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
}
});
The opts
argumen dalam contoh ini adalah DisplayImageOptions
objek. Lihat proyek demo untuk mempelajari lebih lanjut.
Mirip dengan Volley, UIL menyediakan FailReason
kelas yang memungkinkan Anda memeriksa apa yang salah pada kegagalan pengunduhan. Secara default, UIL memelihara cache memori / disk jika Anda tidak secara eksplisit menyuruhnya untuk tidak melakukannya.
Catatan : penulis telah menyebutkan bahwa dia tidak lagi memelihara proyek tersebut mulai 27 November 2015. Tetapi karena ada banyak kontributor, kami berharap Universal Image Loader akan terus berjalan.
-
Fresco Facebook adalah perpustakaan terbaru dan (IMO) yang paling canggih yang membawa manajemen gambar ke tingkat yang baru: dari menjauhkan Bitmaps
tumpukan java (sebelum Lollipop) hingga mendukung format animasi dan streaming JPEG progresif .
Untuk mempelajari lebih lanjut tentang ide dan teknik di balik Fresco, lihat posting ini .
Penggunaan dasarnya cukup sederhana. Perhatikan bahwa Anda hanya perlu menelepon Fresco.initialize(Context);
sekali, lebih disukai di Application
kelas. Menginisialisasi Fresco lebih dari sekali dapat menyebabkan perilaku tak terduga dan kesalahan OOM.
Fresco menggunakan Drawee
s untuk menampilkan gambar, Anda dapat menganggapnya sebagai berikut 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" />
Seperti yang Anda lihat, banyak hal (termasuk opsi transformasi) sudah ditentukan dalam XML, jadi yang perlu Anda lakukan untuk menampilkan gambar adalah satu baris:
mDrawee.setImageURI(Uri.parse(url));
Fresco menyediakan API penyesuaian tambahan, yang, dalam keadaan, bisa sangat kompleks dan mengharuskan pengguna untuk membaca dokumen dengan hati-hati (ya, terkadang Anda perlu RTFM).
Saya telah memasukkan contoh untuk JPEG progresif dan gambar animasi ke dalam proyek sampel.
Perhatikan bahwa teks berikut mencerminkan pendapat pribadi saya dan tidak boleh dianggap sebagai dalil.
Recycler-/Grid-/ListView
dan tidak memerlukan banyak gambar untuk siap ditampilkan, BasicImageDownloader harus sesuai dengan kebutuhan Anda.JSON
data, bekerja dengan gambar, tetapi itu bukan tujuan utama aplikasi, gunakan Volley .Jika Anda melewatkannya, tautan Github untuk proyek demo.
Dan inilah 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;
}
}
}
Cursor
(dalam onActivityResult()
metode), kemudian membuat Bitmap
menggunakan jalur itu. Dan ya, Anda tidak akan lepas dari penggunaan a FileOutputStream
dan a ByteArrayOutputStream
jika Anda ingin menyimpan gambar ini ke SD.
Saya baru saja menyelesaikan masalah ini dan saya ingin membagikan kode lengkap yang dapat mengunduh, menyimpan ke sdcard (dan menyembunyikan nama file) dan mengambil gambar dan akhirnya memeriksa apakah gambar tersebut sudah ada. Url berasal dari database sehingga nama file bisa dengan mudah menggunakan id.
gambar unduhan pertama
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_);
}
}
}
Kemudian buat kelas untuk menyimpan dan mengambil file
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 ;
}
}
Kemudian Untuk mengakses gambar pertama periksa apakah sudah ada jika belum kemudian unduh
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
keuntungannya (penggunaan yang tepat dari parametrization, eksekusi paralel ..). Silakan lihat contoh saya di bawah ini untuk detailnya. PS . bagi mereka yang mungkin berpikir saya menulis ini untuk mempromosikan kode saya sendiri karena alasan apa pun: tidak, saya hanya menunjukkan masalah yang dapat saya lihat dalam contoh yang diberikan.
download
metode saya , terutama doInBackground
metode tugas yang saya gunakan. Sebuah IOException
akan mendarat di catch (Throwable e)
blok tersebut, menghasilkan ImageError
yang dikembalikan dan onError()
panggilan balik dipicu. The ImageError
objek akan berisi jejak stack asli dan penyebab terjadiException
Mengapa Anda benar-benar membutuhkan kode Anda sendiri untuk mendownloadnya? Bagaimana kalau meneruskan URI Anda ke Pengelola unduhan?
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);
}
itu mungkin membantu Anda ..
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();
}
}
});
Saya memiliki solusi sederhana yang bekerja dengan sempurna. Kode ini bukan milik saya, saya menemukannya di tautan ini . Berikut langkah-langkah yang harus diikuti:
1. Sebelum mendownload image, mari kita tulis metode untuk menyimpan bitmap menjadi file image di penyimpanan internal di android. Ini membutuhkan konteks, lebih baik menggunakan pass dalam konteks aplikasi dengan getApplicationContext (). Metode ini bisa dibuang ke kelas Activity Anda atau kelas util lainnya.
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. Sekarang kita memiliki metode untuk menyimpan bitmap menjadi file gambar di andorid, mari kita tulis AsyncTask untuk mengunduh gambar dengan url. Kelas privat ini perlu ditempatkan di kelas Aktivitas Anda sebagai subkelas. Setelah gambar diunduh, dalam metode onPostExecute, ini memanggil metode saveImage yang ditentukan di atas untuk menyimpan gambar. Perhatikan, nama gambar di-hardcode sebagai “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 untuk mengunduh gambar telah ditentukan, tetapi kita perlu menjalankannya untuk menjalankan AsyncTask tersebut. Untuk melakukannya, tulis baris ini dalam metode onCreate di kelas Activity Anda, atau dalam metode onClick dari sebuah tombol atau tempat lain yang Anda inginkan.
new DownloadImage().execute("http://developer.android.com/images/activity_lifecycle.png");
Gambar harus disimpan di /data/data/your.app.packagename/files/my_image.jpeg, periksa posting ini untuk mengakses direktori ini dari perangkat Anda.
IMO ini menyelesaikan masalah! Jika Anda menginginkan langkah lebih lanjut seperti memuat gambar, Anda dapat mengikuti langkah-langkah tambahan ini:
4. Setelah gambar diunduh, kita membutuhkan cara untuk memuat bitmap gambar dari penyimpanan internal, sehingga kita dapat menggunakannya. Mari tulis metode untuk memuat bitmap gambar. Metode ini mengambil dua parameter, konteks dan nama file gambar, tanpa path lengkap, context.openFileInput (imageName) akan mencari file di direktori save ketika nama file ini disimpan dalam metode saveImage di atas.
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. Sekarang kami memiliki semua yang kami butuhkan untuk menyetel gambar ImageView atau Tampilan lain yang Anda suka untuk menggunakan gambar tersebut. Saat kami menyimpan gambar, kami melakukan hardcode nama gambar sebagai "my_image.jpeg", sekarang kami dapat meneruskan nama gambar ini ke metode loadImageBitmap di atas untuk mendapatkan bitmap dan menyetelnya ke ImageView.
someImageView.setImageBitmap(loadImageBitmap(getApplicationContext(), "my_image.jpeg"));
6. Untuk mendapatkan gambar path lengkap dengan nama gambar.
File file = getApplicationContext().getFileStreamPath("my_image.jpeg");
String imageFullPath = file.getAbsolutePath();
7. Periksa apakah file gambar ada.
File file =
getApplicationContext().getFileStreamPath("my_image.jpeg");
if (file.exists()) Log.d("file", "my_image.jpeg exists!");
Untuk menghapus file gambar.
File file = getApplicationContext (). GetFileStreamPath ("my_image.jpeg"); if (file.delete ()) Log.d ("file", "my_image.jpeg dihapus!");
kode ini berjalan dengan sempurna dalam proyek saya
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();
}
}
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();
}
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();
}
}
}
}
Pastikan Anda menambahkan izin untuk menulis data di memori
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
Posting @Droid cukup komprehensif. Volley berfungsi baik dengan data kecil beberapa kbytes. Ketika saya mencoba menggunakan 'BasicImageDownloader.java', Android Studio memberi saya peringatan bahwa kelas AsyncTask harus statis atau mungkin ada kebocoran. Saya menggunakan Volley di aplikasi pengujian lain dan terus mogok karena kebocoran, jadi saya khawatir menggunakan Volley untuk pengunduh gambar (gambar dapat berukuran 100 kB).
Saya menggunakan Picasso dan berfungsi dengan baik, ada sedikit perubahan (mungkin pembaruan di Picasso) dari apa yang diposting di atas. Kode di bawah ini berhasil untuk saya:
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;
}
Seperti yang dikatakan Google, untuk saat ini, jangan lupa tambahkan juga yang dapat dibaca di penyimpanan eksternal di manifes:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
Sumber: http://developer.android.com/training/basics/data-storage/files.html#GetWritePermission