1

xamarin.androidアプリでは、リモートサーバーからファイルをダウンロードしており、クライアントリストの行項目が進行状況に更新されます。ファイルをPCLからXamarin.Androidに更新する

これはアンドロイドとiosに共通のダウンロードを行うためのpclを作成したものです。私たちは以下のようにリモートサーバーからファイルをダウンロードするためには、HttpWebRequestを求めている新しいワーカースレッドからxamarin.androidアプリから

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使用してライト・ファイルの内容メソッドを呼び出しています非同期。

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

HttpWebResponseの入力ストリームを読み取って内部記憶装置に存在する出力ストリームファイルにデータを書き込むために使用される以下のコードスニペット。私たちは以下のようにUIスレッドで実行内のUIを更新しているコールバックがxamarin.androidに受信されると

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(); 
          } 
         } 
        } 

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の "Report download progress"参照リンクを読むと、待機/非同期の内部呼び出しがバックグラウンドタスクを実行するためにスレッドプールを使用することが示されます。

スレッドなしで試してみると、ダウンロードアイコンを押すとUIがハングアップします。スレッド内で呼び出すとUIが応答し、すぐにクラッシュします。

PCL非同期/ Xamarin android UI通信を待つことが適切ではありません。

この問題を解決するために私を助けてください。

答えて

0

私のアプリでは(概念的に言えば)似たようなことをしています。 UIスレッドでダウンロードリスナーに通知する方法は、(ビューレス)DownloadManager- フラグメントRetainInstancetrueに設定することです。 これは、構成の変更(向きの変更など)でフラグメントが破損するのを防ぎます。

ここに私のコードの短い抜粋です:そのTagを使用して取得する(または作成)、

 /// <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. 
      } 
     } 

だからあなたの活動からこのフラグメントを、その後、あなたのダウンロードは、ダウンロードのリスナー(S)で始まります。 あなたの活動から、NotifyDataSetChangedと同様の方法で電話をかけることができます。

あなたの問題を解決するプロセスで役立つことを願っています。

関連する問題