public override void ViewDidLoad() { base.ViewDidLoad(); // Add a bar button item to exit the app manually. Don't do this in productive apps - Apple won't approve it! // We have it here to demonstrate that iOS will relaunch the app if a download has finished. this.NavigationItem.LeftBarButtonItem = new UIBarButtonItem("Quit", UIBarButtonItemStyle.Plain, delegate { // Store all download info to disk. If iOS terminates the app, this would be handled in WillTerminate(). // However this won't be triggered if the app is killed manually by this call. AppDelegate.SerializeAvailableDownloads(); // Exit application with code 3. MusicListController.Exit(3); }); // Magic line: allows starting music playback when app is backgrounded or even terminated! UIApplication.SharedApplication.BeginReceivingRemoteControlEvents(); // We must set up an AVAudioSession and tell iOS we want to playback audio. Only then can music playback be used in the background. var audioSession = AVAudioSession.SharedInstance(); audioSession.SetCategory(AVAudioSessionCategory.Playback); audioSession.SetActive(true); // Add a bar button item to reset all downloads. var refreshBtn = new UIBarButtonItem(UIBarButtonSystemItem.Refresh); refreshBtn.Clicked += async(sender, e) => { // Stop audio. this.PlayAudio(null); var pendingTasks = await this.Session.GetTasks2Async(); if (pendingTasks != null && pendingTasks.DownloadTasks != null) { foreach (var task in pendingTasks.DownloadTasks) { task.Cancel(); } } AppDelegate.AvailableDownloads.ForEach(info => info.Reset(true)); AppDelegate.ResetAvailableDownloads(); ((DelegateTableViewSource <DownloadInfo>)(this.TableView.Source)).Items = AppDelegate.AvailableDownloads; this.TableView.ReloadData(); AppDelegate.SerializeAvailableDownloads(); }; // Add a button to stops playback. this.stopBtn = new UIBarButtonItem(UIBarButtonSystemItem.Stop) { Enabled = false }; this.stopBtn.Clicked += (sender, e) => this.StopAudio(); this.NavigationItem.RightBarButtonItems = new UIBarButtonItem[] { refreshBtn, this.stopBtn }; // Initialize our session config. We use a background session to enabled out of process uploads/downloads. Note that there are other configurations available: // - DefaultSessionConfiguration: behaves like NSUrlConnection. Used if *background* transfer is not required. // - EphemeralSessionConfiguration: use if you want to achieve something like private browsing where all sesion info (e.g. cookies) is kept in memory only. using (var sessionConfig = UIDevice.CurrentDevice.CheckSystemVersion(8, 0) ? NSUrlSessionConfiguration.CreateBackgroundSessionConfiguration(SessionId) : NSUrlSessionConfiguration.BackgroundSessionConfiguration(SessionId)) { // Allow downloads over cellular network too. sessionConfig.AllowsCellularAccess = true; // We want our app to be launched if required. //sessionConfig.SessionSendsLaunchEvents = true; // Give the OS a hint about what we are downloading. This helps iOS to prioritize. For example "Background" is used to download data that was not requested by the user and // should be ready if the app gets activated. sessionConfig.NetworkServiceType = NSUrlRequestNetworkServiceType.Default; // Configure how many downloads we allow at the same time. Set to 2 to see that further downloads start once the first two have been completed. sessionConfig.HttpMaximumConnectionsPerHost = 2; // Create a session delegate and the session itself // Initialize the session itself with the configuration and a session delegate. var sessionDelegate = new SessionDelegate(this); this.Session = NSUrlSession.FromConfiguration(sessionConfig, (INSUrlSessionDelegate)sessionDelegate, null); } this.TableView.Source = new DelegateTableViewSource <DownloadInfo>(this.TableView, "MUSIC_CELL") { Items = AppDelegate.AvailableDownloads, GetCellFunc = (item, cell) => { var musicCell = (MusicCell)cell; musicCell.InitFromDownloadInfo(item); return(musicCell); }, RowSelectedFunc = (downloadInfo, cell, indexPath) => { // If a row gets tapped, download or play. if (downloadInfo.Status != DownloadInfo.STATUS.Completed & downloadInfo.Status != DownloadInfo.STATUS.Downloading) { // Queue download. this.EnqueueDownloadAsync(downloadInfo); // Update UI once more. Download initialization might have failed . ((MusicCell)cell).InitFromDownloadInfo(downloadInfo); this.TableView.ReloadRows(new NSIndexPath[] { indexPath }, UITableViewRowAnimation.None); } else if (downloadInfo.Status == DownloadInfo.STATUS.Completed) { // Play MP3. this.currentSongIndex = indexPath.Row; this.PlayAudio(downloadInfo); } } }; this.TableView.EstimatedRowHeight = 100; this.TableView.RowHeight = UITableView.AutomaticDimension; }