نظرة عامة على الخدمات الخاضعة للحظر

الخدمة المرتبطة هي الخادم في واجهة خادم العميل. يتيح للمكونات مثل ربط الأنشطة بالخدمة وإرسال الطلبات وتلقي الردود وتنفيذ الاتصال البيني للعمليات (IPC). عادةً ما تتواجد الخدمة المرتبطة فقط بينما تخدم خدمة أخرى في التطبيق ولا يتم تشغيله في الخلفية إلى أجل غير مسمى.

يصف هذا المستند كيفية إنشاء خدمة مرتبطة، بما في ذلك كيفية الربط إلى الخدمة من مكونات التطبيق الأخرى. للحصول على معلومات إضافية حول الخدمات في عام، مثل كيفية إرسال الإشعارات من خدمة وضبط الخدمة لتشغيلها في المقدّمة، راجع نظرة عامة على الخدمات

الأساسيات

الخدمة المرتبطة هي تنفيذ لفئة Service تتيح الأخرى اللازمة وتتفاعل معه. لتوفير ارتباط لـ ستنفذ طريقة معاودة الاتصال onBind(). هذا النمط تؤدي إلى إرجاع كائن IBinder يحدد واجهة البرمجة التي يمكن للعملاء استخدامها للتفاعل مع الخدمة.

الالتزام بخدمة تم بدؤها

كما هو موضَّح في مقالة نظرة عامة على الخدمات، يمكنك إنشاء خدمة بدأت ومرتبطة في الوقت نفسه. أي أنه يمكنك بدء من خلال الاتصال بالرقم startService()، ما يتيح تعمل إلى أجل غير مسمى. يمكنك أيضًا السماح للعميل بالالتزام بالخدمة من خلال يَتِمُّ الْآنَ الِاتِّصَالْ بِـ bindService().

إذا سمحت ببدء الخدمة وربطها، فعند بدء تشغيلها، لا يدمر النظام الخدمة عند إلغاء الربط من قِبل كل العملاء. بدلاً من ذلك، يجب عليك إيقاف الخدمة صراحةً من خلال الاتصال بـ stopSelf() أو stopService().

على الرغم من أنّك عادةً ما تنفِّذ إما onBind() أو onStartCommand()، ففي بعض الأحيان الضرورية لـ وتنفيذ كليهما. على سبيل المثال، قد يجد مشغِّل الموسيقى أنّه من المفيد تشغيل خدمته. إلى أجل غير مسمى وأن تكون ملزمة أيضًا. وبهذه الطريقة، يمكن لأي نشاط بدء الخدمة لتشغيل ويستمر تشغيل الموسيقى حتى إذا غادر المستخدم التطبيق. بعد ذلك، عندما يتفاعل المستخدم إلى التطبيق، فيمكن أن يرتبط النشاط بالخدمة لاستعادة التشغيل.

لمزيد من المعلومات حول دورة حياة الخدمة عند إضافة الربط إلى خدمة تم بدؤها، راجِع قسم إدارة دورة حياة خدمة مرتبطة.

يلتزم العميل بخدمة من خلال استدعاء bindService() عندما يحدث ذلك، يجب توفير تنفيذ للدالة ServiceConnection، والتي ويراقب الاتصال بالخدمة. القيمة المعروضة تشير السمة bindService() إلى ما إذا كانت وجود الخدمة المطلوبة وما إذا كان يُسمح للعميل بالوصول إليها أم لا.

فعندما ينشئ نظام Android الاتصال بين العميل والخدمة، الاتصال برقم "onServiceConnected()" في ServiceConnection. تشير رسالة الأشكال البيانية تتضمّن طريقة onServiceConnected() طريقة IBinder التي يستخدمها العميل بعد ذلك للاتصال بالخدمة المرتبطة.

يمكنك ربط عدة برامج بخدمة في آنٍ واحد. ومع ذلك، يخزِّن النظام مؤقتًا قناة اتصال خدمة IBinder. بمعنى آخر، يستدعي النظام السمة onBind() الخاصة بالخدمة لإنشاء IBinder فقط عند والارتباطات العميلة. ويسلِّم النظام بعد ذلك IBinder نفسها إلى جميع العملاء الإضافيين المرتبطين بتلك الخدمة نفسها، دون الاتصال onBind() مرة أخرى.

