Android
サービス
サーチ…
前書き
サービスは、長時間実行される操作を実行したり、リモートプロセスの作業を実行するためにバックグラウンドで実行されます。サービスは、ユーザーの入力でバックグラウンドでのみ実行されるユーザーインターフェイスを提供しません。たとえば、ユーザーが別のAppにいる間にバックグラウンドで音楽を再生したり、Androidデバイスとのユーザーのやりとりを妨げることなくインターネットからデータをダウンロードしたりすることができます。
備考
AndroidManifest.xmlでサービスを定義していない場合、サービスを開始しようとするとServiceNotFoundException
が返されます。
注意:
IntentService
に関する情報は、 IntentService
してください: IntentServiceの例
サービスの開始
サービスを開始することは非常に簡単です。アクティビティ内から目的を持ってstartService
を呼び出すだけです:
Intent intent = new Intent(this, MyService.class); //substitute MyService with the name of your service
intent.putExtra(Intent.EXTRA_TEXT, "Some text"); //add any extra data to pass to the service
startService(intent); //Call startService to start the service.
サービスのライフサイクル
サービスライフサイクルには以下のコールバックがあります
-
onCreate()
:
サービスが最初に作成されたときに実行され、必要な初期設定を設定します。このメソッドは、サービスがまだ実行されていない場合にのみ実行されます。
-
onStartCommand()
:
startService()
がアクティビティやBroadcastReceiverのような別のコンポーネントによって呼び出されるたびに実行されstartService()
。このメソッドを使用すると、 stopSelf()
またはstopService()
を呼び出すまでサービスが実行されます。それに関係なく、あなたが呼び出し回数の注意onStartCommand()
メソッドstopSelf()
とstopService()
サービスを停止するために、一度だけ起動する必要があります。
-
onBind()
:
コンポーネントがbindService()
を呼び出してbindService()
のインスタンスを返し、通信チャネルをサービスに提供するときに実行されます。 bindService()
を呼び出すと、バインドされたクライアントがある限り、サービスは実行されたままになります。
-
onDestroy()
:
サービスがもはや使用されなくなったときに実行され、割り当てられたリソースの廃棄が可能になります。
サービスのライフサイクル中に、 onConfigurationChanged()
やonLowMemory()
などの他のコールバックが呼び出される可能性があることに注意することは重要です。
https://developer.android.com/guide/components/services.html
サービスのプロセスの定義
android:process
フィールドは、サービスが実行されるプロセスの名前を定義します。通常、アプリケーションのすべてのコンポーネントは、アプリケーション用に作成されたデフォルトのプロセスで実行されます。ただし、コンポーネントは独自のプロセス属性を使用してデフォルトをオーバーライドすることができ、アプリケーションを複数のプロセスに分散することができます。
この属性に割り当てられた名前がコロン( ':')で始まる場合、サービスはそれ自身の別のプロセスで実行されます。
<service
android:name="com.example.appName"
android:process=":externalProcess" />
プロセス名が小文字で始まる場合、サービスはその名前のグローバルプロセスで実行されます。これにより、異なるアプリケーションのコンポーネントがプロセスを共有し、リソースの使用を削減できます。
バインダーの助けを借りてバインドされたサービスを作成する
Service
クラスを拡張するクラスを作成し、オーバーライドされたメソッドonBind
て、ローカルのバインダーインスタンスを返します。
public class LocalService extends Service {
// Binder given to clients
private final IBinder mBinder = new LocalBinder();
/**
* Class used for the client Binder. Because we know this service always
* runs in the same process as its clients, we don't need to deal with IPC.
*/
public class LocalBinder extends Binder {
LocalService getService() {
// Return this instance of LocalService so clients can call public methods
return LocalService.this;
}
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
}
次に、あなたのアクティビティでonStart
コールバックでサービスにバインドし、 ServiceConnection
インスタンスを使用してonStop
バインドを解除します。
public class BindingActivity extends Activity {
LocalService mService;
boolean mBound = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
@Override
protected void onStart() {
super.onStart();
// Bind to LocalService
Intent intent = new Intent(this, LocalService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onStop() {
super.onStop();
// Unbind from the service
if (mBound) {
unbindService(mConnection);
mBound = false;
}
}
/** Defines callbacks for service binding, passed to bindService() */
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className,
IBinder service) {
// We've bound to LocalService, cast the IBinder and get LocalService instance
LocalBinder binder = (LocalBinder) service;
mService = binder.getService();
mBound = true;
}
@Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
}
リモートサービスの作成(AIDL経由)
.aidl
ファイルを使用してサービスアクセスインターフェースを.aidl
:
// IRemoteService.aidl
package com.example.android;
// Declare any non-default types here with import statements
/** Example service interface */
interface IRemoteService {
/** Request the process ID of this service, to do evil things with it. */
int getPid();
}
今すぐアプリケーションをビルドしたら、sdkツールは適切な.java
ファイルを生成します。このファイルには、aidlインタフェースを実装し、拡張する必要があるStub
クラスが含まれます:
public class RemoteService extends Service {
private final IRemoteService.Stub binder = new IRemoteService.Stub() {
@Override
public int getPid() throws RemoteException {
return Process.myPid();
}
};
@Nullable
@Override
public IBinder onBind(Intent intent) {
return binder;
}
}
その後、活動中:
public class MainActivity extends AppCompatActivity {
private final ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
IRemoteService service = IRemoteService.Stub.asInterface(iBinder);
Toast.makeText(this, "Activity process: " + Process.myPid + ", Service process: " + getRemotePid(service), LENGTH_SHORT).show();
}
@Override
public void onServiceDisconnected(ComponentName componentName) {}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
protected void onStart() {
super.onStart();
Intent intent = new Intent(this, RemoteService.class);
bindService(intent, connection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onStop() {
super.onStop();
unbindService(connection);
}
private int getRemotePid(IRemoteService service) {
int result = -1;
try {
result = service.getPid();
} catch (RemoteException e) {
e.printStackTrace();
}
return result;
}
}
アンバウンドサービスの作成
まず、 <application>
タグ内のAndroidManifest.xml
にサービスを追加します。
<application ...>
...
<service
android:name=".RecordingService"
<!--"enabled" tag specifies Whether or not the service can be instantiated by the system — "true" -->
<!--if it can be, and "false" if not. The default value is "true".-->
android:enabled="true"
<!--exported tag specifies Whether or not components of other applications can invoke the -->
<!--service or interact with it — "true" if they can, and "false" if not. When the value-->
<!--is "false", only components of the same application or applications with the same user -->
<!--ID can start the service or bind to it.-->
android:exported="false" />
</application>
別のパッケージ(例:.AllServices.RecordingService)でサービスクラスを管理する場合は、サービスがどこにあるかを指定する必要があります。したがって、上記の場合、次のように変更します。
android:name=".RecordingService"
に
android:name=".AllServices.RecordingService"
そうする最も簡単な方法は、完全なパッケージ名を指定することです。
次に、実際のサービスクラスを作成します。
public class RecordingService extends Service {
private int NOTIFICATION = 1; // Unique identifier for our notification
public static boolean isRunning = false;
public static RecordingService instance = null;
private NotificationManager notificationManager = null;
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate(){
instance = this;
isRunning = true;
notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId){
// The PendingIntent to launch our activity if the user selects this notification
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, MainActivity.class), 0);
// Set the info for the views that show in the notification panel.
Notification notification = new NotificationCompat.Builder(this)
.setSmallIcon(R.mipmap.ic_launcher) // the status icon
.setTicker("Service running...") // the status text
.setWhen(System.currentTimeMillis()) // the time stamp
.setContentTitle("My App") // the label of the entry
.setContentText("Service running...") // the content of the entry
.setContentIntent(contentIntent) // the intent to send when the entry is clicked
.setOngoing(true) // make persistent (disable swipe-away)
.build();
// Start service in foreground mode
startForeground(NOTIFICATION, notification);
return START_STICKY;
}
@Override
public void onDestroy(){
isRunning = false;
instance = null;
notificationManager.cancel(NOTIFICATION); // Remove notification
super.onDestroy();
}
public void doSomething(){
Toast.makeText(getApplicationContext(), "Doing stuff from service...", Toast.LENGTH_SHORT).show();
}
}
このサービスは、実行時に通知を表示し、 doSomething()
メソッドが呼び出されたときにトーストを表示することができます。
あなたが気づくように、それはシングルトンとして実装され、独自のインスタンスを追跡しますが、通常の静的シングルトンファクトリメソッドはありません。なぜなら、サービスは自然にシングルトンであり、意図によって作成されるからです。このインスタンスは、実行時にサービスへの「ハンドル」を得るために外部に役立ちます。
最後に、アクティビティからサービスを開始および停止する必要があります。
public void startOrStopService(){
if( RecordingService.isRunning ){
// Stop service
Intent intent = new Intent(this, RecordingService.class);
stopService(intent);
}
else {
// Start service
Intent intent = new Intent(this, RecordingService.class);
startService(intent);
}
}
この例では、サービスは現在の状態に応じて同じ方法で開始および停止します。
doSomething()
メソッドをアクティビティから呼び出すこともできます:
public void makeServiceDoSomething(){
if( RecordingService.isRunning )
RecordingService.instance.doSomething();
}