2017-09-07 4 views
1

しかし、Xamarin.Androidを使用すると、それが私の問題の背後にある理由とは思われません。AsyncTaskのOnProgressUpdateが呼び出されないのはなぜですか?

私が直面している問題は、OnProgressUpdateメソッドが、バックグラウンドタスクを処理しているAsyncTaskオブジェクトで一度だけ呼び出されるということです。

public class DBInflater : AsyncTask 
{ 
    private int progress; 
    private ProgressBar progressBar; 

    public DatabaseInflater(ProgressBar progressBar) 
    { 
     this.progressBar = progressBar; 
    } 

    protected override void OnPreExecute() 
    { 
     base.OnPreExecute(); 
    } 

    protected override Java.Lang.Object DoInBackground(params Java.Lang.Object[] @params) 
    { 
     System.Threading.Tasks.Task.Run([some heavy task]); 

     while (progress < 100) 
     { 
      Java.Lang.Thread.Sleep(500); 
      PublishProgress(progress); 
      progress += 1; 
     } 

     return true; 
    } 

    protected override void OnProgressUpdate(params Java.Lang.Object[] values) 
    { 
     progressBar.Progress = progress; 
    } 

    protected override void OnPostExecute(Java.Lang.Object result) 
    { 
     base.OnPostExecute(result); 
    } 
} 

私はこのラインに問題を絞り込むことができた:ここに私のクラスであるJava.Lang.Thread.Sleep(500); スリープに小さい値を使用すると、初めてOnProgressUpdateが呼び出されることはありません。この値でOnProgressUpdateが正しく呼び出され、progressBarが画面上で更新されるため、私は500に上陸しました。

ある一定の間隔でスレッドをスリープ状態にしなければならない理由はありますか? progressBarをリアルタイムで更新するのがいいですが、半分ごとに更新する必要はありません。

+3

1.進行状況は_lie_です。 2.「スリープに小さい値を使用した場合、初めてOnProgressUpdateが呼び出されることはありません。 - それをどうやって決めますか? – Fildor

+0

つまり '[重いタスク]'は 'doInBackground'スレッドに' PublishProgress'を渡すべきです。 – mihail

+0

[重い作業]は、共有ライブラリから呼び出すタスクであることを明確にする必要があります。しかし、私はこれが問題の中心だとは思わない。 whileループは私に悲しみを引き起こしているものです。私がコード例から除外したのは、入力値[0]を報告するログ出力でした。 Thread.Sleep(<500)の場合、OnProgressUpdateは一度呼び出されます(初めてPublishProgressを呼び出したとき)。 DoInBackgroundが完了するとOnProgressUpdateが呼び出される次回はある - つまり、進捗== 100私は500以上、OnProgressUpdateが呼び出されるたびにのThread.sleepを設定した場合。 – hellaandrew

答えて

3

Taskスレッド内の何かを実行して、DoInBackgroundの進捗状況を報告しない方法は意味をなさない。

DoInBackgroundが呼び出されたときにUIスレッドではなくバックグラウンドスレッドである場合、Looper.MainLooper.IsCurrentThreadの値をチェックすることで確認できます。Task.Runを使用する必要はありません。

だからDoInBackgroundに入ると、DB Inflaterは、DBを作成し、テーブル、インデックスなどを作成し、各テーブルにデータなどをロードする一連の手順を実行します。起こった進行の量を公表してください(PublishProgress)。

この例では、3つのステップがあり、各ステップを完了した後に競争が33%増加すると報告しています。

public class DBInflaterAsyncTask : AsyncTask 
{ 
    protected override Object DoInBackground(params Object[] @params) 
    { 
     // You are not on the UI thread 

     Task.Delay(1000); // create db 
     PublishProgress(new Object[] { 33 }); 
     Task.Delay(1000); // create tables 
     PublishProgress(new Object[] { 66 }); 
     Task.Delay(1000); // load table data 
     PublishProgress(new Object[] { 99 }); 
     return null; 
    } 

    protected override void OnProgressUpdate(params Object[] values) 
    { 
     // You are on the UI thread 

     Log.Debug("SomeTag", values[0].ToString()); 
    } 
} 
+1

この回答は、進捗のベンチマークとして使用する具体的な整数値がない場合、おそらく正しいアプローチの最も良い表現です。したがって、あなた自身の進捗状況を設定することが最良の選択肢です。 – Digitalsa1nt

+0

私の質問の下で私が上に作ったコメントを参照してください。私の問題は、バックグラウンドで処理されているものではなく、実際の進捗計算を行っているものでもありません。これは、私がPublishProgressを呼び出しているレートのようです。あなたは追いつくことができます速くUIスレッドその後、イベントを掲載している場合は、「長いを取得します...など、あなたのバックUIスレッド上で 'OnProgressUpdate'場所を呼び出し、およびメッセージングキューに進捗位置の記事これを更新する – hellaandrew

+0

@hellaandrew (携帯電話のdevオプションでビジュアルな長時間動作のフラッシュを有効にすることができます)。 'OnProgressUpdate'呼び出しをログすると、AsyncTaskが例外をスローして終了するか、バックグラウンドスレッドをブロック/ロックしない限り、呼び出されない方法はありません。 – SushiHangover

関連する問題