first-android-context-barnamechi

سیر تا پیاز Context در اندروید

وقتی که برنامه نویسی اندروید را شروع کردم، یکی از اولین سوال های مهمی که داشتم این بود که “این Context لامصب چیه تو برنامه برنامه نویسی اندروید؟!” یادم هست از اساتید و دوستانی که تجربه بیشتری داشتند در این باره سوال کردم. جواب آنها این بود که Context اندروید یکی از مفاهیم سخت برای برنامه نویس های تازه کار است که یادگیری و جا افتادن آن نیاز به زمان و تمرین دارد. بعدا خودم هم متوجه شدم توضیح این مفهوم برای دیگران کار خیلی سختی است. اما در این نوشته قصد دارم مفهوم Context اندروید را به زبان ساده توضیح بدهم تا این مفهوم برای شما هم بهتر از قبل جا بیافتد.

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

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


ویدئو: از سیر تا پیاز Android Context


تعریف Context اندروید

ترجمه کلمه Context به زبان فارسی میشود “زمینه”. میتوانیم دلیل نام گذاری این بخش از سیستم عامل اندروید را این طور در نظر بگیریم که این کلاس زمینه ای که اپلیکیشن در حال اجرا در آن میباشد را در دسترس ما قرار میدهد. در حقیقت Context در اندروید یکی از پرکار استفاده ترین و شاید مورد سو استفاده ترین آبجکت های اندروید است. بیشتر مقاله هایی که در اینترنت وجود دارند روی تعریف این آبجکت تمرکز دارند.

code در context اندروید

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

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

Context اندروید یک اینترفیس برای دسترسی به اطلاعات عمومی درباره محیط یک اپلیکیشن است. این کلاس از نوع Abstract است که توسط سیستم اندروید پیاده سازی (Implement) شده است. کلاس Context اجازه دسترسی به منابع و کلاس های مخصوص اپلیکیشن و همچنین صدا زدن عملیات های سطح اپلیکیشن مانند اجرای Activity ها، ارسال Broadcast، دریافت Intent و غیره را میدهد. معمولا برنامه نویس ها از Context اندروید برای اطلاع پیدا کردن از دیگر قسمت های اپلیکیشن (مانند اکتیویتی ها و پکیج ها) استفاده میکنند.

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

بعد از خواندن این تعریف به دو نکته باید توجه کنیم:

  • Context اطلاعاتی درباره محیط اجرای اپلیکیشن را به ما میدهد.
  • بسیار مهم است که بدانیم از کدام محیط باید برای کارهای خودمان استفاده کنیم.

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

  • Context به ما اجازه میدهد که به منابع دسترسی داشته باشیم.
  • Context به ما اجازه میدهد با دیگر کامپوننت های اندروید به وسیله ارسال پیام، ارتباط داشته باشیم.
  • Context اطلاعاتی درباره محیط اپلیکیشن به ما میدهد.

اما شاید فهمیدن مفهوم Context اندروید فقط با خواندن این تعریف ممکن نباشد. برای درک بهتر و تعریف به زبان ساده تر، بهتر است این مفهوم را دوباره با استفاده از چند مثال واقعی با هم بررسی کنیم.


فهم کامل Context در اندروید

در حقیقت، Context یکی از اجزای Android API است که طراحی ضعیفی دارد. به این مدل آبجکت ها، God Object هم گفته میشود. به نظر من فهم کامل و دقیق Context اندروید نیاز به زمان و تمرین در برنامه نویسی دارد. زیرا بعد از تمرین و استفاده زیاد از این آبجکت متوجه خواهید شد که انواع مختلفی از Context ها در اندروید موجود هستند و با توجه با وضعیتی که اپلیکیشن در آن قرار دارد و چرخه عمر کامپوننت ها، ممکن است انواع مختلفی از آنها را نیاز داشته باشید. کلا به مرور زمان این مفهوم که Context اطلاعات زمینه و حالت فعلی اپلیکیشن رو منتقل میکنه، بهتر داخل ذهن شما جای میگیرد.

