service سرویس در اندروید

سرویس یا Service در اندروید – توضیح کامل + پروژه

یکی از کامپوننت های اپلیکیشن در اندروید، سرویس ها هستند. شما به عنوان کسی که قصد ساخت اپلیکیشن های اندروید را دارد، باید با همه کامپوننت های اصلی اپلیکیشن اندروید آشنا شوید. در این مقاله از برنامه چی میخواهیم یک راهنمای کامل برای Service ها در اندروید ارائه بدهیم. با ما همراه باشید.

سرویس service در اندروید

در این نوشته درباره سرویس ها در اندروید، مفهوم آنها، انواع متخلف Service ها و مثال هایی کاربردی از آنها صحبت کردیم. در حقیقت سرویس یک کامپوننت اپلیکیشن است که میتواند نرم افزار ما را در پس زمینه زنده نگه دارد. لیست تیتر ها را میتوانید در باکس زیر مشاهده کنید.


سرویس یا Service چیست؟

سرویس ها در اندروید یکی از کامپوننت های مخصوص هستند که میتوانند کاری کنند اپلیکیشن در پس زمینه اجرا شود تا تسک های طولانی مدت را اجرا کند. پس هدف اصلی Service این است که اپلیکیشن در پس زمینه فعال بماند. با این کار، کاربر میتواند از خدمات چندین اپلیکیشن بصورت همزمان استفاده کند. بخاطر اینکه سرویس ها برای انجام تسک های طولانی و بدون احتیاج به تعامل با کاربر استفاده میشوند، نیازی به ساخت رابط کاربری برای آنها نداریم.

یک سرویس میتواند در پس زمینه ادامه داشته باشد حتی اگر نرم افزار بسته شود یا کاربر به یک اپلیکیشن دیگر رفته باشد. علاوه بر اینها، کامپوننت های اپلیکیشن میتوانند به سرویس ها Bind شوند تا ارتباطات میان پردازشی (IPC) را با استفاده از آنها انجام بدهند.

نکته ای که باید به آن توجه داشته باشید، این است که یک تفاوت اصلی بین Service و Thread در اندروید وجود دارد که نباید آنها را باهم اشتباه بگیرید. Thread یکی از قابلیت هایی است که توسط سیستم عامل ارائه میشود و به کاربر اجازه میدهد که عملیات هایی را در پس زمینه انجام بدهد. اما سرویس یکی از کامپوننت های اپلیکشن است که میتواند تسک های طولانی را بدون داشتن UI انجام بدهد.

سرویس اندروید چیست

یک سرویس روی نخ اصلی پردازشی که درون آن قرار دارد اجرا میشود. یعنی Service نخ روی یک نخ جداگانه یا روی یک Process دیگر اجرا نمیشود، مگر اینکه برنامه نویس این روند را تغییر بدهد. بنابراین در هنگام کار با Service ها، باید هر عملیات مسدود کننده را روی یک نخ جداگانه انجام بدهید که باعث خطای Application Not Responding (ANR) نشوید.

سرویس ها دارای اولویت بالاتری نسبت به اکتیویتی یا فرگمنت غیرفعال هستند. به همین دلیل سیستم عامل اندروید تمایل زیادی به از بین بردن آنها ندارد. همچنین میتوانید Service را طوری تنظیم کنید که در صورت از بین رفتن، هروقت منابع کافی در سیستم وجود داشت، دوباره راه اندازی شود.

حتی سرویس در سیستم عامل اندروید میتواند به اندازه یک اکتیویتی که کاربر در حال تعامل با آن است، اولویت داشته باشد. اگر میخواهیم این اتفاق بیفتد، باید یک اعلان (Notification) فعال برای Service مورد نظر بسازیم. این کار معمولا برای سرویس هایی که ویدئو یا موسیقی پخش میکنند انجام میشود.


انتخاب بین Service و Thread

سرویس بصورت ساده یکی از کامپوننت های اپلیکیشن است که در پس زمینه اجرا میشود، حتی اگر کاربر با آن تعامل نداشته باشد. پس فقط باید زمانی از آن استفاده کنید که به همچین سناریویی نیاز داشته باشید. اما اگر باید یک سری کارها را در جایی خارج از Thread اصلی اپلیکیشن انجام بدهید، آن هم وقتی که کاربر در حال تعامل با اپلیکیشن است، بهتر است که یک نخ جدید در Context یک کامپوننت دیگر از اپلیکیشن ایجاد کنید.

thread و service

