web-dev-qa-db-ja.com

アクティビティからIntentServiceを開始し、IntentServiceが終了したらアクティビティを更新します

私のAndroidアプリケーションでは、アダプター付きの単純なリストビューがあります。リストビューにデータを入力するという重いクエリがあります。そこで、別のスレッドで実行されるIntentServiceに配置します。

IntentServiceは通常、一部のデータをクエリしてSQLiteデータベースに挿入するために、単独で個別に実行されます。

しかし今、私は次の可能性を持ちたいと思います:

  1. アクティビティは、startService()を使用してIntentServiceを開始します。
  2. IntentServiceはその重い仕事をします。
  3. IntentServiceが終了すると、アクティビティに結果を通知して、アクティビティを更新して新しいデータを表示できるようにする必要があります。

これは可能ですか?このトピックに関するStackOverflowの質問をたくさん読みました。しかし、すべての質問で、別の解決策がありました。ですから、皆さんにお聞きしたいのですが、私の目的に最適なソリューションはどれですか?

  • IntentServiceをアクティビティにバインドすることは、アクティビティの構成変更などと競合する可能性があるため、最善の解決策ではないようです。正しいですか?
  • このブログ投稿 ParcelablesでAIDLを使用することを提案しています-これは私には非常に複雑に聞こえます。もっと簡単な方法がありますね。
  • アクティビティでブロードキャストレシーバーを設定し、終了時にIntentServiceでこのブロードキャストを起動できます。
  • 一部の人々はあなたがすべきだと言います createPendingResult()を使用してPendingIntentを渡す IntentServiceに。 IntentServiceは、エクストラでそのPendingIntentを検出すると、これを使用して、アクティビティのonActivityResult()をトリガーします。これは選択の方法ですか?
27
caw

例として、 ResultReceiver を使用して、ActivityListActivityを拡張)のアダプターでnotifyDataSetChanged()を呼び出します。それはあなたが必要とすることを何でもするように適応させることができます。

ResultReceiverコード:

public class MyResultReceiver extends ResultReceiver {

    private Context context = null;

    protected void setParentContext (Context context) {
        this.context = context;
    }

    public MyResultReceiver(Handler handler) {
        super(handler);
    }

    @Override
    protected void onReceiveResult (int resultCode, Bundle resultData) {

        // Code to process resultData here

        ((BaseAdapter) ((ListActivity)context).getListAdapter()).notifyDataSetChanged();
    }
}

MyActivityコード:

public class MyActivity extends ListActivity {

    private MyResultReceiver theReceiver = null;

    ...

    private void callService () {
        theReceiver = new MyResultReceiver(new Handler());
        theReceiver.setParentContext(this);
        Intent i = new Intent("com.mycompany.ACTION_DO_SOMETHING");

        // Code to define and initialize myData here

        i.putExtra("someData", myData);
        i.putExtra("resReceiver", theReceiver);
        startService(i);

    }
}

IntentServiceコード:

Bundle resultBundle = new Bundle();
ResultReceiver resRec = intent.getParcelableExtra("resReceiver");

// Do some work then put some stuff in resultBundle here

resRec.send(12345, resultBundle);
23
Squonk

他の回答はどれも公式のAndroidドキュメントを参照していません

https://developer.Android.com/training/run-background-service/report-status.html

これは、Activity-IntentService通信の場合、「ステータスを送受信するための推奨される方法は、LocalBroadcastManagerを使用することです。これにより、ブロードキャストIntentオブジェクトが独自のアプリのコンポーネントに制限されます」と明確に述べられています。

12
DSoldo

IntentServiceが完了すると、 LocalBroadcastManager を使用して、登録されているアクティビティにインテントを送信する必要があります。

IntentServiceには、次のようなコードが含まれます。

private void sendBroadcast() {
    Intent intent = new Intent("myBroadcastIntent");
    intent.putExtra("someName", someValue);
    LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}

通知を受け取るアクティビティには、次のようなコードが含まれます。

@Override
protected void onCreate(Bundle savedInstanceState) {
    // ...
    BroadcastReceiver receiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String someValue = intent.getStringExtra("someName");
            // ... do something ...
        }
    };
    LocalBroadcastManager.getInstance(this)
        .registerReceiver(receiver, new IntentFilter("myBroadcastIntent"));
}

詳細については、ブログ投稿 LocalBroadcastManager In Service To Activity Communicationsの使用 を参照してください。

12
Edward Brey

結果を待つアクティビティでブロードキャストレシーバーを使用することをお勧めします。サービスは、カスタムsendBroadcastIntentを使用するだけです。

3
rui.araujo

イベントバスが行く道だと思います。シンプルで効果的なプロセス間通信。

2
Eugene