فهم عمیق Context اندروید

یک اپ اندروید که پسوند APK (مخفف Application Package Kit) دارد، شامل تعدادی از کامپوننت هاست. به عبارت دیگر، تعدادی از کامپوننت ها که کنار همدیگر قرار میگیرند، اپلیکیشن اندروید را میسازند. این کامپوننت ها درون فایل Manifest اپلیکیشن تعریف میشوند و شامل اکتیویتی (UI)، سرویس (بک گراند)، BroadcastRecieber (اکشن ها)، ContentProvider (آطلاعات) و منابع (عکس، متن و غیره) میشوند. Context اندروید مانند یک پل بین کامپوننت ها عمل میکند. شما برای ارتباط با کامپوننت ها، شروع کامپوننت ها و دسترسی به کامپوننت های مختلف نیاز به استفاده از Context دارید.

چند مثال را با هم بررسی میکنیم:

  • مثال اول) فرض کنید شما وارد یک هتل شده اید و قصد دارید یک اتاق اجاره کنید. زمانی که در هتل هستید، نیاز به صبحانه، ناهار، شام، سرویس اتاق و استفاده از امکانات هتل را دارید. برای اینکه بتوانید از این موارد استفاده کنید، باید به مهماندار هتل درخواست بدهید تا این امکانات را در اختیار شما قرار بدهد. در این مثال مهماندار هتل مانند Context، شما مانند یک اکتیویتی تکی، امکاناتی که به دست شما میرسد مانند منابع (فیلم، متن، عکس و غیره) و هتل مانند کل اپلیکیشن در نظر گرفته میشود.
  •  مثال دوم) فرض کنید شما مدیر یک استارتاپ هستید که دارای یک معمار نرم افزار برای هدایت تیم توسعه میباشد. اگر شما نیاز داشته باشید که یک توسعه دهنده جدید را به تیم اضافه کنید، باید این درخواست را به سرگروه تیم توسعه بدهید و این سرگروه یک عضو جدید را به تیم اضافه میکند. همه وظیفه ها و مواردی که توسعه دهنده تازه وارد نیاز دارد رعایت کند و انجام بدهد باید توسط سرگروه مشخص شود. در این مثال سرگروه مانند Context، توسعه دهنده تازه وارد مانند یک کامپوننت (مثلا اکتیویتی)، و کل شرکت مانند اپلیکیشن در نظر گرفته میشود.

همانطور که تا اینجا متوجه شدید، اپلیکیشن تعدادی از کامپوننت های بسته بندی شده است. اما این کامپوننت ها کاملا مجزا هستند و به امکانات سیستم دسترسی ندارند. وسیله ای که باعث ایجاد ارتباط بین کامپوننت ها و استفاده از منابع سیستم میشود، Context اندروید است.

Context یک لایه (اینترفیس) است که پشت کامپوننت ها (اکتیویتی، اپلیکیشن، سرویس و …) و چرخه عمر آنها قرار میگیرد. این لایه دسترسی به عملکرد های مختلفی که توسط محیط اپلیکیشن و فریم ورک اندروید پشتیبانی میشوند را فراهم میکند.


انواع مختلف کلاس Context اندروید

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

یعنی کلا ما یک نوع context داریم، اما با توجه به روشی که این Context رو دریافت میکنیم، ممکنه اطلاعات اضافی هم همراه اون باشه

برای دسته بندی بهتر و کلی تر، Context ها را به دو دسته بندی کلی تقسیم میکنیم:


1- Context های رابط کاربری

ui context

در حقیقت فقط کلاس ContextThemeWrapper را باید به عنوان Context رابط کاربری (یعنی Context به همراه پوسته اپلیکیشن شما) در نظر بگیریم.

