在我们的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);
以下代码片段,用于从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异步/等待Xamarin android ui通信是不正确的。
帮助我摆脱这个问题。
答案 0 :(得分:0)
我在我的应用程序中做了类似的事情(从概念上讲)。
我在UI线程上通知下载监听器的方法是将({视图])DownloadManager- 片段与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
和类似的方法。
我希望这在解决问题的过程中很有用。