Android
обслуживание
Поиск…
Вступление
Служба работает в фоновом режиме для выполнения длительных операций или для выполнения работы для удаленных процессов. Служба не предоставляет никакого пользовательского интерфейса, который выполняется только в фоновом режиме с помощью ввода пользователя. Например, служба может воспроизводить музыку в фоновом режиме, когда пользователь находится в другом приложении, или может загружать данные из Интернета, не блокируя взаимодействие пользователя с устройством Android.
замечания
Если вы еще не определили свою службу в своем AndroidManifest.xml, при попытке запустить ее вы получите ServiceNotFoundException
.
Замечания:
Информацию о IntentService
см. Здесь: Пример IntentService
Запуск службы
Запуск службы очень прост, просто позвоните startService
с намерением, изнутри Activity:
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()
вызывается другим компонентом, например Activity или BroadcastReceiver. Когда вы используете этот метод, Служба будет работать до тех пор, пока вы не назовете stopSelf()
или stopService()
. Обратите внимание, что независимо от того, сколько раз вы вызываете onStartCommand()
, методы stopSelf()
и stopService()
должны быть вызваны только один раз, чтобы остановить службу.
-
onBind()
:
Выполняется, когда компонент вызывает bindService()
и возвращает экземпляр IBInder, предоставляя канал связи Службе. Вызов функции bindService()
будет поддерживать работу службы, если к ней привязаны клиенты.
-
onDestroy()
:
Выполняется, когда служба больше не используется и позволяет удалять ресурсы, которые были выделены.
Важно отметить, что в течение жизненного цикла службы могут быть вызваны другие обратные вызовы, такие как onConfigurationChanged()
и onLowMemory()
https://developer.android.com/guide/components/services.html
Определение процесса обслуживания
Поле android:process
определяет имя процесса, в котором должна запускаться служба. Обычно все компоненты приложения запускаются в процессе по умолчанию, созданном для приложения. Однако компонент может переопределить значение по умолчанию со своим собственным атрибутом процесса, что позволяет распространять ваше приложение на нескольких процессах.
Если имя, присвоенное этому атрибуту, начинается с двоеточия (':'), служба будет запускаться в отдельном отдельном процессе.
<service
android:name="com.example.appName"
android:process=":externalProcess" />
Если имя процесса начинается с символа в нижнем регистре, служба будет выполняться в глобальном процессе этого имени при условии, что у него есть разрешение на это. Это позволяет компонентам в разных приложениях совместно использовать процесс, уменьшая использование ресурсов.
Создание связанного сервиса с помощью Binder
Создайте класс, который расширяет класс 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
с сервисом в 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
:
// 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 tools создаст соответствующий .java
файл. Этот файл будет содержать класс Stub
который реализует наш интерфейс helpl и который нам нужно расширить:
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;
}
}
Создание несвязанного сервиса
Первое, что нужно сделать, - добавить службу в AndroidManifest.xml
внутри <application>
:
<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()
метод 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();
}