اکتیویتی ها کلاس ContextThemeWrapper را extend میکنند. دقیقا به همین دلیل است که وقتی یک فایل XML را Inflate میکنیم، همه المان های رابط کاربری از قبل دارای استایل کلی نرم افزار ما میباشند. یعنی اگر View های خودتان را با استفاده از Context های غیر رابط کاربری Inflate کنید، رابط کاربری آن قسمت دارای استایل کلی نرم افزار شما نخواهد بود (میتونین امتحان کنین).

وقتی که شما از اکتیویتی برای نگه داشتن Context استفاده میکنید، همیشه UI Context به دست شما خواهد رسید. وقتی که متد getContext را در فرگمنت استفاده میکنید، به صورت غیر مستقیم در حال استفاده از اکتیویتی هستید. (البته اگر فرگمنت را با استفاده از fragmentManager به اکتیویتی متصل کرده باشید).

نکته: استفاده از View.getContext همیشه UI Context بر نمیگرداند. اگر View با استفاده از Layout Inflater مقدار دهی اولیه شده باشد و Context رابط کاربری به آن پاس داده باشیم، UI Context برگردانده میشود. اما اگر مقدار دهی اولیه با نوع دیگر کانتکست باشد، نتیجه برعکس خواهد بود.


2- Context های غیر رابط کاربری

non-ui context

هرچیزی غیر از Context های رابط کاربری، در این دسته قرار میگیرند. در حقیقت هر چیزی که ContextThemeWrapper نداشته باشد، در این دسته جا دارد. Context های غیر رابط کاربری میتوانند همه کارهایی که Context های رابط کاربری میکنند را انجام بدهند. اما همانطور که در بالا اشاره شد، اطلاعات استایل و Theme در این دسته وجود ندارد.


روش دریافت Context

راه های مختلفی برای دریافت Context اندروید وجود دارد. سه تا از متدهایی که بیشترین استفاده را دارند در ادامه مشاهده میکنید:


1- متد getContext

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

Context اکتیویتی دارای کارکردهای مخصوص خودش نیز هست که میتوانیم از آنها برای همه کارهایی که فرم ورک اندروید از آنها پشتیبانی میکند استفاده کنیم. در لیست زیر میتوانید همه این توابع را مشاهده کنید:

Load Resource Values,
Layout Inflation,
Start an Activity,
Show a Dialog,
Start a Service,
Bind to a Service,
Send a Broadcast,
Register BroadcastReceiver.

2- متد getApplicationContext

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

متدها و توابعی که در Activity Context وجود داشتند، از طریق Application Context هم قابل دسترسی هستند. همه توابع و کارکرد هایی که در این مدل قابل دسترسی هستند را میتوانید در لیست زیر مشاهده کنید:

Load Resource Values,
Start a Service,
Bind to a Service,
Send a Broadcast,
Register BroadcastReceiver.

3- متد getBaseContext

این متد به ContextWrapper متصل است. این کلاس در اطراف یک Context موجود درست میشود و به ما اجازه میدهد رفتار آن را تغییر بدهیم. با متد getBaseContext میتوانیم Context موجود را درون یک ContextWrapper قرار بدهیم. یعنی این متد فقط زمانی کارایی دارد که یک آبجکت از کلاس ContextWrapper داشته باشیم. تکه کد زیر را مشاهده کنید:

ContextWrapper wrapper = new ContextWrapper(context); 

مزیت استفاده از این روش این است که میتوانید رفتار ها را بدون تغییر Context اصلی، تغییر بدهید.

وقتی که از کلمه this در اکتیویتی استفاده میکنیم، در حقیقت یک نوع Context را به کار برده ایم. زیرا کلاس Activity، کلاس Context را درون خود دارد. پس درون اکتیویتی هرجا نیاز به Context داشتیم، میتوانیم کلمه کلیدی this را به کار ببریم.


تفاوت متدهای getContext و getApplicationContext

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

تفاوت مهم این دو متد این است که Application Context با UI رابطه ای ندارد. یعنی ما نباید از این آبجکت برای ساخت Layout، شروع یک اکتیویتی یا نشان دادن یک دیالوگ استفاده کنیم. هرجا که نیاز به مقدار دهی اولیه یکی از انواع View بود، باید Activity Context را برای آن ارسال کنیم.

