العمليات و المواضيع Processes and Threads
في هذه الوثيقةالعملياتدورة حياة العمليةالخيوطالمواضيع عاملطرق خيط آمنةاتصال interprocess
عند بدء تشغيل مكون التطبيق والتطبيق ليس لديه أي مكونات أخرى قيد التشغيل، يبدأ نظام أندرويد عملية لينكس جديدة للتطبيق مع مؤشر ترابط واحد من التنفيذ. افتراضيا، يتم تشغيل كافة مكونات نفس التطبيق في نفس العملية وخيط الترابط (تسمى "مؤشر الترابط" الرئيسي). في حالة بدء تشغيل مكون تطبيق وهناك بالفعل عملية لهذا التطبيق (لوجود مكون آخر من التطبيق)، ثم يتم بدء المكون ضمن هذه العملية ويستخدم نفس مؤشر التنفيذ. ومع ذلك، يمكنك ترتيب مكونات مختلفة في التطبيق الخاص بك لتشغيلها في عمليات منفصلة، ويمكنك إنشاء مؤشرات ترابط إضافية لأي عملية.
تناقش هذه الوثيقة كيفية عمل العمليات والخيوط في تطبيق أندرويد.
العمليات
افتراضيا، يجب تشغيل كافة مكونات نفس التطبيق في نفس العملية ومعظم التطبيقات لا يجب تغيير هذا. ومع ذلك، إذا وجدت أنك تحتاج إلى التحكم في العملية التي ينتمي إليها مكون معين، يمكنك القيام بذلك في ملف البيان.إدخال البيان لكل نوع من عناصر المكون - <activity> و <service> و <receiver> و <provider> يدعم سمة android:process بروسيس التي يمكنها تحديد عملية يجب تشغيل هذا المكون فيها. يمكنك تعيين هذه السمة بحيث يتم تشغيل كل مكون في العملية الخاصة به أو بحيث تشارك بعض المكونات عملية بينما لا يفعل الآخرون. يمكنك أيضا تعيين android:process بحيث مكونات تطبيقات مختلفة تعمل في نفس العملية شريطة أن التطبيقات تشترك نفس معرف المستخدم لينكس ويتم توقيع مع نفس الشهادات.
كما يدعم العنصر <application> سمة android:process لتعيين قيمة افتراضية تنطبق على جميع المكونات.
الروبوت قد تقرر لإيقاف عملية في مرحلة ما، عندما الذاكرة منخفضة ومطلوبة من قبل العمليات الأخرى التي هي أكثر خدمة على الفور للمستخدم. مكونات التطبيق قيد التشغيل في العملية التي قتلت وبالتالي دمرت. يتم بدء عملية مرة أخرى لتلك المكونات عندما يكون هناك مرة أخرى العمل بالنسبة لهم القيام به.
عندما تقرر أي عمليات لقتل، ونظام أندرويد يزن أهميتها النسبية للمستخدم. على سبيل المثال، فإنه يزيل بسهولة عملية استضافة العمليات التي لم تعد مرئية على الشاشة، مقارنة مع عملية استضافة أنشطة مرئية. وبالتالي فإن قرار إنهاء العملية يتوقف على حالة المكونات التي تعمل في تلك العملية.
تتم مناقشة تفاصيل دورة حياة العملية وعلاقتها بحالات التطبيق في العمليات ودورة حياة التطبيق .
الخيوط
عند بدء تشغيل تطبيق، يقوم النظام بإنشاء سلسلة تنفيذ للتطبيق، يسمى "رئيسي". هذا الموضوع مهم جدا لأنه هو المسؤول عن إيفاد الأحداث إلى الحاجيات واجهة المستخدم المناسبة، بما في ذلك رسم الأحداث. بل هو أيضا دائما تقريبا موضوع الذي يتفاعل التطبيق الخاص بك مع مكونات من مجموعة أدوات واجهة المستخدم الروبوت (مكونات من android.widget و android.view حزم). على هذا النحو، ويسمى أيضا الموضوع الرئيسي أحيانا مؤشر ترابط واجهة المستخدم. ومع ذلك، في ظل ظروف خاصة، قد لا يكون الموضوع الرئيسي التطبيق في مؤشر واجهة المستخدم الخاص به؛ لمزيد من المعلومات، راجع التعليقات التوضيحية الموضوع .
لا يقوم النظام بإنشاء مؤشر ترابط منفصل لكل مثيل مكون. يتم مثيل كافة المكونات التي تعمل في نفس العملية في مؤشر ترابط واجهة المستخدم، ويتم إرسال استدعاءات النظام إلى كل مكون من هذا الموضوع. ونتيجة لذلك، يتم دائما تشغيل الأساليب التي تستجيب onKeyDown() النظام (مثل onKeyDown() للإبلاغ عن إجراءات المستخدم أو أسلوب استدعاء دورة الحياة) في مؤشر ترابط واجهة المستخدم للعملية.
على سبيل المثال، عندما يلمس المستخدم زرا على الشاشة، يرسل مؤشر ترابط واجهة مستخدم التطبيق إلى الحدث الذي يعمل باللمس إلى الأداة، والذي بدوره يقوم بتعيين حالته المضغوط ويقوم بنشر طلب غير صالح إلى قائمة انتظار الحدث. يؤدي مؤشر ترابط واجهة المستخدم إلى إزالة الطلب وإعلام الأداة بأنه يجب إعادة رسم نفسه.
عندما يقوم تطبيقك بعمل مكثف استجابة لتفاعل المستخدم، يمكن أن يؤدي نموذج ترابط واحد هذا إلى ضعف الأداء ما لم تنفذ تطبيقك بشكل صحيح. على وجه التحديد، إذا كان كل شيء يحدث في مؤشر ترابط واجهة المستخدم، يؤدي تنفيذ عمليات طويلة مثل الوصول إلى الشبكة أو استعلامات قاعدة البيانات إلى حظر واجهة المستخدم بأكملها. عندما يتم حظر مؤشر الترابط، لا يمكن إرسال أي أحداث، بما في ذلك أحداث الرسم. من وجهة نظر المستخدم، يظهر التطبيق لتعليق. والأسوأ من ذلك، إذا تم حظر مؤشر ترابط واجهة المستخدم لأكثر من بضع ثوان (حوالي 5 ثوان حاليا) يتم عرض المستخدم مع الحوار " تطبيق لا يستجيب " (أنر) سيئة السمعة. قد يقرر المستخدم عندئذ إنهاء تطبيقك وإزالته إذا كانوا غير راضين.
بالإضافة إلى ذلك، مجموعة أدوات واجهة مستخدم أندرويد ليست سلسلة رسائل آمنة. لذلك، يجب عدم التلاعب واجهة المستخدم الخاصة بك من مؤشر ترابط عامل-يجب أن تفعل كل التلاعب إلى واجهة المستخدم الخاص بك من مؤشر ترابط واجهة المستخدم. وهكذا، هناك ببساطة اثنين من قواعد لالروبوت نموذج واحد موضوع:
لا تحظر مؤشر ترابط واجهة المستخدم
لا تقم بالوصول إلى مجموعة أدوات واجهة مستخدم أندرويد من خارج مؤشر ترابط واجهة المستخدم
المواضيع عامل
وبسبب النموذج المترابط المفرد الموصوف أعلاه، من الأهمية بمكان استجابة واجهة مستخدم التطبيق التي لا تحظر مؤشر ترابط واجهة المستخدم. إذا كان لديك عمليات لتنفيذ ليست فورية، يجب التأكد من القيام بها في سلاسل محادثات منفصلة ("الخلفية" أو "عامل" المواضيع).
ومع ذلك، لاحظ أنه لا يمكنك تحديث واجهة المستخدم من أي مؤشر ترابط بخلاف مؤشر ترابط واجهة المستخدم أو مؤشر ترابط "رئيسي".
لحل هذه المشكلة، يقدم أندرويد عدة طرق للوصول إلى مؤشر ترابط واجهة المستخدم من سلاسل الترابط الأخرى. وفيما يلي قائمة بالأساليب التي يمكن أن تساعد:
Activity.runOnUiThread(Runnable)
View.post(Runnable)
View.postDelayed(Runnable, long)
public void onClick(View v) {
new Thread(new Runnable() {
public void run() {
// a potentially time consuming task
final Bitmap bitmap =
processBitMap("image.png");
mImageView.post(new Runnable() {
public void run() {
mImageView.setImageBitmap(bitmap);
}
});
}
}).start();
}
هذا التطبيق هو موضوع-آمنة: يتم تشغيل الخلفية من مؤشر ترابط منفصل بينما يتم التلاعب ImageView دائما من مؤشر ترابط واجهة المستخدم.
ومع ذلك، مع تعقيد العملية ينمو، وهذا النوع من التعليمات البرمجية يمكن أن تكون معقدة وصعبة للحفاظ عليها. لمعالجة تفاعلات أكثر تعقيدا مع مؤشر ترابط عامل، قد تفكر في استخدام Handler في مؤشر ترابط عامل الخاص بك، لمعالجة الرسائل تسليمها من مؤشر ترابط واجهة المستخدم. ولعل أفضل حل، هو توسيع فئة AsyncTask ، مما يبسط تنفيذ مهام مؤشر ترابط العامل التي تحتاج إلى التفاعل مع واجهة المستخدم.
استخدام أسينكتاسك
AsyncTask يسمح لك لأداء العمل غير المتزامن على واجهة المستخدم الخاص بك. يقوم بتنفيذ عمليات حظر في مؤشر ترابط عامل ثم نشر النتائج على مؤشر ترابط واجهة المستخدم دون الحاجة إلى التعامل مع المواضيع و / أو المعالجات نفسك.
لاستخدامه، يجب أن فئة فرعية AsyncTask وتنفيذ الأسلوب استدعاء doInBackground() الذي يتم تشغيله في مجموعة من المواضيع الخلفية. لتحديث واجهة المستخدم، يجب أن تنفذ على onPostExecute() ، الذي يسلم النتيجة من doInBackground() ويتم تشغيله في مؤشر ترابط واجهة المستخدم، حتى تتمكن من تحديث واجهة المستخدم الخاصة بك بأمان. يمكنك ثم تشغيل المهمة عن طريق استدعاء execute() من مؤشر ترابط واجهة المستخدم.
يجب عليك قراءة مرجع AsyncTask لفهم كامل حول كيفية استخدام هذه الفئة.
طرق خيط آمنة
في بعض الحالات، قد يتم استدعاء الأساليب التي تقوم بتنفيذها من أكثر من مؤشر ترابط واحد، وبالتالي يجب أن تكون مكتوبة ليكون مؤشر ترابط آمنة.
وينطبق هذا أساسا على الأساليب التي يمكن استدعاؤها عن بعد - مثل الأساليب في خدمة ملزمة . عندما تنشأ مكالمة على طريقة تنفذ في IBinder في نفس العملية التي يتم تشغيل IBinder ، يتم تنفيذ الطريقة في مؤشر الترابط المتصل. ومع ذلك، عندما ينشأ المكالمة في عملية أخرى، يتم تنفيذ الطريقة في مؤشر ترابط يتم اختياره من تجمع مؤشرات الترابط الذي يحافظ عليه النظام في نفس عملية IBinder (لم يتم تنفيذها في مؤشر ترابط واجهة المستخدم للعملية). على سبيل المثال، في حين أنه سيتم استدعاء طريقة onBind() من الخدمة من مؤشر ترابط واجهة المستخدم لعملية الخدمة، يتم استدعاء الطرق التي يتم تنفيذها في الكائن الذي يقوم onBind() بإرجاع (على سبيل المثال، فئة فرعية تقوم بتنفيذ أساليب ريك) من سلاسل الترابط في حوض السباحة. لأن الخدمة يمكن أن يكون أكثر من عميل واحد، أكثر من واحد مؤشر الترابط تجمع يمكن أن تشارك نفس الطريقة IBinder في نفس الوقت. لذلك، يجب تنفيذ طرق IBinder لتكون آمنة.
وبالمثل، يمكن لموفر المحتوى تلقي طلبات البيانات التي تنشأ في عمليات أخرى. على الرغم من أن الطبقات ContentProvider و ContentProvider إخفاء تفاصيل كيفية إدارة الاتصالات إنتيربروسيس، أساليب ContentProvider التي تستجيب لتلك الطلبات- query() أساليب query() ، insert() ، delete() ، update() ، و getType() يسمى من مجموعة من المواضيع في عملية موفر المحتوى، وليس مؤشر ترابط واجهة المستخدم للعملية. لأنه قد يتم استدعاء هذه الأساليب من أي عدد من مؤشرات الترابط في نفس الوقت، يجب أيضا أن يتم تنفيذها لتكون مؤشر ترابط.
اتصال interprocess
الروبوت يوفر آلية للاتصال إنتيربروسيس (إيبك) باستخدام استدعاءات الإجراء البعيد (ريكس)، حيث يتم استدعاء طريقة من خلال نشاط أو مكون تطبيق آخر، ولكن تنفيذها عن بعد (في عملية أخرى)، مع أي نتيجة عاد إلى المتصل. وهذا يستلزم تحلل استدعاء الأسلوب وبياناته إلى مستوى يمكن أن يفهمه نظام التشغيل، ويحيله من العملية المحلية ومساحة العنوان إلى العملية عن بعد ومساحة العنوان، ثم إعادة تجميع وإعادة الاتصال المكالمة هناك. ثم ترسل قيم العودة في الاتجاه المعاكس. يوفر الروبوت كافة التعليمات البرمجية لتنفيذ هذه المعاملات إيبك، حتى تتمكن من التركيز على تحديد وتنفيذ واجهة البرمجة ريك.
لتنفيذ إيبك، يجب أن يكون التطبيق الخاص بك ملزم خدمة، باستخدام bindService() . لمزيد من المعلومات، راجع دليل مطوري الخدمات .
ومع ذلك، مع تعقيد العملية ينمو، وهذا النوع من التعليمات البرمجية يمكن أن تكون معقدة وصعبة للحفاظ عليها. لمعالجة تفاعلات أكثر تعقيدا مع مؤشر ترابط عامل، قد تفكر في استخدام Handler في مؤشر ترابط عامل الخاص بك، لمعالجة الرسائل تسليمها من مؤشر ترابط واجهة المستخدم. ولعل أفضل حل، هو توسيع فئة AsyncTask ، مما يبسط تنفيذ مهام مؤشر ترابط العامل التي تحتاج إلى التفاعل مع واجهة المستخدم.
استخدام أسينكتاسك
AsyncTask يسمح لك لأداء العمل غير المتزامن على واجهة المستخدم الخاص بك. يقوم بتنفيذ عمليات حظر في مؤشر ترابط عامل ثم نشر النتائج على مؤشر ترابط واجهة المستخدم دون الحاجة إلى التعامل مع المواضيع و / أو المعالجات نفسك.
لاستخدامه، يجب أن فئة فرعية AsyncTask وتنفيذ الأسلوب استدعاء doInBackground() الذي يتم تشغيله في مجموعة من المواضيع الخلفية. لتحديث واجهة المستخدم، يجب أن تنفذ على onPostExecute() ، الذي يسلم النتيجة من doInBackground() ويتم تشغيله في مؤشر ترابط واجهة المستخدم، حتى تتمكن من تحديث واجهة المستخدم الخاصة بك بأمان. يمكنك ثم تشغيل المهمة عن طريق استدعاء execute() من مؤشر ترابط واجهة المستخدم.
يجب عليك قراءة مرجع AsyncTask لفهم كامل حول كيفية استخدام هذه الفئة.
طرق خيط آمنة
في بعض الحالات، قد يتم استدعاء الأساليب التي تقوم بتنفيذها من أكثر من مؤشر ترابط واحد، وبالتالي يجب أن تكون مكتوبة ليكون مؤشر ترابط آمنة.
وينطبق هذا أساسا على الأساليب التي يمكن استدعاؤها عن بعد - مثل الأساليب في خدمة ملزمة . عندما تنشأ مكالمة على طريقة تنفذ في IBinder في نفس العملية التي يتم تشغيل IBinder ، يتم تنفيذ الطريقة في مؤشر الترابط المتصل. ومع ذلك، عندما ينشأ المكالمة في عملية أخرى، يتم تنفيذ الطريقة في مؤشر ترابط يتم اختياره من تجمع مؤشرات الترابط الذي يحافظ عليه النظام في نفس عملية IBinder (لم يتم تنفيذها في مؤشر ترابط واجهة المستخدم للعملية). على سبيل المثال، في حين أنه سيتم استدعاء طريقة onBind() من الخدمة من مؤشر ترابط واجهة المستخدم لعملية الخدمة، يتم استدعاء الطرق التي يتم تنفيذها في الكائن الذي يقوم onBind() بإرجاع (على سبيل المثال، فئة فرعية تقوم بتنفيذ أساليب ريك) من سلاسل الترابط في حوض السباحة. لأن الخدمة يمكن أن يكون أكثر من عميل واحد، أكثر من واحد مؤشر الترابط تجمع يمكن أن تشارك نفس الطريقة IBinder في نفس الوقت. لذلك، يجب تنفيذ طرق IBinder لتكون آمنة.
وبالمثل، يمكن لموفر المحتوى تلقي طلبات البيانات التي تنشأ في عمليات أخرى. على الرغم من أن الطبقات ContentProvider و ContentProvider إخفاء تفاصيل كيفية إدارة الاتصالات إنتيربروسيس، أساليب ContentProvider التي تستجيب لتلك الطلبات- query() أساليب query() ، insert() ، delete() ، update() ، و getType() يسمى من مجموعة من المواضيع في عملية موفر المحتوى، وليس مؤشر ترابط واجهة المستخدم للعملية. لأنه قد يتم استدعاء هذه الأساليب من أي عدد من مؤشرات الترابط في نفس الوقت، يجب أيضا أن يتم تنفيذها لتكون مؤشر ترابط.
اتصال interprocess
الروبوت يوفر آلية للاتصال إنتيربروسيس (إيبك) باستخدام استدعاءات الإجراء البعيد (ريكس)، حيث يتم استدعاء طريقة من خلال نشاط أو مكون تطبيق آخر، ولكن تنفيذها عن بعد (في عملية أخرى)، مع أي نتيجة عاد إلى المتصل. وهذا يستلزم تحلل استدعاء الأسلوب وبياناته إلى مستوى يمكن أن يفهمه نظام التشغيل، ويحيله من العملية المحلية ومساحة العنوان إلى العملية عن بعد ومساحة العنوان، ثم إعادة تجميع وإعادة الاتصال المكالمة هناك. ثم ترسل قيم العودة في الاتجاه المعاكس. يوفر الروبوت كافة التعليمات البرمجية لتنفيذ هذه المعاملات إيبك، حتى تتمكن من التركيز على تحديد وتنفيذ واجهة البرمجة ريك.
لتنفيذ إيبك، يجب أن يكون التطبيق الخاص بك ملزم خدمة، باستخدام bindService() . لمزيد من المعلومات، راجع دليل مطوري الخدمات .