2017-03-16 11 views
5

私はAndroidのUIスレッドのコンテキストでのコルーチンの使用を模索しています。 Coroutines Guide UIに記載されているようにcontextJobを実装しました。バックグラウンドの作業はGUIから見て、クリックするたびに再起動します(現在実行中のものを停止してもう一度開始します)。Jobインスタンスを再利用する方法はありますか?

しかし、かつてそうであっても、子ジョブを作成し、再利用することはできませんキャンセルされたジョブ:

val job = Job(contextJob) 

と、それは、再割り当てする必要があるので、それが解決しないキャンセル。

Jobインスタンスを再利用する方法はありますか?

答えて

4

Jobは、設計により非常に単純なライフサイクルを有する。その「完了」状態はの最終であり、AndroidのActivityの「破棄」状態に非常に似ています。したがって、親のJobは、ガイドで説明されているように、Activityに関連付けられることをお勧めします。アクティビティが破棄された場合にのみ、親ジョブをキャンセルする必要があります。破壊されたアクティビティは再利用できないため、ジョブを再利用する必要はありません。

各クリックで作業を開始するための推奨される方法は、不必要な並行性を避けるためにアクターを使用することです。このガイドでは、クリックごとに開始する方法を示していますが、現在実行中の操作をキャンセルする方法は示されていません。俳優は常にアクティブで

fun View.onClick(action: suspend() -> Unit) { 
    var currentJob: Job? = null // to keep a reference to the currently running job 
    // launch one actor as a parent of the context job 
    // actor prevent concurrent execution of multiple actions 
    val eventActor = actor<Unit>(contextJob + UI, capacity = Channel.CONFLATED) { 
     for (event in channel) { 
      currentJob = Job(contextJob) // create a new job for this action 
      try { 
       // run an action within its own job 
       withContext(currentJob!!) { action() } 
      } catch (e: CancellationException) { 
       // we expect it to be cancelled and just need to continue 
      } 
     } 
    } 
    // install a listener to send message to this actor 
    setOnClickListener { 
     currentJob?.cancel() // cancel whatever job we were doing now (if any) 
     eventActor.offer(Unit) // signal to start next action when possible 
    } 
} 

は、その親ジョブまで(アクティビティに添付:

あなたは他のすべてとは別に、コード解約のブロックを作るためにwithContextとの組み合わせでJobの新鮮なインスタンスが必要になります)がキャンセルされます。俳優はクリックを待ち、クリックごとにactionを開始します。ただし、actionの各呼び出しは、withContextブロックを使用して自身のJobにラップされるため、親ジョブとは別にキャンセルできます。

このコードは、取り消しできない、または取り消すまでに時間がかかることに注意してください。アクションは、リソースが取り消されたときにそのリソースをクリーンアップする必要があり、このコードはアクターを使用するため、前のアクションのクリーンアップが次のアクションの開始前に完了するようにします。

関連する問題