application and activity context

یک نکته مهم: اگر Theme یا استایل خاصی برای اکتیویتی تعریف نکرده باشید، میتوانید به جای استفاده از Activity Context، آبجکت Application Context را پاس بدهید.


تعدادی از کاربردهای Conetxt اندروید

با توجه به توضیحاتی که درباره Context اندروید داده شد، در سناریو های زیادی میتوانیم از این آبجکت استفاده کنیم. تعدادی از کاربردهای رایج استفاده آن را در ادامه میتوانید مشاهده کنید:


1- شروع صریح یک کامپوننت

// Provide context if MyActivity is an internal activity.
Intent intent = new Intent(context, MyActivity.class);
startActivity(intent);

وقتی که بخواهیم یک کامپوننت را صریحا استارت کنیم، دو تکه از اطلاعات را نیاز داریم:

  1. نام پکیج: این نام، اپلیکیشنی که میزبان کامپوننت هدف ما میباشد را مشخص میکند.
  2. کلاس جاوا: نام درست کلاسی که مربوط به کامپوننت است.

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


2- ساخت یک View

//instaniate a view
TextView textView = new TextView(context);

Context دارای اطلاعات زیر میباشد که برای ساخت آبجکت View مورد نیاز است:

  1. سایز صفحه نمایش دستگاه و ابعاد آن برای تبدیل مقادیر dp و sp به پیکسل.
  2. ویژگی (Attribute) هایی که استایل دهی شده اند.
  3. یک Reference به اکتیویتی برای تنظیم onClick ها.

3- Inflate کردن یک فایل XML برای ظاهر

کلاس LayoutInflater برای ساخت یا به اصطلاح Inflate کردن فایل های XML به کار میرود. اما این کلاس برای کار کردن، نیاز به آبجکت Context دارد.

// A context is required when creating views.
LayoutInflater inflater = LayoutInflater.from(context);
inflater.inflate(R.layout.my_layout, parent);

4- ارسال یک Broadcast محلی

کلاس LocalBroadcastManager برای ارسال و دریافت Broadcast های محلی استفاده میشود. این کلاس نیاز به آبجکت Context اندروید برای کار کردن دارد.

// The context contains a reference to the main Looper, 
// which manages the queue for the application's main thread.
Intent broadcastIntent = new Intent("custom-action");
LocalBroadcastManager.getInstance(context).sendBroadcast(broadcastIntent);

5- فراخوانی یک سرویس از سیستم

برای ارسال ناتیفیکیشن از اپلیکیشن، میتوانیم کلاس NotificationManager را به کار ببریم. میتوانیم برای دریافت همه سرویس های سیستم که میتوانند فراخوانی بشوند، از Context استفاده کنیم.

// Context objects are able to fetch or start system services.
NotificationManager notificationManager = 
    (NotificationManager) getSystemService(NOTIFICATION_SERVICE);

int notificationId = 1;

// Context is required to construct RemoteViews
Notification.Builder builder = 
    new Notification.Builder(context).setContentTitle("custom title");

notificationManager.notify(notificationId, builder.build());

جلوگیری از مشکل Memory Leak

معمولا زمانی از Application Context استفاده میکنیم که بخواهیم دیزاین پترن Singleton را انتخاب کنیم. مانند کلاس های مدیریتی مختلف که نیاز به اطلاعات Context دارند تا به سرویس های سیستم اجازه دسترسی بدهند. معمولا این کلاس ها در اکتیویتی های مختلف استفاده میشوند. به همین دلیل باید معماری Singleton برای جلوگیری از Memory Leak انتخاب مناسبی است.

memory leak در context اندروید

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


سوالی دارید؟

سوال درباره context اندروید

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


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

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

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

7 در مورد “سیر تا پیاز Context در اندروید”

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

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

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