به عنوان مثال، اگر میخواهید یک موسیقی فقط در زمانی که اپلیکیشن در حال اجرا است پخش شود بهتر است که یک Thread جدید در مرحله onCreate بسازید، آن را در onStart اجرا کرده و در onStop متوقفش کنید. همچنین میتوانید از Thread Pool یا Kotlin Coroutines برای انجام تسک ها در پس زمینه استفاده کنید.

هشدار: این نکته را فراموش نکنید که اگر از Service استفاده میکنید، این کامپوننت روی نخ اصلی اپلیکیشن اجرا میشود. پس اگر قرار است کاری انجام بدهید که Thread اصلی اپ را مسدود میکند، باید یک نخ جدید درون سرویس بسازید.


سرویس های پلتفرمی و سرویس های Custom

سرویس های پلتفرمی اندروید

سیستم عامل اندروید تعدادی سرویس از پیش آماده شده درون خود دارد که همه اپلیکیشن ها، با داشتن مجوز های درست، میتوانند از این Service ها استفاده کنند. این سرویس های پلتفرمی معمولا از طریق کلاس های Manager مخصوص خودشان قابل دسترسی هستند. این دسترسی را میتوانیم با صدا زدن متد getSystemService() به دست بیاوریم. سپس میتوانیم از ثابت های مختلفی که در کلاس Context وجود دارد، نحوه ایجاد این دسترسی ها را کنترل کنیم.

علاوه بر استفاده از Service های مخصوص سیستم عامل اندروید، اپلیکیشن ها نیز میتوانند سرویس های شخصی سازی شده برای خودشان تولید کرده و اجرا کنند. ساخت سرویس های سفارشی به شما امکان میدهد که اپلیکیشن های منعطف تری تولید کنید. درباره کاربرد این سرویس ها و نحوه ساخت آنها در اپلیکیشن اندروید در همین مقاله بصورت کامل توضیح خواهیم داد.


انواع مختلف Service در اندروید

انواع سرویس ها در اندروید

سه نوع مختلف سرویس در اندروید وجود دارد که با همه آنها آشنا میشویم:


Foreground Service

سرویس هایی که کاربر را در جریان عملیاتی که در حال انجام آن است قرار میدهد، به عنوان سرویس Foreground شناخته میشود. کاربر میتواند از طریق ناتیفیکیشن این سرویس، با آن تعامل داشته باشد. مثلا در عملیات دانلود فایل، کاربر میتواند مقدار دانلود فایل را در اعلان سرویس مشاهده کند و حتی آن را Pause یا Stop کند.

یعنی وقتی که میخواهیم از سرویس Foreground استفاده کنیم، باید یک ناتیفیکیشن نمایش بدهیم. این ناتیفیکیشن قابل حذف کردن نیست، مگر اینکه سرویس متوقف شود یا از حالت Foreground بیرون برود.


Background Service

سرویس های Background نیازی به تعامل با کاربر ندارند. این سرویس ها کاربر را در جریان کارهایی که در پس زمینه انجام میشود قرار نمیدهند و کاربر نمیتواند به آنها دسترسی داشته باشد. تسک هایی مانند Sync کردن یا ذخیره کردن داده ها در این Service ها انجام میشوند.


Bound Service

این نوع از سرویس ها در سیستم عامل اندروید به کامپوننت های اپلیکیشن (مثلا اکتیویتی) اجازه میدهند که خودشان را به آن Bound یا متصل کنند. سرویس های Bound تا زمانی به زندگی ادامه میدهند که یک کامپوننت به آنها متصل باشد. حتی بیشتر از یک کامپوننت هم میتوانند بصورت همزمان به یک Service متصل شوند. برای متصل کردن یک کامپوننت به سرویس، از متد bindService استفاده میشود.


چرخه عمر سرویس در اندروید

در اندروید، Service ها دو راه برای تکمیل کردن چرخه عمر خودشان دارند که با نام های Started و Bounded شناخته میشوند.


سرویس های Started (Unbounded)

اگر این مسیر را برای اجرای سرویس انتخاب کنیم، Service با فراخوانی متد startService در یکی از کامپوننت های اپلیکیشن چرخه عمر خود را شروع میکند. وقتی که اجرا شد، سرویس در پس زمینه به کارهای خودش ادامه میدهد حتی اگر کامپوننت شروع کننده سرویس از بین رفته باشد. در این مسیر برای توقف سرویس دو گزینه وجود دارد:

  1. صدا زدن متد stopService
  2. سرویس میتواند خودش را با صدا زدن متد stopSelf متوقف کند

سرویس های Bounded