عندما يقوم العميل الأخير بإلغاء الربط من الخدمة، يقوم النظام بتدمير الخدمة، ما لم بدأت الخدمة باستخدام startService().

أهم جزء في تنفيذ الخدمة المرتبطة هو تحديد الواجهة التي تعرضها طريقة معاودة الاتصال onBind(). ما يلي: العديد من الطرق التي يمكنك من خلالها تحديد واجهة مستخدم واجهة IBinder.

إنشاء خدمة مرتبطة

عند إنشاء خدمة توفّر الربط، يجب توفير IBinder. توفر واجهة البرمجة التي يمكن للعملاء استخدامها للتفاعل مع الخدمة. هناك ثلاث طرق يمكنك من خلالها تعريف الواجهة:

زيادة فئة Binder
إذا كانت الخدمة خاصة بتطبيقك ويتم تشغيلها في العملية نفسها باعتباره العميل، وهو أمر شائع، تنشئ الواجهة من خلال تمديد Binder الصنف وعرض مثيل له من onBind() يتلقّى العميل Binder للوصول مباشرةً إلى الطرق العامة المتاحة في أي من Binder أو Service.

هذا هو الأسلوب المفضّل عندما تكون خدمتك مجرد عامل في الخلفية التطبيق. إنّ حالة الاستخدام الوحيدة عندما لا تكون هذه هي الطريقة المفضّلة لإنشاء واجهتك، إذا تم استخدام الخدمة بواسطة تطبيقات أخرى أو عبر عمليات منفصلة.

استخدام تطبيق Messenger
إذا كنت بحاجة إلى واجهة للعمل من خلال عمليات مختلفة، يمكنك إنشاء واجهة للخدمة باستخدام Messenger. بهذه الطريقة، يمكن للخدمة تحدّد Handler تستجيب لأنواع مختلفة من كائنات Message.

هذا Handler هو الأساس لـ Messenger الذي يمكنه مشاركة IBinder مع العميل، ما يتيح له إرسال الأوامر إلى الخدمة باستخدام كائنات Message. بالإضافة إلى ذلك، يمكن للعميل تحديد Messenger من الخاصة بها، حتى تتمكن الخدمة من إعادة إرسال الرسائل.

هذه هي أبسط طريقة لإجراء الاتصال البيني للعمليات (IPC)، لأنّ السمة Messenger تضع جميع الطلبات ضمن قائمة انتظار في سلسلة محادثات واحدة لكي لا تضطر إلى تصميم للحفاظ على أمان سلاسل المحادثات.

استخدام لغة AIDL
تعمل لغة تعريف واجهة Android (AIDL) على تحليل العناصر إلى الأساسية التي يمكن لنظام التشغيل فهمها وينظّمها عبر العمليات لتنفيذها IPC. يستند الأسلوب السابق، باستخدام Messenger، إلى لغة AIDL على أنّها هيكلها الأساسي.

كما ذكرنا في القسم السابق، تنشئ Messenger قائمة انتظار من كل طلبات العميل في سلسلة محادثات واحدة، لذلك تتلقى الخدمة الطلبات واحدًا تلو الآخر. إذا، ولكنك ترغب في أن تتعامل خدمتك مع طلبات متعددة في وقت واحد، فيمكنك استخدام لغة تعريف واجهة نظام Android (AIDL) مباشرةً. وفي هذه الحالة، يجب أن تكون خدمتك متوافقة مع سلاسل المحادثات وأن تكون قادرة على تنفيذ سلاسل المحادثات المتعددة.

لاستخدام AIDL مباشرةً، أنشئ ملف .aidl يحدّد واجهة البرمجة. تستخدِم أدوات حزمة تطوير البرامج (SDK) لنظام التشغيل Android هذا الملف لإنشاء فئة مجردة تنفّذ الواجهة وتتعامل مع IPC، يمكنك بعد ذلك التوسع ضمن خدمتك.

