web-dev-qa-db-ja.com

Androidでシングルトンとしてサービスを使用する

シングルトンとして機能するServiceを作成することは悪い習慣ですか?つまり、決して停止せず、他のエンジンやServiceが使用するプライベートデータが含まれているActivitiesがあるため、Serviceは次のようになります。

public class CustomService extends Service {
    private List<Profile> mProfiles;
    private static CustomService instance;

     public static CustomService getInstance() {
         if(instance == null) {
             instance = new CustomService();
         }
         return instance;
     }

     public List<Profile> getProfiles() {
          return mProfiles;
     }

     @Override
     public int onStartCommand(Intent intent, int flags, int startId) {
         ...
     }
     ...
}

シングルトンの代わりにServiceを実行する理由は、アプリケーションから独立して機能する必要があるためです。これは、開始時に、決して閉じてはならず、アプリケーションに依存しないWebソケットに接続するためです。どうしたらいいですか?他のエンジンやServiceからいくつかのデータ(例えばmProfiles配列)を利用できるようにするためにActivitiesを再利用するより良い方法はありますか?

Serviceがシングルトンとして機能することをどこかで読みましたが、アプリケーションの他のポイントからプライベート変数にアクセスする方法がわかりません。

10
FVod

シングルトンとして機能するサービスを作成することは悪い習慣ですか?

これは冗長であり、あなたが提案する方法では、AndroidServiceの観点から機能するアプリケーションコンポーネントとして機能しません。

  • Applicationライフサイクルは、次の影響を受けます
  • システムイベント。

アプリケーションコンポーネントのそのような意図は、

  • _AndroidManifest.xml_での宣言
  • トリガー(開始/バインド/登録)および
  • (システムによって)Application内にコンポーネントのインスタンスを作成し、それをApplicationThread/ActivityThreadに「アタッチ」します。

つまり、アプリケーションコンポーネントはOSプロセスによってホストされるApplicationインスタンスに関連付けられており、独立して実行できないという事実がもたらされます。


あなたのアプローチに関して、2つのシナリオがあります:

1。CustomServiceのデフォルトコンストラクタはパターンに従ってプライベートです

getInstance()を呼び出すと、CustomServiceの単一のインスタンスが作成されます。インスタンスは、Javaオブジェクト(シングルトン)であり、AndroidServiceアプリケーションコンポーネントと共通点はありません。 onStart()onStartCommand()などのメソッドがシステムによって呼び出されることはありません。

「サービス」(マニフェストで宣言)を startService(Intent) で開始しようとすると、_IllegalAccessException: access to constructor not allowed_で失敗します。

2。CustomServiceのデフォルトコンストラクタはパブリックです(投稿されたコードに従って)。

サービスがAndroidManifestで宣言され、デフォルトのコンストラクターが空の場合、startService()は失敗しませんが、getInstance()CustomServiceの別のインスタンスを作成しますこれはAndroidServiceアプリケーションコンポーネントとして扱われません。

これはシングルトンではありません。


どうしたらいいですか。他のエンジンやアクティビティからいくつかのデータ(たとえば、mProfiles配列)を利用できるようにするために、サービスを再利用するより良い方法はありますか?

ドキュメント に従ってServiceを使用し、必要な通信の種類を選択します。

  • 一方向通信(Activity _-->_ Service)- started Service を使用し、各IntentmProfilesクラスがonStartCommand()Profile )を実装している場合のParcelableのように、データを添付します。
  • 双方向通信(Activity _<->_ Service)- bound Service を使用し、IBinder経由で通信します。

最後に、ServiceAndroidはシングルトンです。システム内の各サービスのインスタンスは1つだけです。オンデマンドで起動し、保留中のすべてのIntents /バインド済みクライアントを処理します。完了するか、明示的に停止すると、破棄されます。

14
Onik

サービスをシングルトンとして作成することはお勧めしません。サービススティッキを開始して、サービスを名前で取得し、アクティビティ内から次のコードを使用して、サービスが機能しているかどうかを確認できます。

private boolean isMyServiceRunning(Class<?> serviceClass) {
    ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
    for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
        if (serviceClass.getName().equals(service.service.getClassName())) {
            return true;
        }
    }
    return false;
}
1
Mohamed

(およびこれをサポートするドキュメントが見つからないが、そうであると想定している)サービスがAndroidフレームワークによって1回だけインスタンス化されている場合、instanceを初期化できますService.onCreate。唯一の欠点は、これがいつ呼び出されるかが保証されないことです。つまり、Application.onCreate内でstartServiceを呼び出す場合、サービスが利用可能になるまでに少し待つ必要があります実際にインスタンス化。

0
mbonnin