این سرویس میتواند به عنوان یک سرور در رابطه کلاینت-سرور در نظر گرفته بشود. با در نظر گرفتن همین الگو، کامپوننت های یک اپلیکیشن اندروید میتوانند به Service درخواست هایی ارسال کرده و پاسخ دریافت کنند. یک سرویس زمانی بصورت Bounded شناخته میشود که یک کامپوننت با استفاده از متد bindService به آن متصل شده باشد. برای متوقف کردن این مدل سرویس، همه کامپوننت ها باید خودشان را از این سرویس Unbind کنند. این کار با استفاده از متد unbindService انجام میشود.

چرخه عمر سرویس ها در اندروید service lifecycle android

برای انجام یک عمل دانلود در پس زمینه اپلیکیشن، متد startService فراخوانی میشود. برای اینکه اطلاعات مربوط به پیشرفت دانلود دریافت شود و همچنین بتوانیم آن را متوقف کنیم یا ادامه بدهیم در حالی که اپلیکیشن همچنان در پس زمینه در حال اجراست، یک کامپوننت باید به آن متصل شده باشد که بتواند این کار ها را انجام بدهد.


مبانی سرویس در اندروید

برنامه نویس میتواند یک سرویس را با استفاده از یک کلاس معمولی و Extend کردن کلاس Service بسازد. بعد از این کار، برای اینکه بتوانیم عملیات های مربوط به Service را انجام بدهیم، تعدادی متد Callback وجود دارند که باید Override بشوند. در جدول زیر متدهای مهم سرویس ها در اندروید را مشاهده میکنید.

نام متدتوضیحات
متد onStartCommandوقتی یکی از کامپوننت های اپلیکیشن با استفاده از متد startService یک سرویس را شروع میکند، این متد در سرویس اجرا خواهد شد. وقتی که Service شروع به کار کرد، میتواند با فراخوانی متد های stopService (از یک کامپوننت اپلیکیشن) و stopSelf (از داخل خود سرویس) متوقف بشود.
متد onBindاین متد در پیاده سازی سرویس ضروری است و هر وقت یکی از کامپوننت های اپلیکیشن با استفاده از متد bindService بخواهد به این Service متصل شود، فراخوانی میشود. اگر نیازی به Bind شدن در سرویس وجود نداشت، این متد باید مقدار null را برگرداند.
متد onUnbindسیستم عامل اندروید وقتی که همه کلاینت ها از سرویس قطع شده باشند، این متد را فراخوانی میکند.
متد onRebindوقتی که همه کلاینت ها از سرویس قطع شده باشند و نیاز باشد کلاینت های جدیدی به سرویس متصل شوند، این متد صدا زده میشود.
متد onCreateهر وقت که یک Service با استفاده از متد های onStartCommand یا onBind ساخته شود، سیستم عامل اندروید این متد را صدا میزند. این متد برای انجام کارهایی که نیاز است فقط یکبار باید انجام شوند مناسب است.
متد onDestroyوقتی که از یک سرویس دیگر استفاده نمیشود، سیستم عامل این متد را صدا میزند. این متد دقیقا یک مرحله قبل از نابودی کامل Service است و باید پاکسازی های نهایی را در این قسمت انجام بدهیم. سرویس ها باید این متد را برای پاکسازی Listener ها، نخ ها، Receiver ها و بقیه منابعی که ممکن است باعث Memory Leak شوند، پیاده سازی کند.

نحوه ساخت سرویس در اندروید

همانطور که گفتیم دو مدل سرویس در اندروید وجود دارد. در این قسمت میخواهیم روش ساخت هر دو مدل این سرویس ها در اندروید را با هم بررسی کنیم.


ساخت یک سرویس Started – روش اول

یک کامپوننت اپلیکیشن مانند اکتیویتی، میتواند با صدا زدن متد startService() و پاس دادن یک آبجکت از Intent که سرویس مورد نظر را تعریف میکند و شامل همه داده هایی است که Service قرار است از آنها استفاده کند. سرویس Intent را درون متد onStartCommand خودش دریافت میکند.

android started service

برای مثال فرض کنید یک اکتیویتی نیاز دارد مقداری از داده ها را درون یک دیتابیس آنلاین ذخیره کند. اکتیویتی میتواند یک Service را اندازی کند که کار ذخیره سازی را انجام میدهد و اطلاعات مورد نیاز را به همراه یک Intent به متد startService() پاس بدهد. سرویس این اطلاعات را درون متد onStartCommand() خودش دریافت کند. سپس به اینترنت متصل میشود و تراکنش را روی پایگاه داده انجام میدهد. وقتی که تراکنش کامل شد، سرویس خودش را متوقف میکند و از بین میبرد.

