یک سرویس محدود، سروری است که در رابط مشتری-سرور قرار دارد. این اجازه می دهد تا اجزایی مانند فعالیت ها به سرویس متصل شوند، درخواست ها را ارسال کنند، پاسخ ها را دریافت کنند و ارتباطات بین فرآیندی (IPC) را انجام دهند. یک سرویس محدود معمولاً فقط زمانی زندگی می کند که جزء برنامه دیگری را ارائه می دهد و به طور نامحدود در پس زمینه اجرا نمی شود.
این سند نحوه ایجاد یک سرویس محدود، از جمله نحوه اتصال به سرویس از سایر اجزای برنامه را توضیح می دهد. برای اطلاعات بیشتر در مورد خدمات به طور کلی، مانند نحوه ارائه اعلانها از یک سرویس و تنظیم سرویس برای اجرا در پیشزمینه، به نمای کلی سرویسها مراجعه کنید.
اصول اولیه
یک سرویس محدود پیاده سازی کلاس Service
است که به برنامه های کاربردی دیگر اجازه می دهد به آن متصل شده و با آن تعامل داشته باشند. برای ارائه binding برای یک سرویس، شما متد onBind()
callback را پیاده سازی می کنید. این روش یک شی IBinder
را برمی گرداند که رابط برنامه نویسی را تعریف می کند که کلاینت ها می توانند از آن برای تعامل با سرویس استفاده کنند.
به یک سرویس شروع شده متصل شوید
همانطور که در نمای کلی سرویس ها بحث شد، می توانید سرویسی ایجاد کنید که هم شروع شده و هم محدود شده باشد. یعنی میتوانید با فراخوانی startService()
یک سرویس را راهاندازی کنید که به سرویس اجازه میدهد به طور نامحدود اجرا شود. همچنین می توانید با فراخوانی bindService()
به مشتری اجازه دهید به سرویس متصل شود.
اگر اجازه دهید سرویس شما راهاندازی و محدود شود، وقتی سرویس شروع میشود، وقتی همه کلاینتها باز میشوند، سیستم سرویس را از بین نمیبرد . درعوض، باید صراحتاً سرویس را با فراخوانی stopSelf()
یا stopService()
متوقف کنید.
اگرچه معمولاً onBind()
یا onStartCommand()
را پیاده سازی می کنید، گاهی اوقات لازم است هر دو را پیاده سازی کنید. به عنوان مثال، یک پخش کننده موسیقی ممکن است مفید باشد که سرویس خود را به طور نامحدود اجرا کند و همچنین اتصال را ارائه دهد. به این ترتیب، یک فعالیت میتواند سرویس را برای پخش موسیقی شروع کند و حتی اگر کاربر برنامه را ترک کند، موسیقی به پخش ادامه میدهد. سپس، هنگامی که کاربر به برنامه بازگشت، فعالیت می تواند به سرویس متصل شود تا کنترل پخش را دوباره به دست آورد.
برای اطلاعات بیشتر در مورد چرخه عمر سرویس هنگام افزودن اتصال به سرویس شروع شده، به بخش مدیریت چرخه عمر سرویس محدود مراجعه کنید.
یک کلاینت با فراخوانی bindService()
به یک سرویس متصل می شود. هنگامی که این کار را انجام می دهد، باید یک پیاده سازی از ServiceConnection
را ارائه دهد که اتصال با سرویس را نظارت می کند. مقدار برگشتی bindService()
نشان می دهد که آیا سرویس درخواستی وجود دارد یا خیر و آیا مشتری مجاز به دسترسی به آن است.
هنگامی که سیستم Android ارتباط بین سرویس گیرنده و سرویس ایجاد می کند، onServiceConnected()
در ServiceConnection
فراخوانی می کند. متد onServiceConnected()
شامل یک آرگومان IBinder
است که مشتری از آن برای برقراری ارتباط با سرویس محدود استفاده می کند.
می توانید چندین مشتری را به طور همزمان به یک سرویس متصل کنید. با این حال، سیستم کانال ارتباطی سرویس IBinder
را در حافظه پنهان نگه می دارد. به عبارت دیگر، سیستم onBind()
سرویس را فراخوانی میکند تا IBinder
تنها زمانی که اولین مشتری متصل میشود، تولید کند. سپس سیستم همان IBinder
به تمام کلاینت های اضافی که به همان سرویس متصل می شوند، بدون فراخوانی مجدد onBind()
تحویل می دهد.
هنگامی که آخرین سرویس گیرنده از سرویس جدا می شود، سیستم سرویس را از بین می برد، مگر اینکه سرویس با استفاده از startService()
راه اندازی شده باشد.
مهمترین بخش اجرای سرویس باند شما، تعریف رابطی است که متد callback onBind()
شما برمی گرداند. بخش زیر چندین روش را مورد بحث قرار می دهد که می توانید رابط IBinder
سرویس خود را تعریف کنید.
یک سرویس محدود ایجاد کنید
هنگام ایجاد سرویسی که اتصال را ارائه می دهد، باید یک IBinder
ارائه دهید که رابط برنامه نویسی را ارائه می دهد که مشتریان می توانند برای تعامل با سرویس از آن استفاده کنند. سه راه برای تعریف رابط وجود دارد:
- کلاس Binder را گسترش دهید
- اگر سرویس شما برای برنامه شخصی شما خصوصی است و در همان فرآیند مشتری اجرا می شود که معمول است، رابط خود را با گسترش کلاس
Binder
و برگرداندن نمونه ای از آن ازonBind()
ایجاد کنید. مشتریBinder
دریافت می کند و می تواند از آن برای دسترسی مستقیم به روش های عمومی موجود در اجرایBinder
یاService
استفاده کند.این روش ترجیحی است زمانی که سرویس شما صرفاً یک کارگر پس زمینه برای برنامه شخصی شما باشد. تنها مورد استفاده زمانی که این روش ترجیحی برای ایجاد رابط شما نیست، این است که سرویس شما توسط برنامه های کاربردی دیگر یا در فرآیندهای جداگانه استفاده شود.
- از مسنجر استفاده کنید
- اگر نیاز دارید که رابط شما در فرآیندهای مختلف کار کند، می توانید یک رابط برای سرویس با یک
Messenger
ایجاد کنید. به این ترتیب، سرویس یکHandler
را تعریف می کند که به انواع مختلف اشیاءMessage
پاسخ می دهد.این
Handler
مبنایی برای یکMessenger
است که سپس میتواند یکIBinder
با مشتری به اشتراک بگذارد و به مشتری اجازه میدهد با استفاده از اشیاءMessage
دستورات را به سرویس ارسال کند. علاوه بر این، مشتری میتواند یکMessenger
برای خود تعریف کند، بنابراین سرویس میتواند پیامها را بازگرداند.این سادهترین راه برای انجام ارتباطات بین پردازشی (IPC) است، زیرا
Messenger
تمام درخواستها را در یک رشته قرار میدهد تا مجبور نباشید سرویس خود را به گونهای طراحی کنید که ایمن باشد. - از AIDL استفاده کنید
- Android Interface Definition Language (AIDL) اشیاء را به موارد اولیه که سیستم عامل می تواند درک کند تجزیه می کند و آنها را در سراسر فرآیندها برای اجرای IPC به کار می گیرد. تکنیک قبلی، با استفاده از یک
Messenger
، در واقع بر اساس AIDL به عنوان ساختار زیربنایی آن است.همانطور که در بخش قبل ذکر شد،
Messenger
یک صف از تمام درخواست های مشتری در یک رشته ایجاد می کند، بنابراین سرویس درخواست ها را یک به یک دریافت می کند. با این حال، اگر می خواهید سرویس شما چندین درخواست را به طور همزمان انجام دهد، می توانید مستقیماً از AIDL استفاده کنید. در این حالت، سرویس شما باید ایمن باشد و قابلیت چند رشته ای را داشته باشد.برای استفاده مستقیم از AIDL، یک فایل
.aidl
ایجاد کنید که رابط برنامه نویسی را تعریف می کند. ابزار Android SDK از این فایل برای تولید یک کلاس انتزاعی استفاده میکند که رابط را پیادهسازی میکند و IPC را مدیریت میکند، سپس میتوانید آن را در سرویس خود گسترش دهید.
توجه: برای اکثر برنامهها، AIDL بهترین انتخاب برای ایجاد یک سرویس محدود نیست، زیرا ممکن است به قابلیتهای چند رشتهای نیاز داشته باشد و میتواند منجر به اجرای پیچیدهتر شود. بنابراین، این سند در مورد نحوه استفاده از آن برای خدمات شما صحبت نمی کند. اگر مطمئن هستید که باید مستقیماً از AIDL استفاده کنید، به سند AIDL مراجعه کنید.
کلاس Binder را گسترش دهید
اگر فقط برنامه محلی از سرویس شما استفاده می کند و نیازی به کار در بین فرآیندها ندارد، می توانید کلاس Binder
خود را پیاده سازی کنید که دسترسی مستقیم مشتری شما به روش های عمومی در سرویس را فراهم می کند.
توجه: این فقط در صورتی کار می کند که مشتری و سرویس در برنامه و فرآیند یکسانی باشند، که رایج ترین است. به عنوان مثال، این برای یک برنامه موسیقی که باید یک فعالیت را به سرویس خود که در حال پخش موسیقی در پسزمینه است متصل کند، به خوبی کار میکند.
در اینجا نحوه تنظیم آن آمده است:
- در سرویس خود، یک نمونه از
Binder
ایجاد کنید که یکی از موارد زیر را انجام دهد:- شامل روش های عمومی است که مشتری می تواند با آنها تماس بگیرد.
- نمونه
Service
فعلی را برمیگرداند، که دارای روشهای عمومی است که مشتری میتواند تماس بگیرد. - نمونهای از کلاس دیگری را که توسط سرویس میزبانی میشود با روشهای عمومی که کلاینت میتواند فراخوانی کند، برمیگرداند.
- این نمونه از
Binder
را از متدonBind()
callback برگردانید. - در کلاینت،
Binder
از متد callbackonServiceConnected()
دریافت کنید و با استفاده از روش های ارائه شده با سرویس محدود تماس بگیرید.
توجه: سرویس و کلاینت باید در یک برنامه باشند تا کلاینت بتواند شیء برگشتی را ارسال کند و APIهای آن را به درستی فراخوانی کند. سرویس و سرویس گیرنده نیز باید در یک فرآیند باشند، زیرا این تکنیک هیچ گونه مارشالسازی در بین فرآیندها را انجام نمیدهد.
به عنوان مثال، در اینجا یک سرویس است که دسترسی به روشهای موجود در سرویس را از طریق پیادهسازی Binder
به مشتریان ارائه میدهد:
کاتلین
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 } }
جاوا
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()
فرا می خواند:
کاتلین
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() } } }
جاوا
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
برای ارائه رابط برای سرویس خود استفاده کنید. این تکنیک به شما امکان می دهد ارتباطات بین فرآیندی (IPC) را بدون نیاز به استفاده از AIDL انجام دهید.
استفاده از Messenger
برای رابط کاربری سادهتر از استفاده از AIDL است زیرا Messenger
تمام تماسهای سرویس را در صف قرار میدهد. یک رابط AIDL خالص درخواستهای همزمان را به سرویس ارسال میکند، که سپس باید multithreading را مدیریت کند.
برای اکثر برنامهها، سرویس نیازی به انجام چند رشتهای ندارد، بنابراین استفاده از Messenger
به سرویس اجازه میدهد هر بار یک تماس را مدیریت کند. اگر مهم است که سرویس شما چند رشته ای باشد، از AIDL برای تعریف رابط خود استفاده کنید.
در اینجا خلاصه ای از نحوه استفاده از Messenger
آورده شده است:
- این سرویس یک
Handler
پیاده سازی می کند که به ازای هر تماس از یک مشتری یک تماس پاسخ دریافت می کند. - این سرویس از
Handler
برای ایجاد یک شیMessenger
(که اشاره ای بهHandler
است) استفاده می کند. -
Messenger
یکIBinder
ایجاد می کند که سرویس ازonBind()
به مشتریان برمی گرداند. - کلاینت ها از
IBinder
برای نمونه سازیMessenger
(که بهHandler
سرویس اشاره می کند) استفاده می کنند، که مشتری از آن برای ارسال اشیاءMessage
به سرویس استفاده می کند. - این سرویس هر
Message
درHandler
خود دریافت می کند — به طور خاص، در متدhandleMessage()
.
به این ترتیب هیچ روشی برای تماس مشتری با سرویس وجود ندارد. در عوض، سرویس گیرنده پیام هایی (اشیاء Message
) را که سرویس در Handler
خود دریافت می کند، ارائه می دهد.
در اینجا یک نمونه سرویس ساده است که از رابط Messenger
استفاده می کند:
کاتلین
/** 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 } }
جاوا
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
را به سرویس ارائه می دهد:
کاتلین
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 } } }
جاوا
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()
به یک سرویس متصل شوند. سپس سیستم اندروید متد onBind()
سرویس را فراخوانی میکند که یک IBinder
برای تعامل با سرویس برمیگرداند.
binding ناهمزمان است و bindService()
بلافاصله بدون برگرداندن IBinder
به مشتری بازمی گردد. برای دریافت IBinder
، مشتری باید یک نمونه از ServiceConnection
ایجاد کرده و آن را به bindService()
ارسال کند. ServiceConnection
شامل یک روش برگشت تماس است که سیستم برای تحویل IBinder
فراخوانی می کند.
توجه: فقط فعالیتها، خدمات و ارائهدهندگان محتوا میتوانند به یک سرویس متصل شوند—شما نمیتوانید از یک گیرنده پخش به سرویس متصل شوید.
برای اتصال به سرویس مشتری خود، این مراحل را دنبال کنید:
-
ServiceConnection
پیاده سازی کنید.پیاده سازی شما باید دو روش پاسخ به تماس را لغو کند:
-
onServiceConnected()
- سیستم این را برای تحویل
IBinder
بازگردانده شده توسط متدonBind()
سرویس فراخوانی می کند. -
onServiceDisconnected()
- سیستم اندروید زمانی که اتصال به سرویس به طور غیرمنتظره ای قطع می شود، مانند زمانی که سرویس از کار می افتد یا از بین می رود، این را فرا می خواند. وقتی کلاینت باز می شود این نام خوانده نمی شود.
-
- با عبور از اجرای
ServiceConnection
،bindService()
را فراخوانی کنید.توجه: اگر روش false را برگرداند، کلاینت شما اتصال معتبری به سرویس ندارد. با این حال،
unbindService()
در کلاینت خود فراخوانی کنید. در غیر این صورت، سرویس گیرنده شما از خاموش شدن سرویس در حالت بیکار جلوگیری می کند. - هنگامی که سیستم
onServiceConnected()
شما را فراخوانی میکند، میتوانید با استفاده از روشهای تعریفشده توسط رابط، شروع به برقراری تماس با سرویس کنید. - برای قطع ارتباط با سرویس،
unbindService()
را فراخوانی کنید.اگر زمانی که برنامه شما مشتری را از بین میبرد، کلاینت شما همچنان به یک سرویس متصل است، تخریب باعث میشود که کلاینت باز شود. عمل بهتری است که به محض انجام تعامل با سرویس، مشتری را باز کنید. انجام این کار باعث می شود سرویس بیکار خاموش شود. برای اطلاعات بیشتر در مورد زمانهای مناسب برای اتصال و باز کردن، به بخش یادداشتهای اضافی مراجعه کنید.
مثال زیر، سرویس گیرنده را با گسترش کلاس Binder به سرویس ایجاد شده قبلی متصل می کند، بنابراین تنها کاری که باید انجام دهد این است که IBinder
برگشتی را به کلاس LocalBinder
فرستاده و نمونه LocalService
درخواست کند:
کاتلین
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 } }
جاوا
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()
به یک سرویس متصل شود، همانطور که در مثال زیر نشان داده شده است:
کاتلین
Intent(this, LocalService::class.java).also { intent -> bindService(intent, connection, Context.BIND_AUTO_CREATE) }
جاوا
Intent intent = new Intent(this, LocalService.class); bindService(intent, connection, Context.BIND_AUTO_CREATE);
- اولین پارامتر
bindService()
یکIntent
است که صراحتاً نام سرویس را برای bind میدهد.احتیاط: اگر از intent برای اتصال به یک
Service
استفاده میکنید، با استفاده از یک هدف صریح مطمئن شوید که برنامه شما ایمن است. استفاده از یک قصد ضمنی برای شروع یک سرویس یک خطر امنیتی است زیرا نمی توانید مطمئن باشید که چه سرویسی به این هدف پاسخ می دهد و کاربر نمی تواند ببیند کدام سرویس شروع می شود. با شروع Android 5.0 (سطح API 21)، اگر شماbindService()
با یک هدف ضمنی فراخوانی کنید، سیستم یک استثنا ایجاد می کند. - پارامتر دوم شی
ServiceConnection
است. - سومین پارامتر پرچمی است که گزینههای مربوط به اتصال را نشان میدهد - معمولاً
BIND_AUTO_CREATE
، برای ایجاد سرویس در صورتی که از قبل فعال نیست. سایر مقادیر ممکن عبارتند ازBIND_DEBUG_UNBIND
،BIND_NOT_FOREGROUND
، یا0
برای هیچ کدام.
یادداشت های اضافی
در اینجا چند نکته مهم در مورد اتصال به یک سرویس آورده شده است:
- همیشه استثناهای
DeadObjectException
را به دام بیاندازید، که وقتی اتصال قطع می شود پرتاب می شوند. این تنها استثنایی است که توسط روش های راه دور ایجاد می شود. - اشیاء مرجع شمارش شده در فرآیندها هستند.
- همانطور که در مثالهای زیر توضیح داده شده است، معمولاً در طول زمانهای تطبیق بالا و پایینآمدن چرخه زندگی مشتری، اتصال و عدم اتصال را جفت میکنید:
- اگر نیاز به تعامل با سرویس دارید فقط زمانی که فعالیت شما قابل مشاهده است، در طول
onStart()
bind و در طولonStop()
unbind کنید. - اگر میخواهید فعالیت شما حتی زمانی که در پسزمینه متوقف شده است، پاسخها را دریافت کند، در طول
onCreate()
bind و در طولonDestroy()
unbind کنید. مراقب باشید که این بدان معناست که فعالیت شما نیاز به استفاده از سرویس در تمام مدت اجرا دارد، حتی در پسزمینه، بنابراین وقتی سرویس در فرآیند دیگری است، وزن فرآیند را افزایش میدهید و احتمال کشته شدن آن توسط سیستم
توجه: شما معمولاً در طول تماسهای
onResume()
وonPause()
فعالیت خود را باند و باز نمیکنید ، زیرا این تماسها در هر انتقال چرخه حیات رخ میدهند. پردازشی را که در این انتقال ها اتفاق می افتد به حداقل برسانید.همچنین، اگر چندین فعالیت در برنامه شما به یک سرویس متصل شود و بین دو مورد از آن فعالیتها انتقالی وجود داشته باشد، ممکن است سرویس از بین برود و دوباره ایجاد شود، زیرا فعالیت فعلی (در طول مکث) قبل از اتصال بعدی (در طول رزومه) باز میشود. این انتقال فعالیت برای اینکه چگونه فعالیت ها چرخه عمر خود را هماهنگ می کنند در چرخه حیات فعالیت توضیح داده شده است.
- اگر نیاز به تعامل با سرویس دارید فقط زمانی که فعالیت شما قابل مشاهده است، در طول
برای نمونه کد بیشتر که نحوه اتصال به یک سرویس را نشان می دهد، به کلاس RemoteService.java
در ApiDemos مراجعه کنید.
چرخه عمر یک سرویس محدود را مدیریت کنید
وقتی یک سرویس از همه کلاینتها جدا میشود، سیستم Android آن را از بین میبرد (مگر اینکه با استفاده از startService()
شروع شده باشد. بنابراین، لازم نیست چرخه عمر سرویس خود را اگر صرفاً یک سرویس محدود است مدیریت کنید. سیستم اندروید آن را بر اساس اینکه آیا به هر مشتری متصل است یا خیر، آن را برای شما مدیریت می کند.
با این حال، اگر متد onStartCommand()
را پیاده سازی کنید، باید صراحتاً سرویس را متوقف کنید، زیرا اکنون سرویس شروع شده در نظر گرفته می شود. در این مورد، سرویس تا زمانی اجرا میشود که سرویس با stopSelf()
متوقف شود یا مؤلفه دیگری stopService()
را فراخوانی کند، بدون توجه به اینکه آیا به هر کلاینت متصل است یا خیر.
علاوه بر این، اگر سرویس شما راه اندازی شده است و binding را می پذیرد، زمانی که سیستم متد onUnbind()
شما را فراخوانی می کند، اگر می خواهید دفعه بعد که کلاینت به سرویس متصل می شود، تماسی با onRebind()
دریافت کنید، می توانید به صورت اختیاری true
برگردانید. onRebind()
void برمی گرداند، اما مشتری همچنان IBinder
در پاسخ به تماس onServiceConnected()
خود دریافت می کند. شکل زیر منطق این نوع چرخه حیات را نشان می دهد.
برای اطلاعات بیشتر در مورد چرخه عمر سرویس شروع شده، به نمای کلی خدمات مراجعه کنید.