This tutorial explains how to download image asynchronously in Xamarin.Android. In this example, we will downloading image using System.Net.WebClient
and while downloading, the application will show a loading progress indicator.
System.Net.WebClient class provides ability to send and download data from remote location. Check out class reference from Official MSDN API documentation.
Let us create a layout as shown in the image above
Main.axml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:minWidth="25px" android:minHeight="25px" android:layout_width="fill_parent" android:layout_height="fill_parent" android:gravity="center_horizontal" android:orientation="vertical"> <Button android:text="Download Image" android:id="@+id/downloadButton" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <LinearLayout android:minWidth="25px" android:minHeight="25px" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:id="@+id/progressLayout" android:gravity="center"> <ProgressBar android:layout_width="wrap_content" android:layout_height="match_parent" android:id="@+id/progressBar1" /> <TextView android:text="Loading.." android:layout_width="wrap_content" android:layout_height="match_parent" android:id="@+id/textView1" android:gravity="center" /> </LinearLayout> <ImageView android:src="@android:drawable/ic_menu_gallery" android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/imageView1" /> </LinearLayout>
ImageViewExample.cs
using System; using Android.App; using Android.Content; using Android.Runtime; using Android.Views; using Android.Widget; using Android.OS; using Android.Graphics; using System.Threading.Tasks; using System.IO; using System.Net; namespace ImageViewExample { [Activity (Label = "ImageViewExample", MainLauncher = true, Icon = "@drawable/icon")] public class MainActivity : Activity { Button downloadButton; ImageView imageView; LinearLayout progressLayout; //Instance of webclient for async processing WebClient webClient; protected override void OnCreate (Bundle bundle){ base.OnCreate (bundle); // Set our view from the "main" layout resource SetContentView (Resource.Layout.Main); this.imageView = FindViewById<ImageView> (Resource.Id.imageView1); //Hide progressbar initially this.progressLayout = FindViewById<LinearLayout> (Resource.Id.progressLayout); this.progressLayout.Visibility = ViewStates.Gone; // Get views from the layout resource axml file this.downloadButton = FindViewById<Button> (Resource.Id.downloadButton); downloadButton.Click += downloadAsync; } async void downloadAsync(object sender, System.EventArgs ea){ //Logic to download image and display on ImageView } void cancelDownload(object sender, System.EventArgs ea){ // Logic to cancel downlaod } } }
Downloading Image
In our activity, we have a button labelled “Download Image” is added with downloadAsync
delegate. The downloadAsync method will contain the logic of download using WebClient, display progress bar, resize and store image locally. When user hits download button, the download starts and the button turns into “Cancel Download”. Below is the code snippet for downloadAsync method.
async void downloadAsync(object sender, System.EventArgs ea){ webClient = new WebClient (); var url = new Uri ("http://doubletreebyhiltonsanjose.com/wp-content/uploads/2014/08/Dog-Pictures-1024x698.jpg"); byte[] imageBytes = null; //Show loading progress this.progressLayout.Visibility = ViewStates.Visible; //Toggle button click listener to cancel the task this.downloadButton.Text = "Cancel Download"; this.downloadButton.Click -= downloadAsync; this.downloadButton.Click += cancelDownload; try{ imageBytes = await webClient.DownloadDataTaskAsync(url); } catch(TaskCanceledException){ this.progressLayout.Visibility = ViewStates.Gone; return; } catch(Exception e){ this.progressLayout.Visibility = ViewStates.Gone; this.downloadButton.Click -= cancelDownload; this.downloadButton.Click += downloadAsync; this.downloadButton.Text = "Download Image"; return; } //Saving bitmap locally string documentsPath = System.Environment.GetFolderPath (System.Environment.SpecialFolder.Personal); string localFilename = "image.png"; string localPath = System.IO.Path.Combine (documentsPath, localFilename); //Save the Image using writeAsync FileStream fs = new FileStream (localPath, FileMode.OpenOrCreate); await fs.WriteAsync (imageBytes, 0, imageBytes.Length); Console.WriteLine("Saving image in local path: "+localPath); //Close file connection fs.Close (); BitmapFactory.Options options = new BitmapFactory.Options (); options.InJustDecodeBounds = true; await BitmapFactory.DecodeFileAsync (localPath, options); //Resizing bitmap image options.InSampleSize = options.OutWidth > options.OutHeight ? options.OutHeight / imageView.Height : options.OutWidth / imageView.Width; options.InJustDecodeBounds = false; Bitmap bitmap = await BitmapFactory.DecodeFileAsync (localPath, options); imageView.SetImageBitmap (bitmap); //Hide progress bar layout this.progressLayout.Visibility = ViewStates.Gone; //Toggle button click listener this.downloadButton.Click -= cancelDownload; this.downloadButton.Click += downloadAsync; this.downloadButton.Text = "Download Image"; }
Cancel Image Download
The cancelDownload
delegate is added to button, when the user clicks on download button. This method contains the logic to cancel the download process.
void cancelDownload(object sender, System.EventArgs ea){ if(webClient!=null) webClient.CancelAsync (); //Hide progressbar layout this.progressLayout.Visibility = ViewStates.Gone; //Toggle button click listener this.downloadButton.Click -= cancelDownload; this.downloadButton.Click += downloadAsync; this.downloadButton.Text = "Download Image"; }