مشخصات مقاله
-
3490
-
0.0
-
12458
-
0
-
0
آموزش ایجاد و بهره گیری از سرویس ها در اندروید
آموزش ایجاد و بهره گیری از service ها در اندروید,آموزش ایجاد و بهره گیری از سرویس ها در اندروید
این مبحث آموزشی به نحوه ی ایجاد و بهره گیری از سرویس های اندروید می پردازد و بر اساس Eclipse 4.3 و Java 1.6 و Android 4.4 نوشته شده است .
فهرست محتوا
1. سرویس های اندروید
- سرویس در اندروید چه معنا و کاربردی دارد ؟
- سرویس ها و پردازش پس زمینه ای
- سرویس پیش فرض محیط اندروید و سرویس های سفارشی
- ایجاد و راه اندازی سرویس های سفارشی در اندروید
2. تعریف سرویس های سفارشی
- اعلان و پیاده سازی سرویس ها
- راه اندازی و اجرای سرویس
- فرایند راه اندازی و اجرای سرویس مورد نظر
- عملکرد بازآغازی سرویس
- متوقف سازی یک سرویس
3.به ارث بری و بسط کلاس IntentService ویژه ی تسک هایی که یک بار اجاره می شوند
4. متصل کردن و مقید سازی سرویس ها
- ایجاد امکان تعامل و ارتباط بین activity و service
- Local services bindings
- بهره گیری از تکنولوژی ارتباط بین پردازشی (interprocess communication) برای تعامل با سرویس
5. راه اندازی سرویس ها در پروسه های مجزا
- اجرای سرویس در فرایند مختص به خود آن سرویس
- چه زمانی یک سرویس را در فرایندی مجزا راه اندازی کنیم ؟
6. برقراری ارتباط با سرویس ها
- گزینه هایی که برای برقراری ارتباط بین activity و service در اختیار داریم
- استفاده از داده ی intent
- بکارگیری receiver های ثبت شده برای برقراری ارتباط
- متصل کردن activity به سرویس های محلی
- Handler and ResultReceiver or Messenger
- AIDL (رابط توصیف زبان) برای سرویس هایی که در فرایندهای مجزا در حال اجرا هستند
7.تمرین : استفاده از سرویس ها جهت دانلود فایل از طریق activity
8. تمرین : اعلان و استفاده از سرویس های محلی
سرویس های اندروید
سرویس در اندروید چه معنا و کاربردی دارد ؟
Service در حقیقت یک مولفه (component) هست که بدون نیاز به تعامل مستقیم با کاربر در پس زمینه (background) اجرا می شود. از آنجایی که سرویس دارای رابط کاربری مختص به خود نیست, به چرخه ی حیات (life-cycle) activity متصل و مقید نمی باشد .
سرویس ها قالباً برای عملیات تکراری و احتمالاً طولانی مورد استفاده قرار می گیرند از جمله ی این عملیات می توان به دانلود ها, گردش در وب جهت بروز رسانی داده ها, پردازش اطلاعات, آپدیت content provider و مواردی مشابه آن اشاره کرد .
سرویس ها با اولویت بیشتری نسبت به activity های غیرفعال و غیر قابل رویت اجرا می شوند و از همین رو احتمال ناگه متوقف شدن یا خاتمه دادن آن توسط سیستم اندروید به مراتب ضعیف تر است . حتی اگرهم سرویس ها توسط سیستم اندروید ناگهان متوقف شوند, بازهم این امکان وجود دارد که آن ها را طوری پیکربندی کرد که در صورت در دسترس بودن مجدد منابع مورد نیاز دوباره راه اندازی شوند .
این امکان نیز وجود دارد که به سرویس ها همان اولویتی که activity های پس زمینه از آن برخوردار هستند تخصیص داد . در چنین مواردی لازم است یک notification (اطلاعیه) فعال که قابل رویت و پدیدار باشد ویژه ی آن سرویس داشته باشیم, حال notification نام برده غالباً ویژه ی سرویس هایی مورد استفاده قرار می گیرند که برای اجرای فیلم و موسیقی بکار گرفته می شوند .
سرویس ها و پردازش پس زمینه ای
به صورت پیش فرض, یک سرویس درست در همان فرایندی اجرا می شود که نخ اصلی (main thread) برنامه ی کاربردی مربوطه در آن اجرا می شود, از این رو توصیه می شود از پردازش ناهمگام (asynch processing) در سرویس مورد نظر استفاده شود تا بدین وسیله تسک هایی که منابع فشرده و ضروری نیاز دارند (Resource intensive tasks) در پس زمینه اجرا شوند . یکی از الگوهایی که به طور معمول و مکرراً در پیاده سازی سرویس بکار می رود, ایجاد و راه اندازی یک Thread جدید در سرویس مربوطه است تا از این طریق پردازش در پس زمینه صورت گیرد و پس از اتمام پردازش نیز سرویس را کاملاً متوقف (خاتمه) کند .
سرویس هایی که در فرایند های (متعلق به) برنامه ی کاربردی مورد نظر اجرا می شوند, به Service های محلی (local) نیز شهرت دارند .
سرویس پیش فرض محیط اندروید و سرویس های سفارشی
محیط اندروید (platform) خود سرویس های از پیش تعریف شده ای را فراهم می کند که طبیعتاً تمامی برنامه های کاربردی اندروید در صورت داشتن مجوز لازم, توانایی و اجازه ی استفاده از آن ها را دارند . سرویس های پیش فرض خود سیستم (system services) به طور معمول توسط یک کلاس مدیر (manager class) ویژه نمایانده و یا عرضه می شوند . دسترسی به سرویس های مزبور با فراخوانی متد getSystemService() صورت می پذیرد . کلاس Context چندین ثابت (constant) متعدد جهت دستیابی به این سرویس ها ارائه می دهد .
یک اپلیکیشن متعارف اندروید قادر است علاوه بر بهره گیری از سرویس های پیش فرض محیط اندروید, سرویس های جدیدی خلق کرده و مورد استفاده قرار دهد . با تولید سرویس های سفارشی یا اختصاصی خود قادر خواهید بود اپلیکیشن های واکنش گرا (responsive) طراحی کنید . می توان داده های برنامه ی کاربردی مورد نظر را به وسیله ی سرویس های سفارشی دریافت کرد . به مجرد اینکه برنامه توسط کاربر راه اندازی شد, سرویس مزبور اطلاعات جدید را به کاربر عرضه کند .
ایجاد و راه اندازی سرویس های سفارشی در اندروید
سرویس های سفارشی در واقع از دیگر مولفه های اندروید از قبیل activity ها, broadcast receiver ها و همچنین دیگر سرویس ها تشکیل می شوند .
تعریف سرویس های سفارشی
اعلان و پیاده سازی سرویس ها
یک سرویس جدید حتماً باید در فایل AndroidManifest.xml معرفی شده و کلاسی که پیاده سازی می شود نیز باید یا خود کلاس Service و یا یکی از کلاس های زیر مجموعه ی آن (subclass) را بسط دهد (به ارث برد) .
نمونه کد زیر مثالی از اعلان و پیاده سازی سرویس را به نمایش می گذارد .
public class MyService extends Service { @Override public int onStartCommand(Intent intent, int flags, int startId) { //TODO do something useful return Service.START_NOT_STICKY; } @Override public IBinder onBind(Intent intent) { //TODO for communication return IBinder implementation return null; } }
راه اندازی و اجرای سرویس
یک مولفه ی اندروید (service, receiver, activity) قادر است با فراخوانی متد startService(intent) پروسه ی اجرای یک سرویس را فعال (راه اندازی) کند .
// use this to start and trigger a service
Intent i= new Intent(context, MyService.class);
// potentially add data to the intent
i.putExtra("KEY1", "Value to be used by the service");
context.startService(i);
متناوباً, می توانید سرویس دلخواه را با صدا زدن متد bindService() راه اندازی کنید . این کار به شما این اجازه را می دهد تا با service مستقیماً ارتباط برقرار کنید .
فرایند راه اندازی و اجرای سرویس مورد نظر
چنانچه متد startService(intent) فراخوانده شده ولی سرویس هنوز اجرا نشده, در آن صورت شئی از سرویس ایجاد گشته و متد onCreate () سرویس مربوطه صدا زده می شود .
پس از اینکه service راه اندازی شد, متد onStartCommand(intent) در service صدا زده می شود, شئ Intent را از فراخوانی تابع startService(intent) به داخل ارسال می کند .
اگر تابع startService(intent) در حال اجرای سرویس فراخوانده شود (زمانی که سرویس راه اندازی شده و اکنون در حال اجرا است) , در این صورت متد onStartCommand() نیز به دنبال آن صدا زده می شود . بدین ترتیب سرویس ها باید آماده باشند تا از این طریق تابع onStartCommand() بتواند بارها صدا زده شود .
نکته : اگر متد مذکور را دوبار در کد خود صدا بزنید چه اتفاقی رخ می دهد ؟ آیا باید نگران همگام سازی فراخوانی متد onStartCommand() باشید ؟ در جواب باید بگوییم خیر, متد ذکر شده توسط سیستم اندروید در نخ اصلی رابط کاربری (main UI thread) صدا زده می شود, بهمین خاطر امکان صدا زدن آن به طور همزمان از دو نخ مختلف وجود ندارد .
یک سرویس تنها یکبار راه اندازی و اجرا می شود, صرف نظر از تعداد مرتبه هایی که تابع startService() فراخوانده می شود .
عملکرد بازآغازی سرویس
در فراخوانی متد onStartCommand(), سرویس یک int برمی گرداند که متعاقباً عملکرد بازآغازی سرویس را در صورتی که سرویس توسط محیط اندروید ناگهان متوقف شد, تعریف می کند . می توانید از ثابت ها برای این منظور کمک بگیرید .
معمول ترین گزینه های پیش رو در جدول زیر توصیف شده اند .
جدول 1. گزینه های باز آغازی
می توانید بررسی کنید آیا سرویس به وسیله ی Intent.getFlags() مجدداً راه اندازی شده است یا خیر . START_FLAG_REDELIVERY (در صورتی که سرویس با Service.START_REDELIVER_INTENT راه اندازی شده باشد) یا START_FLAG_RETRY (در صورتی که سرویس با Service.START_STICKY اجرا یا آغاز شده باشد) ارسال می گردد.
متوقف سازی یک سرویس
پروسه ی متوقف سازی سرویس به وسلیه ی تابع stopService() انجام می گیرد . ) صرف نظر از اینکه چند مرتبهstartService (intent) را (مکرراً( فراخوانی کردید(, کافی است یک بار متد stopService() را صدا بزنید تا سرویس کاملاً متوقف شود .
یک سرویس می تواند خود را با فراخوانی متد stopSelf() متوقف کند . این امر غالباً زمانی رخ می دهد که کار سرویس تمام شده باشد .
به ارث بری و بسط کلاس IntentService ویژه ی تسک هایی که یک بار اجاره می شوند
همچنین برنامه نویس این اجازه را دارد که کلاس IntentService را برای پیاده سازی سرویس به ارث ببرد .
IntentService به منظور اجرای تسک های خاصی در پس زمینه مورد استفاده قرار می گیرد. پس از انجام این کار, نمونه ی IntentService خود را به صورت خودکار کاملاً متوقف می کند . درمورد نمونه ی کاربرد آن می توان به دانلود منابع معینی از اینترنت اشاره کرد .
کلاس IntentService متد onHandleIntent()را ارائه می دهد که به صورت ناهمگام (asynch) توسط سیستم اندروید فراخوانی می شود .
متصل کردن و مقید سازی سرویس ها
ایجاد امکان تعامل و ارتباط بین activity و service
در صورت نیاز activity به تعامل مستقیم با سرویس, activity می تواند با استفاده از متد bindService() سرویس لازمه را راه اندازی کنید .
متد مذکور به ServiceConnection به مثابه ی یک پارامتر نیاز دارد که در هنگام راه اندازی سرویس و اتمام (استفاده از) متد onBind() صدا زده می شود . این متد یک شئ IBinder به ServiceConnection بازمی گرداند .
شئ IBinder توسط activity جهت برقراری رابطه با سرویس مورد استفاده قرار می گیرد .
هنگامی که فرایند اتصال یا مقید سازی (binding process) خاتمه می یابد, تابع onStartCommand() در سرویس فراخوانده شده و شئ Intent برای متد bindService() مورد استفاده قرار داده می شود .
Local services bindings
چنانچه سرویس و activity هر دو در یک فرایند اجرا شوند, این قابلیت وجود دارد که سرویس را به activity برگرداند . این امر به activity اجازه می دهد توابع سرویس را خود مستقیم صدا بزند .
بهره گیری از تکنولوژی ارتباط بین پردازشی (interprocess communication) برای تعامل با سرویس
در صورتی که سرویس در همان پروسه ی خود اجرا شود (در حال اجرا باشد), به IPC (تکنولوژی ارتباط بین پردازشی) جهت ارتباط با سرویس مورد نظر نیاز خواهی داشت .
راه اندازی سرویس ها در پروسه های مجزا
اجرای سرویس در فرایند مختص به خود آن سرویس
همچنین می توانید تعیین کنید که Service در یک پروسه ی جداگانه راه اندازی شود . این کار را می توان از طریق خصیصه ی android:process=":process_description" ترتیب داد .
علامت یا کاراکتر دونقطه (colon) که جلوی اسم قرار می گیرد به اندروید اطلاع می دهد که Service مورد نظر تنها مختص اپلیکیشنی است که آن را اعلان می کند (declaring app) . اگر هیچ کاراکتر دونقطه ای مورد استفاده قرار داده نشده باشد, در این صورت Service یک فرایند سراسری (global process) تلقی می شود که تمامی اپلیکیشن های اندروید توانایی بهره گیری از آن را دارند .
اجرای یک سرویس در فرایند خودش, به خصوص در مواردی که سرویس مزبور مجبور است عملیات طولانی و سنگین در نخ اصلی خود (main thread) اجرا کند, برنامه ی کاربردی مربوطه را مسدود (block) نمی سازد, اما از آنجایی که سرویس در پروسه ی خودش در حال اجرا است (اجرا شده), به منظور اتصال یا برقراری ارتباط با سرویس از دیگر بخش ها (part), برنامه نویس به قابلیت IPC (ارتباط بین پردازشی) نیاز پیدا می کند .
حتی اگر هم سرویس در پروسه ی خود در حال اجرا باشد, برای دسترسی به شبکه برنامه نویس (شما) باید از امکان پردازش ناهمگام کمک بگیرد, زیرا که اندروید اجازه ی دسترسی به شبکه را در نخ اصلی یک پروسه نمی دهد
چه زمانی یک سرویس را در فرایندی مجزا راه اندازی کنیم ؟
اجرای سرویس در پروسه ی متعلق به خود آن سرویس, نشانی یا آدرس فضای حافظه (memory address space) را خود ارائه می دهد و یک زباله روب (از دستگاه مجازی / virtual machine) در این پروسه, فرایند اپلیکیشن را دستخوش تغییر قرار نمی دهد .
لازم به ذکر است که یک اپلیکیشن متعارف به ندرت نیاز دارد یک سرویس را در پروسه ی خود اجرا کند . در واقع اجرای سرویس ها در فرایند خود (آن برنامه ی کاربردی), ارتباط با دیگر مولفه های اندروید و سرویس مورد نظر را به مراتب دشوارتر می سازد .
چنانچه مایلید یک سرویس را در دسترس دیگر برنامه های اندروید قرار دهید, در آن صورت آن ها باید در پروسه ی خود اجرا و راه اندازی شوند .
برقراری ارتباط با سرویس ها
گزینه هایی که برای برقراری ارتباط بین activity و service در اختیار داریم
راه های بالقوه و احتمالی متعددی وجود دارد که از طریق آن activityمی تواند با یک سرویس ارتباط برقرار کند و بالعکس . در این بخش از مقاله ی آموزشی به این رویکرد های احتمالی پرداخته و پیشنهاداتی در این زمینه در اختیار شما قرار می دهیم .
استفاده از داده ی intent
طبیعتاً در سناریو یا شرایطی ساده و معمولی هیچ گونه ارتباط مستقیمی نیاز نیست . سرویس داده ی intent را از مولفه ی شروع (starting component) دریافت کرده و کار لازم و مرتبط با آن را انجام می دهد . در این مورد هیچ احتیاجی به اطلاعیه (notification) نیست . به عنوان مثال, در صورتی که سرویس به آپدیت یک content provider بپردازد, content provider به activity اطلاع می دهد و دیگر هیچ مرحله یا اقدام اضافی نیاز نیست . رویکرد نام برده عمدتاً ویژه ی سرویس های محلی بکار گرفته می شود که در فرایند خود اجرا و راه اندازی می شوند .
بکارگیری receiver های ثبت شده برای برقراری ارتباط
شما می توانید از events broadcast (رخدادهای اعلام) و registered receivers (گیرندهای ثبت شده) ویژه ی برقراری ارتباط استفاده کنید . به عنوان مثال می توان از activity سخن به میان آورد که قادر است به صورت پویا (dynamic) یک (گیرنده ی پخش) broadcast receiver به رخداد تخصیص داده (register), سرویس نیز به دنبال آن رویدادهای مربوطه را (به بیرون) ارسال می کند .
همان طور که مشاهده می کنید جریان این ارتباط در تصویر زیر به نمایش گذاشته شده است .
نکته : اندروید کلاس LocalBroadcastManager را در کتابخانه ی پشتیبانی v4 برای برنامه نویس در نظر گرفته است . کلاس ذکر شده در حقیقت یک کلاس کمک رسانی (helper class) است که broadcastهای intent را برای اشیإ محلی ثبت کرده, سپس broadcast ها را به اشیإ فوق الذکر در داخل پروسه ارسال می کند . از آن جایی که (در این روش) broadcast event ها تنها داخل فرایند قابل رویت می باشند, به بهبود امنیت کمک شایانی شده است . همچنین استفاده از broadcast event ها به مراتب نسبت به استفاده از standard events (رخدادهای متعارف و استاندارد) سریع تر است .
این روش برای سرویس های محلی که در پروسه ی خود اجرا می شوند بکار گرفته می شود .
متصل کردن activity به سرویس های محلی
اگر سرویس و activity هر دو در یک فرایند یکسان راه اندازی شوند, در آن صورت activity می تواند مستقیماً به سرویس متصل شده و با آن تعامل برقرار کند . این روشی نسبتاً ساده و کارامد برای برقراری ارتباط می باشد و غالباً برای activity هایی که به لایه ی ارتباطی (communiacation layer) سریع با سرویس احتیاج دارند توصیه می شود .
لازم به ذکر است که رویکرد فوق مناسب سرویس های محلی (local servies) می باشد .
Handler and ResultReceiver or Messenger
در صورت لزوم ارتباط متقابل بین سرویس و activity, سرویس می تواند به وسیله ی داده ی Intent که از activity دریافت می کند, یک شئ از نوع Messenger دریافت کند . چنانچه Messenger در activity مورد نظر به یک Handler متصل می باشد, در آن صورت service می تواند اشیإیی از نوع Message به activity مربوطه ارسال کند .
Messenger تجزیه پذیر (parceable) است, به این معنا که می توان آن را به پروسه ی دیگری پاس داد (فرستاد) و از این شئ به منظور ارسال Messages به Handler در activity کمک گرفت.
Messenger همچنین متد getBinder() را ارائه می دهد . تابع مزبور امکان ارسال یک Messenger به activity را فراهم می کند . بنابه دلایل ذکر شده activity این توانایی را دارد که Messages به سرویس مورد نظر ارسال کند .
این رویکرد مناسب سرویس های محلی که در پروسه های خود اجرا می شوند, تعبیه شده است .
جهت اتصال به سرویسی که در پروسه ی دیگری در حال اجرا است, شما ملزوم به استفاده از تکنولوژی ارتباط بین پردازشی (IPC) هستید زیرا که داده باید بین فرایندهای متعدد رد و بدل شود . برای نیل به این هدف, لازم است یک فایل AIDL (Android Interface Description Language = یک رابط توصیف زبان مبتنی بر جاوا ویژه ی اندروید می باشد که از فراخوانی رویه های محلی و راه دور (remote) پشتیبانی می کند) که شبیه به رابط جاوا می باشد ولی به پسوند فایل .aidl ختم می شود و تنها اجازه ی بسط (extend) دیگر فایل های AIDL را دارد, ایجاد کنید .
این روش برای زمانی که برنامه نویس مجبور است به یک سرویس که در فرایند دیگری در حال اجرا است وصل (bind) شود, ضروری محسوب می شود, برای مثال می توان به وضعیتی اشاره کرد که در آن سرویس مورد استفاده ی دیگر اپلیکیش های اندروید قرار گرفته است .
تمرین : استفاده از سرویس ها جهت دانلود فایل از طریق activity
مثال زیر نحوه ی استفاده از سرویس جهت دانلود فایل از اینترنت, با زدن و فعال سازی تنها یک دکمه در activity را برای شما نمایش می دهد . پس از اتمام این عملیات, سرویس activity را به واسطه ی یک broadcast receiver از خاتمه ی پروسه ی دانلود مطلع می سازد .
در تمرین پیش رو از کلاس IntentService برای این مقصود استفاده می کنیم, زیرا که این کلاس قابلیت پردازش پس زمینه ای خودکار را در اختیارمان قرار می دهد.
پروژه ی جدیدی به نام com.vogella.android.service.receiver و activity ی به نام MainActivity ایجاد کنید .
در مرحله ی نخست, کلاس زیر را ویژه ی سرویس بسازید .
package com.vogella.android.service.receiver;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import android.app.Activity;
import android.app.IntentService;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.Message;
import android.os.Messenger;
import android.util.Log;
public class DownloadService extends IntentService {
private int result = Activity.RESULT_CANCELED;
public static final String URL = "urlpath";
public static final String FILENAME = "filename";
public static final String FILEPATH = "filepath";
public static final String RESULT = "result";
public static final String NOTIFICATION = "com.vogella.android.service.receiver";
public DownloadService() {
super("DownloadService");
}
// will be called asynchronously by Android
@Override
protected void onHandleIntent(Intent intent) {
String urlPath = intent.getStringExtra(URL);
String fileName = intent.getStringExtra(FILENAME);
File output = new File(Environment.getExternalStorageDirectory(),
fileName);
if (output.exists()) {
output.delete();
}
InputStream stream = null;
FileOutputStream fos = null;
try {
URL url = new URL(urlPath);
stream = url.openConnection().getInputStream();
InputStreamReader reader = new InputStreamReader(stream);
fos = new FileOutputStream(output.getPath());
int next = -1;
while ((next = reader.read()) != -1) {
fos.write(next);
}
// successfully finished
result = Activity.RESULT_OK;
} catch (Exception e) {
e.printStackTrace();
} finally {
if (stream != null) {
try {
stream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
publishResults(output.getAbsolutePath(), result);
}
private void publishResults(String outputPath, int result) {
Intent intent = new Intent(NOTIFICATION);
intent.putExtra(FILEPATH, outputPath);
intent.putExtra(RESULT, result);
sendBroadcast(intent);
}
}
حال این کلاس را به فایل AndroidManifest.xml اضافه کنید, سپس مجوز لازم برای نوشتن در حافظه ی خارجی و دسترسی به اینترنت را به آن اضافه کنید . فایل حاصله ی AndroidManifest.xml باید شبیه لیستینگ ذیل باشد .
فایل Layout را به صورت زیر بنویسید:
اکنون MainActivity را به زیر تغییر دهید .
package com.vogella.android.service.receiver;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends Activity {
private TextView textView;
private BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Bundle bundle = intent.getExtras();
if (bundle != null) {
String string = bundle.getString(DownloadService.FILEPATH);
int resultCode = bundle.getInt(DownloadService.RESULT);
if (resultCode == RESULT_OK) {
Toast.makeText(MainActivity.this,
"Download complete. Download URI: " + string,
Toast.LENGTH_LONG).show();
textView.setText("Download done");
} else {
Toast.makeText(MainActivity.this, "Download failed",
Toast.LENGTH_LONG).show();
textView.setText("Download failed");
}
}
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.status);
}
@Override
protected void onResume() {
super.onResume();
registerReceiver(receiver, new IntentFilter(DownloadService.NOTIFICATION));
}
@Override
protected void onPause() {
super.onPause();
unregisterReceiver(receiver);
}
public void onClick(View view) {
Intent intent = new Intent(this, DownloadService.class);
// add infos for the service which file to download and where to store
intent.putExtra(DownloadService.FILENAME, "index.html");
intent.putExtra(DownloadService.URL,
"http://www.vogella.com/index.html");
startService(intent);
textView.setText("Service started");
}
}
اگر مثال را اجرا کرده و دکمه ی مورد نظر را بزنید, پروسه ی دانلود توسط سرویس پیاده می شود . پس از پایان یابی این فرایند, رابط کاربری بروز رسانی شده و به دنبال آن یک Toast به همراه اسم فایل نشان داده می شود .
اکنون تنظیملت را اصلاح کنید تا سرویس در پروسه ی خود اجرا شود . پس از انجام این کار, مطمئن شوید که برنامه هنوز کار می کند زیرا که broadcast receiver ها از مرزهای فرایندهای دیگر عبور کرده و دریافت می شوند .
اعلان و استفاده از سرویس های محلی
در این تمرین به چگونگی اتصال به یک سرویس محلی از activity خواهیم پرداخت .
سرویس پس از اینکه دستگاه اندروید بالا می اید (بوت می شود) راه اندازی شده و طوری تنظیم می شود که به طور متناوب داده واکشی (fetch) کند . activity برای دسترسی به داده های سرویس خود را به آن متصل می کند .
پروژه ی جدید را de.vogella.android.ownservice.local و activity آن را MainActivity نام گذاری کنید .
package de.vogella.android.ownservice.local;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
public class LocalWordService extends Service {
private final IBinder mBinder = new MyBinder();
private ArrayList list = new ArrayList();
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Random random = new Random();
if (random.nextBoolean()) {
list.add("Linux");
}
if (random.nextBoolean()) {
list.add("Android");
}
if (random.nextBoolean()) {
list.add("iPhone");
}
if (random.nextBoolean()) {
list.add("Windows7");
}
if (list.size() >= 20) {
list.remove(0);
}
return Service.START_NOT_STICKY;
}
@Override
public IBinder onBind(Intent arg0) {
return mBinder;
}
public class MyBinder extends Binder {
LocalWordService getService() {
return LocalWordService.this;
}
}
public List getWordList() {
return list;
}
}
اکنون دو کلاس زیر را که به عنوان BroadcastReceivers ثبت (رجیستر) می شوند, خلق کنید .
package de.vogella.android.ownservice.local;
import java.util.Calendar;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class MyScheduleReceiver extends BroadcastReceiver {
// restart service every 30 seconds
private static final long REPEAT_TIME = 1000 * 30;
@Override
public void onReceive(Context context, Intent intent) {
AlarmManager service = (AlarmManager) context
.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(context, MyStartServiceReceiver.class);
PendingIntent pending = PendingIntent.getBroadcast(context, 0, i,
PendingIntent.FLAG_CANCEL_CURRENT);
Calendar cal = Calendar.getInstance();
// start 30 seconds after boot completed
cal.add(Calendar.SECOND, 30);
// fetch every 30 seconds
// InexactRepeating allows Android to optimize the energy consumption
service.setInexactRepeating(AlarmManager.RTC_WAKEUP,
cal.getTimeInMillis(), REPEAT_TIME, pending);
// service.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(),
// REPEAT_TIME, pending);
}
}
package de.vogella.android.ownservice.local;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class MyStartServiceReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Intent service = new Intent(context, LocalWordService.class);
context.startService(service);
}
}
کلیه ی مولفه ها را در فایل AndroidManifest.xml ثبت کنید .
فایل طرح بندی (layout) activity را مشابه نمونه ی زیر اصلاح کنید .
کلاس activity خود را به کد زیر تغییر دهید .
package de.vogella.android.ownservice.local;
import java.util.ArrayList;
import java.util.List;
import android.app.ListActivity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Toast;
public class MainActivity extends ListActivity {
private LocalWordService s;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
wordList = new ArrayList();
adapter = new ArrayAdapter(this,
android.R.layout.simple_list_item_1, android.R.id.text1,
wordList);
setListAdapter(adapter);
}
@Override
protected void onResume() {
super.onResume();
Intent intent= new Intent(this, LocalWordService.class);
bindService(intent, mConnection,
Context.BIND_AUTO_CREATE);
}
@Override
protected void onPause() {
super.onPause();
unbindService(mConnection);
}
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className,
IBinder binder) {
LocalWordService.MyBinder b = (LocalWordService.MyBinder) binder;
s = b.getService();
Toast.makeText(MainActivity.this, "Connected", Toast.LENGTH_SHORT)
.show();
}
public void onServiceDisconnected(ComponentName className) {
s = null;
}
};
private ArrayAdapter adapter;
private List wordList;
public void onClick(View view) {
if (s != null) {
Toast.makeText(this, "Number of elements" + s.getWordList().size(),
Toast.LENGTH_SHORT).show();
wordList.clear();
wordList.addAll(s.getWordList());
adapter.notifyDataSetChanged();
}
}
}
برنامه ی کاربردی را راه اندازی کرده و دکمه را فشار دهید . بار دیگر داده از سرویس واکشی (fetch) شده و ListView بروز رسانی می شود .