将文件下载进度从 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-Fragment 与 RetainInstance
设置为 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上?
如何使用 PCL 支持从 xamarin 跨平台项目中的 URL 下载文件