کلاس Service، کلاس پایه برای همه سرویس ها است. وقتی که این کلاس را Extend میکنید، کار مهمی که باید انجام بدهید این است که یک Thread جدید بسازید تا سرویس بتواند کارهای خودش را درون آن کامل کند. همانطور که گفته شد سرویس بصورت پیشفرض روی نخ اصلی اپلیکیشن اجرا میشود. این مسئله باعث کند شدن همه اکتیویتی هایی میشود که درون اپلیکیشن شما اجرا میشوند.

نکته: در بخش های بعدی درباره اینکه چگونه میتوانید یک سرویس را در اپلیکیشن خودتان بسازید صحبت کردیم. اما حتما پیشنهاد میکنم استفاده از WorkManager را برای بسیاری از سناریو ها در نظر داشته باشید. میتوانید درباره پردازش پس زمینه در اپلیکیشن های اندروید جستجو کنید تا راه حل های مناسب خودتان را پیدا کنید.


گام اول: Extend کردن کلاس Service

باید برای مدیریت Intent های ورودی، کلاس Service را Extend کنیم. پیاده سازی این کلاس را در تکه کد زیر میتوانید مشاهده کنید:

public class HelloService extends Service {
  private Looper serviceLooper;
  private ServiceHandler serviceHandler;

  // Handler that receives messages from the thread
  private final class ServiceHandler extends Handler {
      public ServiceHandler(Looper looper) {
          super(looper);
      }
      @Override
      public void handleMessage(Message msg) {
          // Normally we would do some work here, like download a file.
          // For our sample, we just sleep for 5 seconds.
          try {
              Thread.sleep(5000);
          } catch (InterruptedException e) {
              // Restore interrupt status.
              Thread.currentThread().interrupt();
          }
          // Stop the service using the startId, so that we don't stop
          // the service in the middle of handling another job
          stopSelf(msg.arg1);
      }
  }

  @Override
  public void onCreate() {
    // Start up the thread running the service. Note that we create a
    // separate thread because the service normally runs in the process's
    // main thread, which we don't want to block. We also make it
    // background priority so CPU-intensive work doesn't disrupt our UI.
    HandlerThread thread = new HandlerThread("ServiceStartArguments",
            Process.THREAD_PRIORITY_BACKGROUND);
    thread.start();

    // Get the HandlerThread's Looper and use it for our Handler
    serviceLooper = thread.getLooper();
    serviceHandler = new ServiceHandler(serviceLooper);
  }

  @Override
  public int onStartCommand(Intent intent, int flags, int startId) {
      Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();

      // For each start request, send a message to start a job and deliver the
      // start ID so we know which request we're stopping when we finish the job
      Message msg = serviceHandler.obtainMessage();
      msg.arg1 = startId;
      serviceHandler.sendMessage(msg);

      // If we get killed, after returning from here, restart
      return START_STICKY;
  }

  @Override
  public IBinder onBind(Intent intent) {
      // We don't provide binding, so return null
      return null;
  }

  @Override
  public void onDestroy() {
    Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
  }
}

به کدهای بالا دقت کنید. این کدها همه Intent های ورودی را درون متد onStartCommand مدیریت میکند و کارها را به یک Handler ارسال میکند که روی یک Thread در پس زمینه اجرا میشود. این مثال مانند IntentService کار میکند و همه کار ها را بصورت سریالی یعنی یکی یکی و پشت سر هم انجام میدهد.

این نکته را فراموش نکنید که متد onStartCommand باید یک مقدار integer را برگرداند. این مقدار integer مشخص میکند که سیستم چطور باید بعد از متوقف کردن سرویس، با آن رفتار کند. مقدار برگشتی از onStartCommand باید یکی از مقادیر ثابت زیر باشد:


START_NOT_STICKY

اگر سیستم سرویس را بعد از اجرا شدن onStartCommand متوقف کند، سرویس دوباره ساخته نمیشود مگر اینکه Intent دیگری برای ارسال شدن به سرویس وجود نداشته باشد. این گزینه ایمن ترین راه برای جلوگیری از اجرای سرویس وقتی که نیازی به آن نیست میباشد. همچنین برای مواقعی که اپلیکیشن میتواند یک کار ناتمام را دوباره از اول شروع کند.


START_STICKY

