2017-03-07 4 views
2

私は愚かな要件のように思えるものを持っている:UIスレッドでメソッドを呼び出すときにサービススレッドをブロックすることはできますか?

私はUIスレッドからアクセスされなければならない一つの方法を実行している間、私は私のIntentServiceスレッドをブロックする必要があります。これどうやってするの?

HandlerLooper.getMainLooper()を使用してUIメソッドを実行できますが、もちろん残りのサービス処理は続行されます。

もう少し詳細:

マイサービス同期のコンテンツ徐々に新しいアイテムでUIを更新するために、バインダーのコールバックを使用しています。アイテムのリストに影響を与えるすべてのメソッドは、StaggeredGridLayoutがConcurrentModificationExceptionsを投げるのを避けるためにUIスレッドにバインドされています。

しかし、サービスの開始時に、各コンテンツソースを同期する前に、現在のIDを取得するためにリストを呼び出す必要があります。これはUIスレッドアクセスが必要です。

サービスを開始するときに私がこのリストを提供するだけの理由がないのは、アプリが応答し続ける必要があるということです(つまり、同期するとアイテムを削除することができます)

ソリューション同期さ:

を私が思いついた最善の解決策は、他のすべてのために2つのハンドラ、UIメソッドの主なルーパーの1、その他を作成し、それらの間でメッセージを送信することです。許容できるクリーンなソリューションのようには感じられません

もう1つは、同じUIメソッドのスレッドセーフバージョンを作成し、まずコンテンツの配列コピーを行い、コピーでループします。私はバグを引き起こすのが難しいので、arraycopy操作が安全でない(ConcurrentModificationExceptionになりやすい)かどうかはわかりません。だから私はこれも受け入れられるかどうかはわかりません。

+0

通常、サービススレッド*はUIスレッドです。 –

+0

これはIntentServiceなので、私は –

+0

が 'synchronized'ブロックのリストにアクセスするメソッドをラップすることを明確にしておく必要があります – nandsito

答えて

0

AsyncTaskを使用するソリューションを作成しました。

ここでタスクを呼び出しますActivityです:バックグラウンドでのアイテムを更新しAsyncTask

public class CallingActivity extends Activity { 

    // method that does all the synchronization 
    private void doSync() { 

     // for each item you want to sync 
     int itemId; 

     new ItemUpdateAsyncTask(itemId, this).execute(); 
    } 

    // this method is called for each synced item 
    public void syncItem(int itemId, Object syncedItem) { 
     // update list etc. 
    } 
} 

を:

public class ItemUpdateAsyncTask extends AsyncTask<Void, Void, Object> { 

    // the id of the item to be updated 
    private final int mItemId; 
    // reference to the activity that will be notified 
    // of the item update 
    private final WeakReference<CallingActivity> mCallingActivity; 

    public ItemUpdateAsyncTask(int itemId, CallingActivity callingActivity) { 
     super(); 
     mItemId = itemId; 
     mCallingActivity = new WeakReference<>(callingActivity); 
    } 

    @Override 
    protected Object doInBackground(Void... params) { 

     // sync item in background 
     Object syncedItem; 

     return syncedItem; 
    } 

    @Override 
    protected void onPostExecute(Object syncedItem) { 
     CallingActivity callingActivity = mCallingActivity.get(); 
     if (callingActivity != null) { 

      // update item in main thread 
      callingActivity.syncItem(mItemId, syncedItem); 
     } 
    } 
} 

私は代わりにAsyncTask Sを使用して、このソリューションを設計する方が簡単だと思いますコールバックオブジェクトが通過するため、Serviceが返されます。サービスとアクティビティは、シリアライズ可能なデータだけを運ぶことができるインテントによって互いに通信することができます。ご覧のように、asynctaskはコールバックオブジェクトを参照することができます。そうでなければ、アクティビティにブロードキャストレシーバを登録しなければならず、サービスはシリアル化する必要がある更新されたアイテムでブロードキャストを送信する必要があります。しかし、これも実行可能な解決策です。

ユーザーは、それがバックグラウンドで何かをするとの結果をプッシュしますが、このようなアーキテクチャを設計する際に注意すべき点、である

を実行している時間の間に、いくつかのactivitesの間で行くことができます発信者。発呼者は、例えば、 Activityは、すでに終了していて、バックグラウンド作業が終了するまでにガベージコレクションされている可能性があります。それが私がWeakReferenceに呼び出し元をラップした理由です。

+1

インテントサービスには、あなたが知っているクライアントに返答するために使用できるバインダーがあります。私のアプリケーションにはバインダーが会話するオブジェクトがあり、各アクティビティーは自分のオブジェクトを観察します(非同期タスクの実行には時間がかかりすぎます)。私はこの答えを唯一のものとして受け取り、よく書かれています –

関連する問題