5

現在、次のニーズを持つ Android アプリケーションを開発しています。

Service で開始されたワーカー スレッド。このスレッドはいくつかの処理を行い、メインのアクティビティから呼び出され、同じアクティビティにいくつかの非同期応答を提供する必要があります。

アクティビティからサービスを呼び出すのは簡単です (IBinder のもの)

私の質問は、サービス コールバックの適切な実装に関するものです。

最初にアクティビティに android.os.Handler を追加し、MyActivity.handleMessage(Message) でスレッドの応答を処理するつもりでしたが、これには、このハンドラーのサービスへの参照を与える必要があります。では、Android OS が方向の変更などによりアクティビティを破棄/再作成することを決定した場合はどうなりますか? サービスで (間接的に) 参照されているので、アクティビティは存続しますか? とにかく Activity が破棄/再構築された場合、 Service の Handler 参照はどうなりますか?

サービススレッドからアクティビティをコールバックするための正しい方法を使用していないと思うので、誰かが正しい方法を教えてくれるかどうか知りたかったのです。

ティア

4

4 に答える 4

4

LocalBroadcastManagerを使用することを好みます

のコードの例を次に示しますActivity

BroadcastReceiver localBroadcastReceiver = new BroadcastReceiver()
{
    @Override
    public void onReceive(Context context, Intent intent)
    {
        Log.d("BroadcastReceiver", "Message received " + intent.getAction());
        Log.d("BroadcaseReceiver", "Received data " + intent.getStringExtra("com.my.package.intent.EXTRA_DATA"));
    }
};

@Override
protected void onStart()
{
    super.onStart();
    final LocalBroadcastManager localBroadcastManager =
        LocalBroadcastManager.getInstance(this);
    final IntentFilter localFilter = new IntentFilter();
    localFilter.addAction("com.my.package.intent.ACTION_NAME_HERE");
    localBroadcastManager.registerReceiver(localBroadcastReceiver, localFilter);
}

@Override
protected void onStop()
{
    super.onStop();
    final LocalBroadcastManager localBroadcastManager =
        LocalBroadcastManager.getInstance(this);
    // Make sure to unregister!!
    localBroadcastManager.unregisterReceiver(localBroadcastReceiver);
}

コードベースの他の場所 (バックグラウンド スレッドの完了時など):

final LocalBroadcastManager localBroadcastManager =
    LocalBroadcastManager.getInstance(context);
final Intent intent = new Intent("com.my.package.intent.ACTION_NAME_HERE")
intent.putExtra("com.my.package.intent.EXTRA_DATA", yourBackgroundData);
localBroadcastManager.sendBroadcast(intent);

もちろん、 を使用intent.putExtraしてデータを追加したり、複数のアクションを使用してブロードキャスト メッセージを区別したりできます。

于 2013-03-14T15:53:00.847 に答える
3

Applicationクラス内のアクティビティとサービス間のすべての通信を一元化することで、これを実現しました。クラスを拡張し、Applicationそこにサービスにバインドしてコールバックを受け入れるメソッドを用意します。このアーキテクチャでは、Activityと の間に直接的な関係はありません。Service

このメカニズムの利点は、アクティビティの遷移中、およびアクティビティの終了と再作成中に、サービスへのバインド解除/再バインドについて心配する必要がないことです。クラスはこれらApplicationすべてを管理し、アクティビティの影響を受けません。クラスはすべてのApplicationコールバックを受け取ります。コールバックをどう処理するかを決定するコードがそこに必要です。おそらく、いくつかのデータをApplicationクラスに保存してから、利用可能な新しいデータがあることをアクティビティに通知するか、または同様のことを行いたいと思うでしょう。

もう 1 つの方法はService、コールバックをブロードキャストすることです。Handlerこの場合、サービスとアクティビティ間の結合は緩いため、アクティビティで を作成してから に渡す必要はありませんService。アクティビティはBroadcastReceiver、関心のあるコールバックの を登録するか、マニフェストでこれを管理できます。

于 2013-03-14T16:05:41.590 に答える
0

あなたが言うように、1つの解決策はMyActivity.handleMessage(Message)を使用することです。アクティビティが開始(または再開)されるたびに、おそらくサービス(あなたが言及する「onBind」のもの)を開始しようとします。サービスがすでに実行されている場合、害はありません。バインドが完了したら、メッセンジャーに返信を送信するようにサービスに指示します。

再起動が確実に処理されるようにするには、onStopで、現在存在しないメッセンジャーに誤ってメッセージを送信しないように、そのメッセンジャーを「返信先のリスト」から削除するようにサービスに指示する必要があります。再起動の一部としてonStartが呼び出されると、正しいメッセンジャーが送信されます。

明らかに、これには、サービスがこれを処理し、送信するメッセンジャーがないときに送信する応答があるシナリオを何らかの方法で管理する必要があります。メッセンジャーが使用可能になるまで情報を保持するか、情報をドロップします。アクティビティは、onStartで実行したバインドに続くものとして、すべての状態情報を明示的に取得します。

もう1つのアプローチは、結果が利用可能かどうかを確認するための処理が進行中であることがわかったときに、アクティビティがサービスを頻繁に(10秒?)ポーリングし、すべての情報が戻ったらポーリングを停止することです。

于 2013-03-14T15:48:27.897 に答える
0

非同期サービス呼び出しの場合、開始時にコールバック参照を渡すと思います。

コールバックは、このアプローチの標準であるバインダー スレッドによって実行されます。

もちろん、呼び出しを開始するアクティビティは、バインダー スレッドが独自のプロセスで実行されるという事実に依存できます。そのため、コールバックからメイン/UI スレッドに戻るのは非常に簡単です。

したがって、コールバックがメイン/UI スレッドで何かを処理する必要がある場合は、

(new Handler(Looper.getMainLooper()).post()

これには、コードが実行される時点でメイン/UI スレッドが動的に検出されるという利点があります。一方、メイン/UI スレッドは変更されないため、それも必要ありません。したがって、ビュー参照またはコールバックで手元にある可能性のある他のものを介して見つけることもできます。

于 2013-03-14T15:50:48.660 に答える