将文件下载进度从 PCL 更新到 Xamarin.Android

Posted

技术标签:

【中文标题】将文件下载进度从 PCL 更新到 Xamarin.Android【英文标题】:Update File download progress from PCL to Xamarin.Android 【发布时间】:2017-10-28 21:39:50 【问题描述】:

在我们的 xamarin.android 应用程序中,我们正在从远程服务器下载一个文件,并且客户端列表行项目已更新为进度状态。

为此,我们创建了一个 pcl 来进行 android 和 ios 通用的下载。

从新工作线程的 xamarin.android 应用程序中,我们调用了 httpwebrequest 从远程服务器下载文件,如下所示,

ThreadStart downloadThreadStart = new ThreadStart(() =>
   
                Stream destinationFileStream = FileUtils.GetFileStream(fileName, info, context);
                // Call the static method downloadFile present in PCL library class WebRequestHandler
                WebRequestHandler.downloadFile(listener, fileName, key, destinationFileStream);
);
new Thread(downloadThreadStart).Start();

从 PCL 下载后,我们使用 await/async 调用写入文件内容方法。

await WriteFileContentAsync(response.GetResponseStream(), destFileStream, 
    Convert.ToInt64(size), listener, geoidFileName);

下面的代码 sn-p 用于从 httpwebresponse 读取输入流并将数据写入内部存储中存在的输出流文件。

    private static async Task WriteFileContentAsync(Stream sourceStream, 
        Stream destFileStream, long size, ResponseListener listener, string filename)
                    
                        byte[] buffer = new byte[BUFFER_SIZE];
                        //Interface callback sent to the xamarin.android application
                        listener.UpdateDownloadProgress(filename, 0);
                        try
                        
                            int currentIndex = 0;
                            int bytesRead = await sourceStream.ReadAsync(buffer,
 0, buffer.Length);

                            while (bytesRead > 0)
                            
                                await destFileStream.WriteAsync(buffer, 0, bytesRead);
                                currentIndex += bytesRead;
                                int percentage = (int)(((double)currentIndex / size) * 100);
                                Debug.WriteLine("Progress value is : " + percentage);
                                listener.UpdateDownloadProgress(filename, percentage);
                                bytesRead = await sourceStream.ReadAsync(buffer, 
0, buffer.Length);
                            
                            listener.UpdateDownloadProgress(filename, 100);
                            //Send the callback
                            listener.updateDownloadStatus(ResponseStatus.Success, filename);
                        
                        catch (Exception ex)
                        
                            Debug.WriteLine("Geoid file write exception : " + ex);
                            listener.updateDownloadStatus(ResponseStatus.Error, filename);
                        
                        finally
                        
                            if (sourceStream != null)
                            
                                sourceStream.Flush();
                                sourceStream.Dispose();
                            
                            if (destFileStream != null)
                            
                                destFileStream.Flush();
                                destFileStream.Dispose();
                            
                        
                    

一旦在 xamarin.android 中收到回调,我们将更新 UI 内部运行在 UI 线程上,如下所示,

   public void UpdateDownloadProgress(string filename, int progressValue)
   
            //Skip the progress update if the current and previous progress value is same
            if (previousProgressValue == progressValue)
            
                return;
            

            int position = findAndUpdateProgressInList(filename);
            this.itemList[position].ProgressValue = progressValue;        
            RunOnUiThread(() =>
            
                this.coordinateAdapter.NotifyDataSetChanged();
            );
   

但应用突然关闭并崩溃。下载状态会在应用程序突然关闭并崩溃后立即更新。滚动也不流畅。

我们正在从线程调用下载 API。在阅读 Xamarin“报告下载进度”参考链接时说,内部调用 await/async 使用线程池来执行后台任务。

如果我尝试不使用线程,一旦我按下下载图标,UI 就会挂起。如果我在线程内调用 UI 响应并立即崩溃。

PCL async/await 到 Xamarin android ui 通信不正确。

帮助我摆脱这个问题。

【问题讨论】:

【参考方案1】:

我正在我的应用程序中做类似的事情(从概念上讲)。 我在 UI 线程上通知下载侦听器的方式是通过将(无视图)DownloadManager-FragmentRetainInstance 设置为 true。 这将防止您的片段在配置更改(例如方向更改)时被破坏。

这是我的代码的简短摘录:

        /// <summary> A non-UI, retaining-instance fragment to internally handle downloading files. </summary>
        public class DownloadFragment : Fragment
        
            /// <summary> The tag to identify this fragment. </summary>
            internal new const string Tag = nameof(DownloadFragment);

            public override void OnCreate(Bundle savedInstanceState)
            
                base.OnCreate(savedInstanceState);
                RetainInstance = true;
            

            /// <summary> Starts the given download. </summary>
            public async void RunDownload(Context context, Download download, IDownloadListener listener,
                IDownloadNotificationHandler handler = null)
            
                // start your async download here, and hook listeners. 
                // Note that listener calls will happen on the UI thread.
            
        

因此,从您的活动中,使用其Tag 获取(或创建)此片段,然后使用您的下载侦听器开始下载。 然后,从您的活动中,您可以调用NotifyDataSetChanged 和类似方法。

我希望这对解决您的问题有用。

【讨论】:

以上是关于将文件下载进度从 PCL 更新到 Xamarin.Android的主要内容,如果未能解决你的问题,请参考以下文章

如何从xamarin表单应用程序中的PCL项目访问android原生布局文件?

如何将json.net添加到Xamarin Forms,本地项目或PCL上?

在 Xamarin Forms 中下载带有进度条的文件

如何使用 PCL 支持从 xamarin 跨平台项目中的 URL 下载文件

如何在 xamarin ios pcl 中使用 protobuf-net

xamarin形式的进度条色调颜色