ملاحظة: بالنسبة إلى معظم التطبيقات، لا تعد AIDL الخيار الأفضل إنشاء خدمة مرتبطة، لأنها قد تتطلب إمكانيات تعدد سلاسل التعليمات إلى عملية تنفيذ أكثر تعقيدًا. لذلك، لا يناقش هذا المستند كيف لاستخدامه في خدمتك إذا كنت متأكدًا من أنك بحاجة لاستخدام AIDL مباشرةً، يُرجى الاطّلاع على مستند AIDL. جلسة المراجعة.

تمديد فئة Binder

إذا كان التطبيق المحلي فقط يستخدم خدمتك ولا يحتاج إلى ذلك والعمل عبر العمليات، يمكنك عندئذٍ تنفيذ فئة Binder الخاصة بك التي توفّر لعميلك مباشرةً. الوصول إلى الطرق العامة في الخدمة.

ملاحظة: لا ينجح هذا الإجراء إلا إذا كان العميل والخدمة في نفس الوقت التطبيق والمعالجة، وهو الأكثر شيوعًا. فعلى سبيل المثال، قد يكون هذا مناسبًا للموسيقى تطبيق يحتاج إلى ربط نشاط بخدمته الخاصة التي تشغِّل الموسيقى في الخلفية.

لإعداد الأداة، يجب:

  1. في خدمتك، أنشئ مثيلاً لـ Binder يعمل على ما يلي: واحد مما يلي:
    • يحتوي على طرق عامة يمكن للعميل الاتصال بها.
    • عرض مثيل Service الحالي، الذي يتضمن طرقًا عامة يمكن للعميل الاتصال به.
    • لعرض مثيل لفئة أخرى تستضيفها الخدمة بالطرق العامة يمكن للعميل الاتصال به.
  2. يمكنك عرض هذا المثيل من Binder من طريقة معاودة الاتصال onBind().
  3. في برنامج العميل، يمكنك تلقّي Binder من طريقة معاودة الاتصال onServiceConnected() إجراء اتصالات بالخدمة المرتبطة باستخدام الطرق المتاحة.

ملاحظة: يجب أن تكون الخدمة والعميل متطابقَين. بحيث يمكن للعميل بثّ الكائن الذي تم عرضه واستدعاء واجهات برمجة التطبيقات التابعة له بشكل صحيح. الخدمة وعميله يجب أن يكون أيضًا في العملية نفسها، لأن هذا الأسلوب لا يؤدي وتنظيمه عبر العمليات.

على سبيل المثال، إليك خدمة تزوّد العملاء بإمكانية الوصول إلى طرق في الخدمة من خلال تنفيذ Binder:

Kotlin

class LocalService : Service() {
    // Binder given to clients.
    private val binder = LocalBinder()

    // Random number generator.
    private val mGenerator = Random()

    /** Method for clients.  */
    val randomNumber: Int
        get() = mGenerator.nextInt(100)

    /**
     * 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.
     */
    inner class LocalBinder : Binder() {
        // Return this instance of LocalService so clients can call public methods.
        fun getService(): LocalService = this@LocalService
    }

    override fun onBind(intent: Intent): IBinder {
        return binder
    }
}

Java

public class LocalService extends Service {
    // Binder given to clients.
    private final IBinder binder = new LocalBinder();
    // Random number generator.
    private final Random mGenerator = new Random();

    /**
     * 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 binder;
    }

    /** Method for clients. */
    public int getRandomNumber() {
      return mGenerator.nextInt(100);
    }
}

توفّر LocalBinder الطريقة getService() للعملاء لاسترداد المثيل الحالي لـ LocalService. يتيح ذلك للعملاء استدعاء الطرق العامة في خدمة ما. على سبيل المثال، يمكن للعملاء الاتصال بـ getRandomNumber() من الخدمة.

إليك نشاط مرتبط بـ "LocalService" ويتصل بـ getRandomNumber(). عند النقر على زر:

Kotlin

class BindingActivity : Activity() {
    private lateinit var mService: LocalService
    private var mBound: Boolean = false

