Поиск…


Вступление

Служба работает в фоновом режиме для выполнения длительных операций или для выполнения работы для удаленных процессов. Служба не предоставляет никакого пользовательского интерфейса, который выполняется только в фоновом режиме с помощью ввода пользователя. Например, служба может воспроизводить музыку в фоновом режиме, когда пользователь находится в другом приложении, или может загружать данные из Интернета, не блокируя взаимодействие пользователя с устройством 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();
}


Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow