
Asynchronous Image Loading in Xamarin Android
This tutorial explains how to download image asynchronously in Xamarin.Android. In this example, we will downloading image using…
December 11, 2014 · 9 min read
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";
}