اگر سیستم سرویس را بعد از اجرا شدن onStartCommand متوقف کند، سرویس دوباره ساخته میشود و متد onStartCommand فراخوانی خواهد شد. اما آخرین Intent دوباره برای آن ارسال نمیشود. به جای این کار، سیستم یک Intent با مقدار null برای سرویس ارسال میکند (مگر این که Intent های دیگری درون صف برای ارسال شدن وجود داشته باشند). در این سناریو، Intent هایی که درون صف هستند ارسال خواهند شد. این گزینه برای سرویس هایی که فایل چند رسانه ای پخش میکنند مناسب هستند (یا سرویس هایی که کار مشابه دارند). یعنی Service هایی که دستور خاصی اجرا نمیکنند، بلکه بصورت نامحدود اجرا میشوند و منتظر یک تسک جدید می مانند.


START_REDELIVER_INTENT

اگر سیستم سرویس را بعد از اجرا شدن onStartCommand متوقف کند، سرویس دوباره ساخته میشود و متد onStartCommand اجرا شده و آخرین Intent که به آن ارسال شده بود، دوباره به آن فرستاده میشود. Intent هایی که درون صف باشند هم به ترتیب بعد از آن ارسال میشوند. این گزینه برای Service هایی که همیشه در حال انجام کارهای متفاوت هستند و باید بلافاصله ادامه پیدا کنند مناسب است، مانند دانلود کردن یک فایل.


گام دوم: Start کردن سرویس

برای استارت کردن یک سرویس میتوانید متد های startService() یا startForegroundService() را از درون یکی از کامپوننت های اپلیکیشن صدا بزنیم و یک آبجکت Intent به آن پاس بدهیم. در این صورت سیستم عامل اندروید متد onStartCommand از سرویس مورد نظر را صدا میزند و آبجکت Intent، که مشخص میکند کدام سرویس باید اجرا شود، را به آن میدهد.

نکته: اگر اپلیکیشن روی API 26 یا بالاتر قرار است اجرا شود، سیستم اجرای Background Service ها را به این محدود میکند که اپلیکیشن روی Foreground در حال اجرا باشد (یعنی کاربر درحال تعامل با اپلیکیشن باشد). اگر اپلیکیشن نیاز به ساخت یک Foreground Service داشت، باید متد startForegroundService را فراخوانی کند. این متد یک سرویس بک گراند را استارت میزند اما به سیستم سیگنال میدهد که سرویس قرار است در Foreground باقی بماند. یعنی وقتی که سرویس ساخته شد، 5 ثانیه فرصت دارد تا متد startForeground را درون خودش صدا بزند.

به عنوان مثال، یک اکتیویتی میتواند سرویس مثال زده شده در قسمت قبل (HelloService) را با استفاده از یک Intent صریح مانند تکه کدهای زیر، اجرا کند.

Intent intent = new Intent(this, HelloService.class);
startService(intent);

به کدهای بالا دقت کنید، متد startService() بلافاصله اجرا میشود و سیستم عامل اندروید، متد onStartCommand سرویس را فراخوانی میکند. اگر Service از قبل در حال اجرا نباشد، اول onCreate() آن اجرا میشود و بعد متد onStartCommand فراخوانی خواهد شد.

نکته: اگر سرویس از عملیات Binding پشتیبانی نکند، آبجکت Intent که برای آن فرستاده شد، تنها راه ارتباطی بین کامپوننت و Service مورد نظر میباشد.


گام سوم: اضافه کردن سرویس در فایل Manifest.xml

برای اینکه سرویس ما بتواند روی دستگاه اجرا شود، باید آن را درون فایل Manifest.xml اپلیکیشن خودمان تعریف کنیم. اگر سرویسی ساخته باشیم که درون این فایل تعریف نشده باشد، نمیتواند هیچکدام از کارهای خودش را انجام بدهد. برای تعریف Service باید آن را در تگ <application> قرار بدهیم. کدهای زیر را مشاهده کنید:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
	package="com.example.services_in_android">

	<application
		android:allowBackup="true"
		android:icon="@mipmap/ic_launcher"
		android:label="@string/app_name"
		android:supportsRtl="true"
		android:theme="@style/AppTheme">
		<activity android:name=".MainActivity">
			<intent-filter>
				<action android:name="android.intent.action.MAIN" />
				<category android:name="android.intent.category.LAUNCHER" />
			</intent-filter>
		</activity>
		
		<!-- Mention the service name here -->
		<service android:name=".HelloService"/>
		
	</application>

</manifest>


گام چهارم: متوقف کردن Service