    /** Defines callbacks for service binding, passed to bindService().  */
    private val connection = object : ServiceConnection {

        override fun onServiceConnected(className: ComponentName, service: IBinder) {
            // We've bound to LocalService, cast the IBinder and get LocalService instance.
            val binder = service as LocalService.LocalBinder
            mService = binder.getService()
            mBound = true
        }

        override fun onServiceDisconnected(arg0: ComponentName) {
            mBound = false
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.main)
    }

    override fun onStart() {
        super.onStart()
        // Bind to LocalService.
        Intent(this, LocalService::class.java).also { intent ->
            bindService(intent, connection, Context.BIND_AUTO_CREATE)
        }
    }

    override fun onStop() {
        super.onStop()
        unbindService(connection)
        mBound = false
    }

    /** Called when a button is clicked (the button in the layout file attaches to
     * this method with the android:onClick attribute).  */
    fun onButtonClick(v: View) {
        if (mBound) {
            // Call a method from the LocalService.
            // However, if this call is something that might hang, then put this request
            // in a separate thread to avoid slowing down the activity performance.
            val num: Int = mService.randomNumber
            Toast.makeText(this, "number: $num", Toast.LENGTH_SHORT).show()
        }
    }
}

Java

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, connection, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onStop() {
        super.onStop();
        unbindService(connection);
        mBound = false;
    }

    /** Called when a button is clicked (the button in the layout file attaches to
      * this method with the android:onClick attribute). */
    public void onButtonClick(View v) {
        if (mBound) {
            // Call a method from the LocalService.
            // However, if this call is something that might hang, then put this request
            // in a separate thread to avoid slowing down the activity performance.
            int num = mService.getRandomNumber();
            Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show();
        }
    }

    /** Defines callbacks for service binding, passed to bindService(). */
    private ServiceConnection connection = 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;
        }
    };
}

يوضح النموذج السابق كيفية ارتباط العميل بالخدمة باستخدام تطبيق ServiceConnection ومعاودة الاتصال onServiceConnected(). التالي مزيدًا من المعلومات حول عملية الربط بالخدمة.

ملاحظة: في المثال السابق، تشير تؤدي طريقة onStop() إلى إلغاء ربط العميل من الخدمة. إلغاء ربط العملاء بالخدمات في الأوقات المناسبة، كما تمت مناقشته في قسم ملاحظات إضافية.

لمزيد من المعلومات عن نموذج الرمز، يُرجى مراجعة LocalService.java و LocalServiceActivities.java الصف في ApiDemos.

استخدام Messenger

إذا كنت بحاجة إلى خدمة التواصل مع العمليات عن بُعد، يمكنك استخدام Messenger لتوفير واجهة للخدمة. يتيح هذا الأسلوب إذا كنت تجري اتصالًا بين العمليات (IPC) دون الحاجة إلى استخدام AIDL.

إنّ استخدام Messenger للواجهة هو أسهل من استخدام AIDL لأنّ Messenger قوائم انتظار جميع الاتصالات بالخدمة. ترسل واجهة AIDL البحتة طلبات متزامنة إلى التي ستتعامل بعد ذلك مع سلاسل المحادثات المتعددة.

بالنسبة إلى معظم التطبيقات، لا تحتاج الخدمة إلى إجراء سلاسل محادثات متعددة، لذا يتيح استخدام Messenger للخدمة التعامل مع استدعاء واحد في كل مرة. إذا كان من المهم أن تكون خدمتك ذات سلاسل متعددة، استخدِم AIDL لتحديد واجهتك.

إليك ملخص حول كيفية استخدام Messenger:

  1. تنفِّذ الخدمة Handler تتلقى معاودة اتصال لكل الاتصال من أحد العملاء.
  2. تستخدم الخدمة Handler لإنشاء Messenger. كائن (وهي إشارة إلى Handler).
  3. تنشئ Messenger السمة IBinder التي تستخدمها الخدمة. للعملاء من onBind().
  4. يستخدم العملاء IBinder لإنشاء مثيل للسمة Messenger (التي تشير إلى Handler للخدمة)، والذي يستخدمه العميل لإرسال يعترض Message على الخدمة.
  5. تتلقّى الخدمة كل Message في Handler، خاصةً في طريقة handleMessage().

