onCreate هو الطريقة الأولى والوحيدة الإجبارية في دورة حياة Activity و Fragment في Android. يستدعيه النظام مرة واحدة عند إنشاء مكون، ممررًا معلمة Bundle بالحالة المحفوظة سابقًا. داخل onCreate، يقوم المطور بتهيئة واجهة المستخدم، وربط عناصر View، وتكوين معالجات الأحداث، واستعادة البيانات من savedInstanceState. بدون تنفيذ صحيح لـ onCreate، لا يمكن تشغيل أي تطبيق Android — إنه نقطة الدخول لكل شاشة. لمزيد من التفاصيل حول دورة حياة Activity العامة، اقرأ المقال Activity Lifecycle.
النقاط الرئيسية
onCreate هو طريقة استدعاء (callback) يستدعيها Android عند إنشاء مثيل جديد لـ Activity أو Fragment. هذه هي نقطة الدخول الأولى في كود شاشة المستخدم: لا يتم تشغيل أي كود للمستخدم قبل استدعاء onCreate. يمرر النظام معلمة Bundle إلى الطريقة، والتي تحتوي إما على بيانات محفوظة سابقًا (عند إعادة الإنشاء) أو تكون null (عند الإطلاق الأول).
يتم تعريف طريقة onCreate في الفئة android.app.Activity وفي الفئة androidx.fragment.app.Fragment. تقوم كلا النسختين بمهام متشابهة: تهيئة المكون، إعداد واجهة المستخدم واستعادة الحالة. ولكن التنفيذ المحدد يختلف — يستخدم Activity setContentView لتحميل التخطيط، بينما يعيد Fragment View عبر onCreateView. يجب على المطور إعادة تعريف onCreate على الأقل في Activity — بدون ذلك، لا يستطيع Android عرض الشاشة.
يتم استدعاء onCreate مرة واحدة بالضبط خلال دورة حياة كاملة لمثيل Activity. حتى عند تدوير الشاشة، يتلقى مثيل Activity جديد استدعاء onCreate جديد مع Bundle من المثيل السابق. هذا يجعل onCreate المكان المثالي للتهيئة لمرة واحدة: تحميل البيانات، إنشاء المكيّفات، إعداد مكوّنات DI عبر Dagger أو Hilt.
في Activity، تؤدي طريقة onCreate أربع مهام رئيسية: تحميل تخطيط layout، تهيئة عناصر View، استعادة الحالة من Bundle، وإعداد معالجات الأحداث الأساسية. الكود الأدنى الإجباري في onCreate هو استدعاء super.onCreate(savedInstanceState) و setContentView(R.layout.activity_main).
class MainActivity : AppCompatActivity() {
private var binding: ActivityMainBinding? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// ViewBinding — بديل حديث لـ findViewById
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding?.root)
// التهيئة باستخدام binding
binding?.apply {
welcomeText.text = getString(R.string.welcome)
startButton.setOnClickListener { startGame() }
}
// استعادة الحالة
if (savedInstanceState != null) {
score = savedInstanceState.getInt("score", 0)
binding?.scoreText?.text = score.toString()
}
}
}
الممارسة الحديثة تستخدم ViewBinding بدلاً من findViewById. يقوم ViewBinding بإنشاء الفئة ActivityMainBinding في وقت الترجمة، مما يلغي الأخطاء بالأيدي غير الصحيحة ويقلل الكود المكرر. توصي Google باستخدام ViewBinding كطريقة قياسية للوصول إلى View في Activity و Fragment ابتداءً من Android Studio 3.6.
يجب أن يكون ترتيب العمليات في onCreate صارمًا: أولاً super، ثم setContentView، ثـ5 كل شيء آخر. استدعاء findViewById قبل setContentView يعيد null — لم يتم تحميل التخطيط بعد، ولا توجد عناصر View في التسلسل الهرمي. هذا هو أحد أكثر الأخطاء شيوعًا بين مطوري Android المبتدئين.
onCreate في Fragment يختلف عن Activity: لا يتم استدعاء setContentView هنا، يتم فقط تهيئة البيانات غير المرتبطة بواجهة المستخدم. يفصل Fragment إنشاء المكون عن إنشاء View إلى طريقتين منفصلتين: onCreate (تستدعى مرة) و onCreateView (تستدعى كل مرة يتم فيها إنشاء أو إعادة إنشاء View).
class UserListFragment : Fragment() {
private lateinit var viewModel: UserViewModel
private var binding: FragmentUserListBinding? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// تهيئة ViewModel — تنجو من إعادة إنشاء View
viewModel = ViewModelProvider(this)[UserViewModel::class.java]
// الوسائط من FragmentManager
arguments?.let {
viewModel.loadUser(it.getString("user_id") ?: "")
}
// الحفظ عند التدوير
retainInstance = true
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = FragmentUserListBinding.inflate(inflater, container, false)
return binding!!.root
}
}
الفرق الرئيسي بين onCreate في Activity و Fragment: onCreate في Fragment لا يجب أن يحتوي على كود متعلق بـ View، لأن View يمكن أن يتم تدميره وإعادة إنشائه (على سبيل المثال، عند التبديل بين علامات تبويب ViewPager)، بينما يتم استدعاء onCreate مرة واحدة فقط. تحميل البيانات، إعداد ViewModel وتهيئة المكيّفات هي مهام onCreate، بينما ربط View هو مهمة onViewCreated.
معلمة savedInstanceState في onCreate هي آلية لحفظ واستعادة الحالة المؤقتة لـ Activity أو Fragment. عندما يدمر النظام Activity (تدوير الشاشة، نقص الذاكرة)، يستدعي onSaveInstanceState()، حيث يضع المطور إدخالات من نوع مفتاح-قيمة في Bundle. عند إنشاء مثيل جديد، يتم إعادة هذا Bundle في onCreate.
يدعم Bundle أنواع البيانات التالية: String، Integer، Boolean، Long، Float، Double، مصفوفاتها، بالإضافة إلى كائنات Parcelable و Serializable. للكائنات المعقدة، يتم استخدام Parcelable — آلية تسلسل أكثر كفاءة ومحددة لـ Android. حجم Bundle محدود بتقريب 500 كيلوبايت — تجاوز الحد يؤدي إلى TransactionTooLargeException.
companion object {
private const val KEY_USER_NAME = "user_name"
private const val KEY_SCORE = "score"
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_game)
if (savedInstanceState != null) {
userName = savedInstanceState.getString(KEY_USER_NAME) ?: ""
currentScore = savedInstanceState.getInt(KEY_SCORE)
}
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putString(KEY_USER_NAME, userName)
outState.putInt(KEY_SCORE, currentScore)
}
من المهم فهم: لا يتم استدعاء onSaveInstanceState عندما يغلق المستخدم Activity بصورة صريحة عبر finish() أو زر الرجوع. يعتبر النظام أن المستخدم ينهي العمل بوعي ولا يحتاج إلى حفظ الحالة. لذا، لا يمكنك الاعتماد فقط على savedInstanceState لتخزين البيانات طويل الأمد — استخدم Room، DataStore أو SharedPreferences.
يتم تنفيذ onCreate في الخيط الرئيسي (UI)، وينتظر النظام اكتماله قبل عرض Activity على الشاشة. إذا استغرق onCreate أكثر من 5 ثوان، يعرض النظام حوار ANR (Application Not Responding) ويقدم للمستخدم خيار إغلاق التطبيق. يجب نقل العمليات الطويلة، مثل تحميل البيانات من الشبكة أو القراءة من قاعدة بيانات، إلى خيط خلفي.
وفقًا لتوصيات Google Android Performance (2025)، يجب أن يكتمل onCreate في أقل من ثانية واحدة على الأجهزة متوسطة الفئة. لتحقيق ذلك: استخدم التهيئة البطيئة (lazy delegate في Kotlin)، أخر تحميل البيانات الثقيلة إلى onResume أو عبر الكوروتينز، طبق ViewStub لمكونات UI نادرة الاستخدام، وقيس وقت البدء من خلال Android Vitals.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// التهيئة البطيئة — يتم إنشاء الكائن فقط عند أول وصول
val heavyData by lazy {
HeavyDataLoader.load()
}
// تحميل البيانات في الخلفية عبر lifecycleScope
lifecycleScope.launch(Dispatchers.IO) {
val users = userDao.getAllUsers()
withContext(Dispatchers.Main) {
adapter.submitList(users)
}
}
}
أدوات التحليل: يعرض Android Studio Profiler (علامة تبويب CPU) وقت التنفيذ الدقيق لكل طريقة. في Android Vitals (وحدة تحكم Google Play)، يمكنك تتبع مقياس «وقت البدء البارد» — إذا تجاوز onCreate لـ Activity الخاص بك 500 ملي ثانية، تعلمها وحدة التحكم كمشكلة أداء. في IT Sectr، نستخدم اختبارات Macrobenchmark للتحكم التلقائي في وقت بدء كل Activity في خط أنابيب CI.
ViewModel هو أفضل طريقة لتهيئة البيانات في onCreate التي يجب أن تبقى عند تدوير الشاشة. يتم إنشاء ViewModel في onCreate عبر ViewModelProvider ويتم الاحتفاظ به تلقائيًا عند تغييرات التهيئة. عندما يتم إعادة إنشاء Activity بعد التدوير، يبقى ViewModel في الذاكرة، ويتلقى onCreate نفس ViewModel دون فقدان للبيانات.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_profile)
// يتم إنشاء ViewModel مرة واحدة وينجو من تغييرات التهيئة
val viewModel: ProfileViewModel =
ViewModelProvider(this)[ProfileViewModel::class.java]
// مراقبة LiveData — يتم تحديث واجهة المستخدم تلقائيًا عند تغير البيانات
viewModel.user.observe(this) { user ->
binding?.userName?.text = user.name
binding?.userEmail?.text = user.email
}
// تحميل البيانات إذا تم إنشاء ViewModel توبًا
if (savedInstanceState == null) {
viewModel.loadProfile(userId)
}
}
يحل مزيج ViewModel + LiveData/StateFlow مشكلة تدوير الشاشة دون الحاجة إلى الحفظ اليدوي في Bundle. يخزن ViewModel البيانات في الذاكرة، يقوم LiveData بإعادة اشتراك Activity تلقائيًا عند إعادة الإنشاء، ويضيف StateFlow (من Kotlin Coroutines) الاستجابية مع دعم الكوروتينز. هذه هي المعمارية القياسية الموصى بها من Google في Guide to App Architecture.
حتى المطورون ذوو الخبرة يرتكبون أخطاء نموذجية في onCreate. دعنا ننظر إلى أكثر خمسة مشاكل شيوعًا وكيفية تجنبها.
الخطأ الأكثر شيوعًا هو محاولة العثور على View من خلال findViewById قبل استدعاء setContentView. يتم إنشاء جميع عناصر View في لحظة تمديد التخطيط، لذا فإن أي استدعاء لـ findViewById قبل setContentView يعيد null ويسبب NullPointerException عند محاولة استخدام View. الحل: ترتيب صارم — أولاً super، ثم setContentView، ثم findViewById أو ViewBinding.
تحميل البيانات من الشبكة، القراءة من قاعدة بيانات أو معالجة مصفوفات كبيرة مباشرة في onCreate يحجز عرض الإطار الأول. يرى المستخدم شاشة سوداء حتى يكتمل onCreate، مما يضعف إدراك سرعة التطبيق. الحل: استخدم lifecycleScope.launch للعمليات غير المتزامنة، اعرض هيكلاً عظميًا (UI placeholder) حتى اكتمال التحميل.
إذا لم تقم باستعادة الحالة من Bundle عند تدوير الشاشة، يفقد المستخدم جميع المدخلات غير المحفوظة: النص في حقول النموذج، موقع التمرير، العناصر المحددة. الحل: تحقق دائمًا من savedInstanceState != null في onCreate لاستعادة البيانات، حتى لو كان فقدان الحالة يبدو غير محتمل.
يمكن للفئات المجهولة ولامبدات في onCreate أن تحتفظ ضمنيًا بمرجع إلى Activity بعد تدميره. على سبيل المثال، يستمر Handler المنشأ في onCreate في تنفيذ المهام المؤجلة حتى بعد تدمير Activity. الحل: استخدم LifecycleObserver، ViewModel و lifecycleScope، التي تلغي المهام تلقائيًا عند التدمير.
تهيئة View في onCreate لـ Fragment هي خطأ منطقي، لأن View يمكن إعادة إنشائه دون استدعاء onCreate. إذا قمت بإعداد مستمع في onCreate وربط View في onCreateView، سيبقى المستمع على View القديم عند إعادة الإنشاء. الحل: قم بجميع العمل المتعلق بـ View في onViewCreated، واترك onCreate فقط لتهيئة طبقة البيانات.
الأسئلة الشائعة
نعم، إعادة تعريف onCreate إجبارية لأي Activity يعرض واجهة مستخدم. بدونها، من المستحيل استدعاء setContentView وتحميل تخطيط XML. إذا كان Activity لا يملك UI (على سبيل المثال، Activity شفافة مؤقتة)، يتم إعادة تعريف onCreate مع ذلك، ولكن دون استدعاء setContentView.
لا، لا يمكن استدعاء onCreate مرة أخرى لنفس مثيل Activity. إذا تم تدمير Activity وإعادة إنشائه (تدوير الشاشة، نقص الذاكرة)، يكون هذا مثيلاً جديداً مع استدعاء جديد لـ onCreate. استثناء هو الطريقة recreate()، التي تدمر وتعيد إنشاء Activity بالقوة، ولكن هذا إعادة إنشاء مثيل جديد.
إذا لم تقم باستدعاء super.onCreate(savedInstanceState)، سيطرح Android Runtime استثناء SuperNotCalledException وسيتعطل التطبيق. يتطلب النظام بصرامة أن كل طريقة دورة حياة معاد تعريفها تستدعي نسختها super — هذا يضمن التشغيل الصحيح لآلة الحالات الداخلية.
الفرق الرئيسي: onCreate في Activity يحمل UI عبر setContentView، بينما onCreate في Fragment يهيئ البيانات فقط. ينشئ Fragment View في طريقة منفصلة onCreateView، والتي يمكن استدعاؤها عدة مرات (على سبيل المثال، عند تبديل العلامات)، بينما يتم استدعاء onCreate لـ Fragment مرة واحدة خلال عمر مثيل Fragment.
تتم تخزين البيانات المهيئة في onCreate في حقول فئة Activity أو Fragment. على سبيل المثال، private lateinit var binding: ActivityMainBinding يتم الإعلان عنه على مستوى الفئة، ويتم تهيئته في onCreate ويكون متاحًا في جميع الطرق اللاحقة. للبيانات التي تبقى عند تدوير الشاشة، استخدم ViewModel مع LiveData أو StateFlow.
الملخص
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.