وقتی یک Service در حال اجرا است، باید مراحل چرخه عمر خودش را مدیریت کند. سیستم عامل هم تا زمانی که نیاز به حافظه نداشته باشد، سرویس را متوقف نمیکند. پس اجرای آن بعد از فراخوانی onStartCommand همیشه ادامه خواهد داشت. بنابراین سرویس باید خودش را با صدا زدن متد stopSelf() متوقف کند، یا اینکه یکی از کامپوننت های دیگر میتواند متد stopService() را برای از بین بردن سرویس صدا بزند. وقتی که یکی از این متد ها برای متوقف کردن Service فراخوانی شوند، سیستم در سریع ترین زمان ممکن سرویس را از بین خواهد برد.

هشدار: برای جلوگیری از هدر رفتن منابع سیستم و شارژ باتری دستگاه، مطمئن شوید اپلیکیشن بعد از اینکه کارهایش تمام شد، سرویس را هم از بین ببرد. همانطور که گفته شد بقیه کامپوننت ها هم میتوانند این کار را انجام بدهند. حتی اگر Binding را برای سرویس فعال کرده باشید، همیشه باید وقتی که onStartCommand() صدا زده میشود یکبار Service را متوقف کنید.


ساخت یک سرویس Started – روش دوم

یک راه دیگر برای ساخت Started Service وجود دارد. این روش از روش قبلی آسان تر میباشد و بیشتر کار ها بصورت خودکار توسط اندروید استودیو انجام خواهد شد. برای استفاده از این راه، گام های زیر را دنبال کنید.


گام اول: کلیک راست روی نام پکیج

بعد از این که پروژه خودمان را در اندروید استودیو ساختیم، روی نام پکیجی که میخواهیم سرویس ما درون آن ساخته شود راست کلیک میکنیم. سپس از منوی New، گزینه Service را انتخاب میکنیم.

گام اول ساخت سرویس در اندروید

گام دوم: انتخاب نام سرویس

در پنجره ای که باز شده باید نام سرویس را انتخاب کنیم و گزینه Finish را بزنیم. بعد از این کار سرویس ما ساخته میشود و بصورت اتوماتیک به فایل Manifest هم معرفی خواهد شد.

گام دوم ساخت سرویس در اندروید

ساخت یک سرویس Bounded

این مدل سرویس به کامپوننت های اپلیکیشن اجازه میدهد با صدا زدن متد bindService به آن متصل شوند و یک ارتباط طولانی مدت از این طریق شکل میگیرد. شما نمیتوانید این مدل Service را با متد startService() اجرا کنید.

اگر میخواهید از طریق اکتیویتی ها یا دیگر کامپوننت های اپلیکیشن با سرویس ارتباط برقرار کنید یا بعضی از کاربرد های اپلیکیشن خودتان را از طریق ارتباطات بین پردازشی (IPC) در اختیار دیگر اپلیکیشن ها قرار بدهید، میتوانید از Bounded Service ها استفاده کنید.

برای ساخت این سرویس باید متد onBind() را پیاده سازی کنیم که یک آبجکت از IBinder را برمیگرداند. این آبجکت یک اینترفیس برای ارتباط با سرویس است. یعنی بقیه کامپوننت ها وقتی متد bindService() را صدا میزنند، این اینترفیس را دریافت میکنند و میتوانند از طریق آن متدهای سرویس را فراخوانی کنند. سرویس فقط برای خدمت رسانی به کامپوننت هایی که به آن متصل هستند، زنده میماند. بنابراین وقتی که کامپوننتی به آن متصل نباشد، توسط سیستم عامل از بین میرود و نیازی نیست خودتان سرویس را متوقف کنید.

bounded service اندروید

برای ساخت یک Bound Service، ابتدا باید یک اینترفیس تعریف کنیم که نحوه ارتباط با سرویس را مشخص کند. این اینترفیس رابطه بین Service و کلاینت را مشخص میکند و باید اینترفیس IBinder را هم implement کرده باشد. سپس سرویس یک آبجکت از این اینترفیس را به عنوان مقدار برگشتی متد onBind() ارسال میکند. بعد از اینکه کلاینت IBinder را دریافت کرد، میتواند ارتباط با سرویس را از طریق این اینترفیس شروع کند.

نکته: چندین کلاینت میتوانند بصورت همزمان به یک سرویس متصل بشوند. وقتی که یک کلاینت کارهایش با سرویس تمام شد، با صدا زدن متد unbindService()، از آن جدا میشود. زمانی هم که هیچ کلاینت دیگری برای سرویس باقی نماند، سیستم سرویس را تخریب میکند.

ساخت Bound Service پیچیدگی های بیشتری نسبت به مدل معمولی سرویس ها دارد. به همین دلیل در یک مقاله جداگانه بصورت کامل روش ساخت این مدل را بررسی خواهیم کرد (به زودی).