بهذه الطريقة، لا تتوفّر طُرق يمكن للعميل من خلالها طلبها في الخدمة. بدلاً من ذلك، تسليم الرسائل (Message عنصر) بأنّ الخدمة استلام الكرة خلال Handler.

في ما يلي مثال بسيط على خدمة تستخدم واجهة Messenger:

Kotlin

/** Command to the service to display a message.  */
private const val MSG_SAY_HELLO = 1

class MessengerService : Service() {

    /**
     * Target we publish for clients to send messages to IncomingHandler.
     */
    private lateinit var mMessenger: Messenger

    /**
     * Handler of incoming messages from clients.
     */
    internal class IncomingHandler(
            context: Context,
            private val applicationContext: Context = context.applicationContext
    ) : Handler() {
        override fun handleMessage(msg: Message) {
            when (msg.what) {
                MSG_SAY_HELLO ->
                    Toast.makeText(applicationContext, "hello!", Toast.LENGTH_SHORT).show()
                else -> super.handleMessage(msg)
            }
        }
    }

    /**
     * When binding to the service, we return an interface to our messenger
     * for sending messages to the service.
     */
    override fun onBind(intent: Intent): IBinder? {
        Toast.makeText(applicationContext, "binding", Toast.LENGTH_SHORT).show()
        mMessenger = Messenger(IncomingHandler(this))
        return mMessenger.binder
    }
}

Java

public class MessengerService extends Service {
    /**
     * Command to the service to display a message.
     */
    static final int MSG_SAY_HELLO = 1;

    /**
     * Handler of incoming messages from clients.
     */
    static class IncomingHandler extends Handler {
        private Context applicationContext;

        IncomingHandler(Context context) {
            applicationContext = context.getApplicationContext();
        }

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_SAY_HELLO:
                    Toast.makeText(applicationContext, "hello!", Toast.LENGTH_SHORT).show();
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    }

    /**
     * Target we publish for clients to send messages to IncomingHandler.
     */
    Messenger mMessenger;

    /**
     * When binding to the service, we return an interface to our messenger
     * for sending messages to the service.
     */
    @Override
    public IBinder onBind(Intent intent) {
        Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show();
        mMessenger = new Messenger(new IncomingHandler(this));
        return mMessenger.getBinder();
    }
}

تُستخدم الطريقة handleMessage() في Handler هو المكان الذي تتلقّى الخدمة منه بيانات Message الواردة. ويقرّر ما يجب فعله بناءً على عضو what.

كل ما يحتاج إليه العميل هو إنشاء Messenger استنادًا إلى IBinder التي تعرضها الخدمة وإرسال رسالة باستخدام send(). على سبيل المثال، إليك نشاط يرتبط وتسليم الرسالة MSG_SAY_HELLO إلى الخدمة:

Kotlin

class ActivityMessenger : Activity() {
    /** Messenger for communicating with the service.  */
    private var mService: Messenger? = null

    /** Flag indicating whether we have called bind on the service.  */
    private var bound: Boolean = false

    /**
     * Class for interacting with the main interface of the service.
     */
    private val mConnection = object : ServiceConnection {

        override fun onServiceConnected(className: ComponentName, service: IBinder) {
            // This is called when the connection with the service has been
            // established, giving us the object we can use to
            // interact with the service.  We are communicating with the
            // service using a Messenger, so here we get a client-side
            // representation of that from the raw IBinder object.
            mService = Messenger(service)
            bound = true
        }

        override fun onServiceDisconnected(className: ComponentName) {
            // This is called when the connection with the service has been
            // unexpectedly disconnected—that is, its process crashed.
            mService = null
            bound = false
        }
    }