پروژه: پخش موسیقی در پس زمینه

به عنوان بخش پایانی و برای اینکه با پیاده سازی Service ها در اپلیکیشن اندروید بیشتر آشنا شوید، یک پروژه کوچک را با هم پیاده سازی میکنیم.

پخش موسیقی در پس زمینه، یکی از رایج ترین مثال ها در اندروید است. از زمانی که کاربر سرویس را استارت میکند، موسیقی باید ادامه داشته باشد. حتی اگر کاربر به یک اپلیکیشن دیگر برود. کاربر برای متوقف کردن پخش موسیقی، باید سرویس را متوقف کند. در ادامه همه گام های پیاده سازی این پروژه را با هم میبینیم.


گام اول: ساخت یک پروژه جدید

بعد از اینکه پروژه ما در اندروید استودیو ساخته شد، کارهای زیر را به ترتیب انجام بدهید:

  1. روی File کلیک کنید، از منوی New، گزینه New Project را انتخاب کنید.
  2. گزینه Empty Activity را انتخاب کنید.
  3. زبان را روی Java/Kotlin قرار بدهید.
  4. مقدار Minimum SDK را هر طور که میخواهید تنظیم کنید.

گام دوم: فایل strings.xml را ویرایش کنید

همه رشته های متنی که در نرم افزار استفاده شده اند، داخل این فایل قرار دارند.

<resources>
	<string name="app_name">Services_In_Android</string>
	<string name="heading">Services In Android</string>
	<string name="startButtonText">Start the Service</string>
	<string name="stopButtonText">Stop the Service</string>
</resources>

گام سوم: کار با فایل activity_main.xml

داخل این فایل دو Button اضافه میکنیم که مسئول شروع و متوقف کردن سرویس هستند. در کد های زیر میتوانید روش پیاده سازی این دکمه ها را در این فایل ببینید.

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
	xmlns:android="http://schemas.android.com/apk/res/android"
	xmlns:app="http://schemas.android.com/apk/res-auto"
	xmlns:tools="http://schemas.android.com/tools"
	android:layout_width="match_parent"
	android:layout_height="match_parent"
	android:background="#168BC34A"
	tools:context=".MainActivity">

	<LinearLayout
		android:id="@+id/linearLayout"
		android:layout_width="match_parent"
		android:layout_height="wrap_content"
		android:layout_centerVertical="true"
		android:orientation="vertical"
		app:layout_constraintBottom_toBottomOf="parent"
		app:layout_constraintEnd_toEndOf="parent"
		app:layout_constraintStart_toStartOf="parent"
		app:layout_constraintTop_toTopOf="parent"
		app:layout_constraintVertical_bias="1.0"
		tools:ignore="MissingConstraints">

		<TextView
			android:id="@+id/textView1"
			android:layout_width="match_parent"
			android:layout_height="wrap_content"
			android:layout_marginBottom="170dp"
			android:fontFamily="@font/roboto"
			android:text="@string/heading"
			android:textAlignment="center"
			android:textAppearance="@style/TextAppearance.AppCompat.Large"
			android:textColor="@android:color/holo_green_dark"
			android:textSize="36sp"
			android:textStyle="bold" />

		<Button
			android:id="@+id/startButton"
			android:layout_width="match_parent"
			android:layout_height="match_parent"
			android:layout_marginStart="20dp"
			android:layout_marginTop="10dp"
			android:layout_marginEnd="20dp"
			android:layout_marginBottom="20dp"
			android:background="#4CAF50"
			android:fontFamily="@font/roboto"
			android:text="@string/startButtonText"
			android:textAlignment="center"
			android:textAppearance="@style/TextAppearance.AppCompat.Display1"
			android:textColor="#FFFFFF"
			android:textStyle="bold" />

		<Button
			android:id="@+id/stopButton"
			android:layout_width="match_parent"
			android:layout_height="match_parent"
			android:layout_marginStart="20dp"
			android:layout_marginTop="10dp"
			android:layout_marginEnd="20dp"
			android:layout_marginBottom="20dp"
			android:background="#4CAF50"
			android:fontFamily="@font/roboto"
			android:text="@string/stopButtonText"
			android:textAlignment="center"
			android:textAppearance="@style/TextAppearance.AppCompat.Display1"
			android:textColor="#FFFFFF"
			android:textStyle="bold" />

		<ImageView
			android:id="@+id/imageView"
			android:layout_width="match_parent"
			android:layout_height="wrap_content"
			android:layout_marginTop="80dp"
			app:srcCompat="@drawable/banner" />
	</LinearLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

گام چهارم: ساخت کلاس Service سفارشی

در همان فایلی که کلاس MainActivity وجود دارد، یک کلاس دیگر درست میکنیم که مسئول پیاده سازی سرویس سفارشی ما است. متد هایی که در این سرویس وجود دارند برای شروع و متوقف کردن آن به کار میروند. برای پخش موسیقی از آبجکت MediaPlayer استفاده کردیم. کدهای زیر نحوه انجام کار را نشان میدهند.

import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.IBinder;
import android.provider.Settings;
import androidx.annotation.Nullable;

public class NewService extends Service {

	// declaring object of MediaPlayer
	private MediaPlayer player;

	@Override

	// execution of service will start
	// on calling this method
	public int onStartCommand(Intent intent, int flags, int startId) {

		// creating a media player which
		// will play the audio of Default
		// ringtone in android device
		player = MediaPlayer.create( this, Settings.System.DEFAULT_RINGTONE_URI );

		// providing the boolean
		// value as true to play
		// the audio on loop
		player.setLooping( true );

		// starting the process
		player.start();

		// returns the status
		// of the program
		return START_STICKY;
	}

	@Override

	// execution of the service will
	// stop on calling this method
	public void onDestroy() {
		super.onDestroy();

		// stopping the process
		player.stop();
	}

	@Nullable
	@Override
	public IBinder onBind(Intent intent) {
		return null;
	}
}

گام پنجم: کار با فایل MainActivity

در این مرحله باید دکمه هایی که در Layout ساختیم را درون فایل MainActivity دریافت کنیم و مشخص کنیم زمانی که روی آنها کلیک شد چه رفتاری باید داشته باشند. کد های زیر را نگاه کنید.

import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

	// declaring objects of Button class
	private Button start, stop;

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

		// assigning ID of startButton
		// to the object start
		start = (Button) findViewById( R.id.startButton );

		// assigning ID of stopButton
		// to the object stop
		stop = (Button) findViewById( R.id.stopButton );

		// declaring listeners for the
		// buttons to make them respond
		// correctly according to the process
		start.setOnClickListener( this );
		stop.setOnClickListener( this );
	}

	public void onClick(View view) {

		// process to be performed
		// if start button is clicked
		if(view == start){

			// starting the service
			startService(new Intent( this, NewService.class ) );
		}

		// process to be performed
		// if stop button is clicked
		else if (view == stop){

			// stopping the service
			stopService(new Intent( this, NewService.class ) );

		}
	}
}

گام ششم: ویرایش فایل AndroidManifest.xml

در این مرحله باید Service خودمان را درون فایل Manifest تعریف کنیم. نحوه انجام این کار را در ادامه مشاهده کنید.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
	package="com.example.services_in_android">

	<application
		android:allowBackup="true"
		android:icon="@mipmap/ic_launcher"
		android:label="@string/app_name"
		android:roundIcon="@mipmap/ic_launcher_round"
		android:supportsRtl="true"
		android:theme="@style/AppTheme">
		<activity android:name=".MainActivity">
			<intent-filter>
				<action android:name="android.intent.action.MAIN" />
				<category android:name="android.intent.category.LAUNCHER" />
			</intent-filter>
		</activity>
		<meta-data
			android:name="preloaded_fonts"
			android:resource="@array/preloaded_fonts" />
		
		<!-- Mention the service name here -->
		<service android:name=".NewService"/>
		
	</application>

</manifest>

خروجی: اجرا روی شبیه ساز

با اجرای این نرم افزار روی شبیه ساز یا یک تلفن همراه فیزیکی، میتوانید کار کردن آن را چک کنید. دقت کنید که اگر از نرم افزار خودتان به یک نرم افزار دیگر هم بروید، باز هم اجرای موسیقی باید ادامه پیدا کند.


سوالی دارید؟

سوال

در این مقاله سرویس ها و نحوه کار کردن با آنها در اپلیکیشن های اندروید را یاد گرفتیم و همه نکته های مورد نیاز را بررسی کردیم. اگر سوالی در ذهن شما وجود دارد یا موارد بیشتری بلد هستید، میتوانید با نوشتن آن در قسمت نظرات (همین پایین) این مقاله آموزشی را کامل تر کنید.


منابع بیشتر برای مطالعه

میتوانید از منابع زیر برای مطالعه بیشتر در زمینه Service های اندروید استفاده کنید:

  1. بازتاب: معرفی کامل معماری MVVM در اندروید + روش پیاده سازی | برنامه چی | Barnamechi

دیدگاه‌ خود را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

اسکرول به بالا