    fun sayHello(v: View) {
        if (!bound) return
        // Create and send a message to the service, using a supported 'what' value.
        val msg: Message = Message.obtain(null, MSG_SAY_HELLO, 0, 0)
        try {
            mService?.send(msg)
        } catch (e: RemoteException) {
            e.printStackTrace()
        }

    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.main)
    }

    override fun onStart() {
        super.onStart()
        // Bind to the service.
        Intent(this, MessengerService::class.java).also { intent ->
            bindService(intent, mConnection, Context.BIND_AUTO_CREATE)
        }
    }

    override fun onStop() {
        super.onStop()
        // Unbind from the service.
        if (bound) {
            unbindService(mConnection)
            bound = false
        }
    }
}

Java

public class ActivityMessenger extends Activity {
    /** Messenger for communicating with the service. */
    Messenger mService = null;

    /** Flag indicating whether we have called bind on the service. */
    boolean bound;

    /**
     * Class for interacting with the main interface of the service.
     */
    private ServiceConnection mConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className, IBinder service) {
            // This is called when the connection with the service has been
            // established, giving us the object we can use to
            // interact with the service.  We are communicating with the
            // service using a Messenger, so here we get a client-side
            // representation of that from the raw IBinder object.
            mService = new Messenger(service);
            bound = true;
        }

        public void onServiceDisconnected(ComponentName className) {
            // This is called when the connection with the service has been
            // unexpectedly disconnected—that is, its process crashed.
            mService = null;
            bound = false;
        }
    };

    public void sayHello(View v) {
        if (!bound) return;
        // Create and send a message to the service, using a supported 'what' value.
        Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0);
        try {
            mService.send(msg);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }

    @Override
    protected void onStart() {
        super.onStart();
        // Bind to the service.
        bindService(new Intent(this, MessengerService.class), mConnection,
            Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onStop() {
        super.onStop();
        // Unbind from the service.
        if (bound) {
            unbindService(mConnection);
            bound = false;
        }
    }
}

لا يوضّح هذا المثال طريقة استجابة الخدمة للعميل. إذا كنت ترغب في خدمة للرد، يجب أيضًا إنشاء Messenger في البرنامج. عندما يتلقّى العميل معاودة الاتصال "onServiceConnected()"، يرسل Message إلى الخدمة التي تتضمّن. Messenger للعميل في المعلمة replyTo من طريقة send().

يمكنك الاطّلاع على مثال على كيفية تقديم مراسلة ثنائية في MessengerService.java (الخدمة) و نماذج MessengerServiceActivities.java (للعميل).

الارتباط بخدمة

يمكن ربط مكونات التطبيق (العملاء) بخدمة من خلال استدعاء bindService() نظام التشغيل Android عندئذٍ يستدعي الطريقة onBind() للخدمة، والتي تعرض رمز IBinder للتفاعل مع الخدمة.

الربط غير متزامن، وتعرض bindService() فورًا بدون عرض IBinder إلى للعميل. لتلقّي "IBinder"، يجب أن ينشئ العميل مثيل لـ ServiceConnection وتمريره إلى bindService(). تتضمّن ServiceConnection طريقة معاودة الاتصال التي لإرسال طلبات النظام إلى IBinder.

ملاحظة: لا يمكن الربط إلا من خلال الأنشطة والخدمات وموفّري المحتوى. بإحدى الخدمات: لا يمكنك ربطها بخدمة من مستقبل بث.

للربط بخدمة من العميل، اتبع الخطوات التالية:

  1. تنفيذ ServiceConnection.

    يجب أن تلغي عملية التنفيذ طريقتَين لمعاودة الاتصال:

    onServiceConnected()
    يستدعي النظام هذه العملية لتسليم IBinder الذي تم إرجاعه عن طريق طريقة onBind() للخدمة.
    onServiceDisconnected()
    يستدعي نظام Android هذا عندما يكون الاتصال بالخدمة غير متوقع مثل عندما تتعطل الخدمة أو تتوقف عن العمل. هذا ليس يتم استدعاؤه عندما إلغاء ربط العميل.
  2. يمكنك الاتصال بالرقم bindService() واجتياز عملية تنفيذ ServiceConnection.

    ملاحظة: إذا كان ناتج الطريقة هو false، لا يتصل العميل بالخدمة. ومع ذلك، قم باستدعاء unbindService() في عميلك. وإلا، فسيحافظ عميلك على الخدمة من إيقاف التشغيل عندما يكون غير نشِط لفترة قصيرة.

  3. عندما يستدعي النظام طريقة معاودة الاتصال onServiceConnected()، يمكنك البدء في إجراء اتصالات بالخدمة، باستخدام الطرق التي تحددها الواجهة.
  4. لقطع الاتصال بالخدمة، اتصل بـ unbindService().

    إذا كان العميل لا يزال ملتزمًا بإحدى الخدمات عندما يؤدي تطبيقك إلى تدمير العميل، سيتم تدميره. إلى إلغاء ربط العميل. من الأفضل إلغاء ربط العميل بمجرد الانتهاء من ذلك التفاعل مع الخدمة. وسيؤدي ذلك إلى إيقاف تشغيل الخدمة غير النشِطة. لمزيد من المعلومات حول الأوقات المناسبة للربط وإلغاء الربط، راجع القسم ملاحظات إضافية.

يربط المثال التالي العميل بالخدمة التي تم إنشاؤها سابقًا من خلال تمديد فئة Binder، لذلك كل ما عليك فعله هو تحويل IBinder إلى الفئة LocalBinder وطلب المثيل LocalService:

Kotlin

var mService: LocalService

val mConnection = object : ServiceConnection {
    // Called when the connection with the service is established.
    override fun onServiceConnected(className: ComponentName, service: IBinder) {
        // Because we have bound to an explicit
        // service that is running in our own process, we can
        // cast its IBinder to a concrete class and directly access it.
        val binder = service as LocalService.LocalBinder
        mService = binder.getService()
        mBound = true
    }

    // Called when the connection with the service disconnects unexpectedly.
    override fun onServiceDisconnected(className: ComponentName) {
        Log.e(TAG, "onServiceDisconnected")
        mBound = false
    }
}

Java

LocalService mService;
private ServiceConnection mConnection = new ServiceConnection() {
    // Called when the connection with the service is established.
    public void onServiceConnected(ComponentName className, IBinder service) {
        // Because we have bound to an explicit
        // service that is running in our own process, we can
        // cast its IBinder to a concrete class and directly access it.
        LocalBinder binder = (LocalBinder) service;
        mService = binder.getService();
        mBound = true;
    }

    // Called when the connection with the service disconnects unexpectedly.
    public void onServiceDisconnected(ComponentName className) {
        Log.e(TAG, "onServiceDisconnected");
        mBound = false;
    }
};

باستخدام ServiceConnection، يمكن للعميل الربط بخدمة. بالمرور إلى bindService()، كما هو موضح في المثال التالي:

Kotlin

Intent(this, LocalService::class.java).also { intent ->
    bindService(intent, connection, Context.BIND_AUTO_CREATE)
}

Java

Intent intent = new Intent(this, LocalService.class);
bindService(intent, connection, Context.BIND_AUTO_CREATE);
  • المعلمة الأولى لـ bindService() هي Intent الذي يحدد الخدمة المطلوب ربطها بشكل صريح.

    تنبيه: إذا كنت تستخدم نية للربط Service، يُرجى التأكّد من أنّ تطبيقك آمن باستخدام محتوى فاضح. والنية. يعتبر استخدام نية ضمنية لبدء خدمة ما مخاطر أمنية بسبب عدم القدرة على التأكد من استجابة الخدمة لهدفها، ولا يمكن للمستخدم معرفة الخدمة التي بدأت. بدءًا من الإصدار 5.0 من نظام التشغيل Android (المستوى 21 لواجهة برمجة التطبيقات)، النظام تطرح استثناء إذا طلبت bindService() بهدف ضمني.

  • المعلمة الثانية هي الكائن ServiceConnection.
  • المعلمة الثالثة هي علامة تشير إلى خيارات الربط، وعادةً ما تكون BIND_AUTO_CREATE، لإنشاء الخدمة إذا لم تكن موجودة بالفعل حَيِي القيم الأخرى المحتملة هي BIND_DEBUG_UNBIND، BIND_NOT_FOREGROUND، أو 0 للتعبير عن القيمة بلا.

ملاحظات إضافية

في ما يلي بعض الملاحظات المهمة حول الربط بخدمة:

  • رصد استثناءات DeadObjectException التي يتم التخلص منها دائمًا عند انقطاع الاتصال. وهذا هو الاستثناء الوحيد الذي تحدثه الطرق البعيدة.
  • يتم احتساب العناصر كمراجع على مستوى العمليات.
  • عادةً ما تقوم بإقران الربط وإلغاء الربط أثناء لحظات مطابقة لحظات تأسيس وإنهاء دورة حياة العميل، كما هو موضح في في ما يلي الأمثلة:
    • إذا أردت التفاعل مع الخدمة فقط عندما يكون نشاطك مرئيًا، عليك الربط خلال onStart() وإلغاء الربط أثناء onStop().
    • إذا أردت أن يتلقى نشاطك ردودًا حتى أثناء توقفه في الخلفية والربط خلال onCreate() وإلغاء الربط خلال onDestroy(). احذر من أن هذا يعني أن أن أي نشاط يحتاج إلى استخدام الخدمة طوال مدة تشغيلها، حتى في الخلفية، ولذلك عندما كانت الخدمة في عملية أخرى، فستزيد من أهمية العملية من المرجح أن يقتلها النظام.

    ملاحظة: لا تربط عادةً البيانات وتفككها. أثناء عمليات استدعاء onResume() وonPause() لنشاطك، لأن عمليات الاسترداد هذه تحدث في الانتقال إلى دورة الحياة. حافظ على أقل قدر ممكن من المعالجة التي تحدث عند الانتقالات هذه.

    أيضًا، إذا ارتباط العديد من الأنشطة في التطبيق بنفس الخدمة وهناك انتقال بين اثنين من هذه الأنشطة، فقد يتم تدمير الخدمة وإعادة إنشائها باعتبارها عمليات إلغاء ربط الأنشطة (أثناء التوقف المؤقت) قبل الارتباط التالي (أثناء السيرة الذاتية). سيتغير هذا الانتقال في النشاط حول كيفية التي تنظِّم مراحل نشاطها في دورة حياة النشاط.

لمزيد من نموذج التعليمات البرمجية الذي يعرض كيفية الربط بخدمة، راجع صف واحد (RemoteService.java) في ApiDemos.

إدارة دورة حياة خدمة مرتبطة

عند إلغاء ربط خدمة من جميع العملاء، يتلفها نظام Android. (ما لم يتم بدء استخدام startService()). لذا، لا تضطر إلى إدارة دورة حياة خدمتك إذا خدمة مرتبطة حصرًا. ويديره نظام Android نيابةً عنك استنادًا إلى وما إذا كان ملتزمًا بأي عملاء.

ومع ذلك، إذا اخترت تنفيذ طريقة معاودة الاتصال onStartCommand()، يجب إيقاف الخدمة صراحةً بسبب تعتبر الخدمة الآن بدأت. في هذه الحالة، يتم تشغيل الخدمة حتى يتم تشغيل الخدمة يتوقف نفسه عن طريق stopSelf() أو استدعاء مكوِّن آخر لـ stopService()، بصرف النظر عما إذا كان مربوطًا بأي الدائمين.

بالإضافة إلى ذلك، إذا كانت الخدمة قد بدأت وتقبل الالتزام، فعند استدعاء النظام طريقة onUnbind()، يمكنك اختياريًا الرجوع true إذا كنت تريد تلقّي اتصال بـ onRebind() في المرة التالية التي يربط فيها العميل الخدمة. تُرجع الدالة onRebind() قيمة لاغية، ولكن لا يزال العميل يتلقّى IBinder ضمن معاودة الاتصال onServiceConnected(). يوضح الشكل التالي منطق هذا النوع من دورة الحياة.

الشكل 1. دورة حياة خدمة تم تشغيلها ويسمح أيضًا بالربط.

لمزيد من المعلومات عن دورة حياة الخدمة التي تم بدؤها، يُرجى الاطّلاع على نظرة عامة على الخدمات.