كيفية إنشاء خلفية لتطبيق أندرويد؟
في هذه المقالة، سنتحدث عن أندرويد – أحد أشهر أنظمة التشغيل. سنلقي نظرة على إيجابيات وسلبيات تطوير الأندرويد، وخيارات الواجهة الخلفية لتطبيقات الجوال، وسنعلمك كيفية بناء الواجهة الخلفية الخاصة بك على الجوال.
Contents
الوجبات الرئيسية
- هيمنة أندرويد: يعمل نظام التشغيل Android، بوصفه نظام تشغيل مفتوح المصدر، على تشغيل ما يقرب من 70% من الأجهزة المحمولة مع أكثر من ثلاثة مليارات مستخدم نشط.
- خيارات الواجهة الخلفية للتطبيقات: بالنسبة إلى الواجهات الخلفية لتطبيقات الأجهزة المحمولة، يمكن للمطورين اختيار البنية التحتية كخدمة (IaaS) أو المنصة كخدمة (PaaS) أو الواجهة الخلفية كخدمة (BaaS).
- خطوات بناء الواجهة الخلفية الخاصة بك: سنقدم برنامجًا تعليميًا تفصيليًا حول كيفية إنشاء واجهة خلفية لنظام Android باستخدام منصة BaaS والرمز المصدري بنهاية المقال.
ما هو الأندرويد؟
أندرويد هو نظام تشغيل مجاني ومفتوح المصدر قائم على نظام لينكس. وقد تم تصميمه في المقام الأول للأجهزة المحمولة مثل الهواتف الذكية والأجهزة اللوحية، ولكنه يُستخدم الآن أيضًا في أجهزة التلفاز الذكية والأنظمة المدمجة وأجهزة الألعاب وغيرها.
بدأ تطوير Android في عام 2003 من قبل شركة Android Inc. أرادت الشركة في البداية إنشاء نظام تشغيل للكاميرات الرقمية، ولكنها سرعان ما تحولت نحو تطوير نظام تشغيل للهواتف المحمولة للوصول إلى سوق أوسع.
وفي عام 2005، استحوذت Google على الشركة مع موظفيها. تم إصدار الإصدار الأول من أندرويد في عام 2008.
على الرغم من أن أندرويد مفتوح المصدر، إلا أن معظم الأجهزة المحمولة تعمل بنسخة جوجل المملوكة لها. وتأتي نسختهم مثبتة مسبقاً مع برامج مثل Google Chrome وYouTube وGoogle TV وGmail.
نظرًا لخيارات التخصيص الرائعة التي يوفرها نظام Android، فإن العديد من الشركات المصنعة أيضًا تقوم بتهيئة نظام Android لتمثيل شركتها بشكل أفضل. لهذا السبب يبدو OnePlus Android مختلفًا تمامًا عن Pixel Android.
نظام التشغيل Android هو نظام التشغيل الأكثر شعبية منذ عام 2013. ويستخدمه ما يقرب من 70% من الأجهزة المحمولة ولديه أكثر من ثلاثة مليارات مستخدم نشط شهرياً.
وعلاوة على ذلك، يوفر لك متجر Google Play Store إمكانية الوصول إلى أكثر من ثلاثة ملايين تطبيق للهاتف المحمول. تابع القراءة لمعرفة كيفية إنشاء خلفية لتطبيق أندرويد.
فوائد تطوير أندرويد
دعنا نستكشف بعض مزايا التطوير لنظام Android.
عبر المنصة
من خلال التطوير لنظام Android يمكنك استهداف مجموعة كبيرة من الأجهزة. وهذا يشمل الهواتف المحمولة، والأجهزة القابلة للارتداء، وأجهزة التلفاز الذكية، وأجهزة الألعاب، وغيرها. إذا كنت تعرف كيفية برمجة تطبيق جوال، فلن تواجه أي مشكلة في تطوير تطبيق قابل للارتداء أو تلفزيون ذكي.
سوق ضخمة
كما ذكرنا سابقًا، يستحوذ نظام Android على حصة سوقية أكبر بنسبة 70%، مقارنةً بنظام iOS بنسبة 30%. من خلال تطوير تطبيقات Android، ستتمكن تلقائيًا من الوصول إلى جمهور أوسع.
علاوة على ذلك، تشتهر تطبيقات Android باستثماراتها المنخفضة وعائدها المرتفع على الاستثمار. وعلى عكس نظام iOS، لا توجد أيضاً رسوم سنوية للمطورين.
قابلية التخصيص
أجهزة Android قابلة للتخصيص بدرجة كبيرة مقارنة بأنظمة التشغيل الأخرى. فهي تسمح لك بتغيير أي شيء يمكنك تخيله عملياً.
بالإضافة إلى ذلك، يتيح لك نظام Android دمج تطبيقك مع خدمات الطرف الثالث الأخرى بسهولة.
المجتمع
أندرويد مدعوم بمجتمع هائل من المطورين مفتوح المصدر. وعلاوة على ذلك، فإنه يأتي مع العديد من الأدوات الصديقة للمطورين مثل Android Studio وADB وLogcat التي تتيح لك برمجة التطبيقات بسهولة.
إذا واجهتك أي مشكلة في أي وقت، فهناك العديد من المنصات التي يمكنك أن تجد فيها المساعدة، بما في ذلك GitHub و StackOverflow و Reddit وغيرها من المجتمعات التي تركز على نظام Android.
حدود تطوير أندرويد
فيما يلي بعض سلبيات تطوير نظام Android.
الأمن
نظام Android أقل أماناً من نظام iOS ولا يتبع بروتوكولات أمنية صارمة. نظرًا لأن أندرويد مفتوح المصدر، يتم اكتشاف الثغرات الأمنية أسبوعيًا. وهذا يمنح المخترقين القدرة على استغلال هذه الثغرات قبل أن يتم تصحيحها.
يمكن أيضًا عمل روت لأجهزة Android للحصول على وصول المستخدم الخارق. وعلى الرغم من أن ذلك يجعل جهازك أكثر قوة، إلا أنه محفوف بالمخاطر أيضًا لأنه يعطل بعض إجراءات الأمان المدمجة.
التعقيد
تأتي أجهزة Android بأشكال وأحجام مختلفة، وعلى الرغم من أن هذا أمر رائع، إلا أنه قد يكون عيبًا كبيرًا عند تطوير تطبيقات Android لأنواع متعددة من الأجهزة.
للتأكد من توافق تطبيقك مع أكبر عدد ممكن من الأجهزة، سيتعين عليك دمج التصميم سريع الاستجابة، والتفكير في أجهزة الأجهزة المختلفة، وما إلى ذلك.
تطبيقات متميزة
التطبيقات المميزة أقل نجاحاً على متجر Google Play مقارنة بمتجر التطبيقات. ليس سراً أن مستخدمي Android يميلون إلى إنفاق أقل على التطبيقات مقارنة بمستخدمي iOS. إذا كنت تعمل على تطبيق متميز أولاً، فاعتبر Android خيارك الثاني.
خيارات الواجهة الخلفية لتطبيقات Android
ما هي أفضل خلفية لتطبيقات الأندرويد؟ يمكن استضافة الخلفيات لتطبيقات الجوال على البنية التحتية الخاصة بك أو نشرها على الخدمات السحابية. تتضمن نماذج الحوسبة السحابية الأكثر شيوعًا للواجهات الخلفية للأجهزة المحمولة ما يلي:
- البنية التحتية كخدمة (IaaS)
- المنصة كخدمة (PaaS)
- الواجهة الخلفية كخدمة (BaaS)
يغطي كل خيار طبقات تجريد مختلفة، كما هو موضح في الصورة أدناه.
دعنا نلقي نظرة على كل خيار بالتفصيل لمساعدتك في تحديد النموذج السحابي الأنسب لتطبيقاتك الخلفية.
البنية التحتية كخدمة (IaaS)
البنية التحتية كخدمة (IaaS) هو نموذج الحوسبة السحابية الأقل تجريدًا. في هذا النموذج، يقدم البائع للمستخدمين موارد افتراضية، مثل الخوادم والشبكات والتخزين وأنظمة التشغيل، من خلال واجهات برمجة التطبيقات عالية المستوى أو لوحات تحكم بديهية.
أفضل ما في IaaS هو أنه يمنح المستخدمين تحكمًا كاملاً في بنيتهم التحتية بالكامل. IaaS هو النموذج الأكثر مرونة وقابلية للتطوير ولكنه أيضاً الأكثر صعوبة في الإدارة. إذا اخترت هذا الخيار، ستحتاج على الأرجح إلى مسؤول نظام أو اثنين.
بعض الأمثلة على IaaS هي Amazon Web Services و Google Cloud Platform و Azure.
المنصة كخدمة (PaaS)
النظام الأساسي كخدمة (PaaS) هو نموذج حوسبة سحابية مصمم لمساعدة المستخدمين على تطوير التطبيقات وإدارتها ونشرها.
إلى جانب توفير البنية التحتية، تأتي المنصة كخدمة مع أدوات سهلة الاستخدام لتطوير التطبيقات وتخصيصها واختبارها.
من خلال استخدام PaaS، ستتمكن من التركيز على برامجك وتجربة المستخدم دون القلق بشأن البنية التحتية الأساسية.
بالإضافة إلى ذلك، ستضمن المنصة كخدمة توسيع نطاق تطبيقك عند الطلب، والاهتمام بالنسخ الاحتياطية، وما إلى ذلك. وتتمثل سلبيات PaaS في انخفاض مستوى التحكم، ومخاطر انغلاق البائع، وارتفاع التكاليف نسبيًا.
تشمل منصات PaaS الأكثر شيوعًا منصات Heroku وRender وDigital Ocean App Platform.
الواجهة الخلفية كخدمة (BaaS)
تعمل الواجهة الخلفية كخدمة (BaaS) على أتمتة الجزء الخلفي من التطوير من خلال توفير حل خلفي متكامل.
تتضمن ميزات BaaS إدارة المستخدمين وقواعد البيانات والمصادقة والتكاملات الاجتماعية والإشعارات الفورية وواجهات برمجة التطبيقات وحزم تطوير البرمجيات والمزيد.
تمنحك BaaS جميع مزايا IaaS وPaaS مع توفير وظائف إضافية. تميل الفرق التي تستفيد من BaaS إلى إصدار منتجاتها بشكل أسرع، وخفض التكاليف الهندسية، وبناء برامج أفضل.
تشمل الجوانب السلبية لمنصة BaaS انخفاض مستوى التحكم والتخصيص وإمكانية انغلاق البائع على المنصات غير مفتوحة المصدر.
تشمل أمثلة BaaS Back4app، وAWS Amplify، وFirebase.
كيفية إنشاء خلفية لتطبيق أندرويد؟
في هذا القسم من المقالة، سنلقي نظرة على كيفية إنشاء تطبيق خلفي يستند إلى Back4app والاتصال به من تطبيق Android.
المتطلبات الأساسية
- خبرة في تطوير Kotlin وAndroid.
- الفهم الأساسي للواجهة الخلفية للجوال كخدمة.
- Java و Android Studio مثبتان على جهازك المحلي.
ما هو تطبيق Back4app؟
Back4app هو منصة ممتازة لبناء خلفيات للتطبيقات الحديثة وتسريع عملية التطوير.
يأتي مجهزًا جيدًا بميزات مفيدة من جانب الخادم مثل إدارة المستخدم، وقواعد البيانات في الوقت الفعلي، والتكاملات الاجتماعية، ووظائف الرمز السحابي، والإشعارات الفورية، وواجهات برمجة التطبيقات، والمزيد!
باستخدام تطبيق Back4app، ستتمكن من الاستعانة بمصادر خارجية في الكثير من أعمال الواجهة الخلفية والتركيز على الجوانب المهمة في تطبيقك وتسريع تطوير الواجهة الخلفية لتطبيق Android.
لن تكون هناك حاجة للتعامل مع البنية التحتية الأساسية للواجهة الخلفية، وخادم الواجهة الخلفية، والتوسع، والصيانة، وما إلى ذلك.
والأهم من ذلك، يقدم Back4app مستوى مجاني وهو رائع لتجربة واختبار المنصة. ومع نمو تطبيقك، يمكنك الترقية إلى باقات مميزة مقابل رسوم شهرية.
مقدمة المشروع
في هذه المقالة، سنقوم ببناء تطبيق ملاحظات بسيط. سيسمح التطبيق للمستخدمين بإضافة الملاحظات وتعديلها وحذفها. سيتم تخزين الملاحظات في قاعدة بيانات Back4app ومعالجتها عبر Parse SDK.
سنستخدم لغة البرمجة Kotlin لبناء التطبيق. بالنسبة لواجهة المستخدم، سنستخدم Jetpack Compose – مجموعة أدوات Android الحديثة لبناء واجهات مستخدم أصلية.
إنشاء تطبيق Back4app
كخطوة أولى لتطوير خلفية لتطبيق أندرويد، ستحتاج إلى حساب Back4app. إذا لم يكن لديك حساب، فقم بالتسجيل.
عند تسجيل الدخول إلى حساب Back4app الخاص بك، ستتم إعادة توجيهك إلى عرض التطبيق. انقر على “إنشاء تطبيق جديد” لبدء عملية إنشاء التطبيق.
تقدم منصة Back4app حلين:
- الواجهة الخلفية كخدمة (BaaS) – حل قوي للواجهة الخلفية
- الحاويات كخدمة (CaaS) – منصة لإدارة الحاويات (خاصة تطبيقات الويب)
بالنظر إلى أننا نبني واجهة خلفية لتطبيق جوال، سنستخدم “الواجهة الخلفية كخدمة”.
امنح تطبيقك اسمًا لطيفًا وغنيًا بالمعلومات، واختر “NoSQL” كقاعدة بيانات، وانقر على “إنشاء”. هذه خطوة مهمة لنشر خلفية لتطبيق Android.
سيستغرق Back4app بعض الوقت لإعداد كل ما هو مطلوب لتطبيقك. يتضمن ذلك قاعدة البيانات، وإدارة المستخدمين، والتوسع، والتكوينات، وما إلى ذلك. بمجرد أن يصبح تطبيقك جاهزاً، ستتم إعادة توجيهك إلى عرض قاعدة بيانات تطبيقك.
تصميم قاعدة البيانات
للمضي قدمًا، دعنا نصمم قاعدة البيانات. هذه خطوة ضرورية لتطوير خلفية لتطبيق أندرويد.
بما أننا ننشئ تطبيق ملاحظات بسيط، سنحتاج إلى فصل واحد فقط. انطلق وانقر على “إنشاء صنف”، وقم بتسميته "ملاحظة
“، وقم بتمكين “قراءة وكتابة عامة”، وانقر على “إنشاء صنف وإضافة أعمدة”.
بعد ذلك، أضف الحقول الثلاثة التالية إلى الفئة المنشأة حديثًا:
+-------------+-------------+--------------------+----------+
| Data type | Name | Default value | Required |
+-------------+-------------+--------------------+----------+
| String | icon | <leave blank> | yes |
+-------------+-------------+--------------------+----------+
| String | title | <leave blank> | yes |
+-------------+-------------+--------------------+----------+
| String | content | <leave blank> | yes |
+-------------+-------------+--------------------+----------+
أخيرًا، انقر على زر “إضافة صف” وقم بتعبئة قاعدة البيانات الخاصة بك ببعض البيانات النموذجية. إذا لم يكن لديك أي أفكار، يمكنك أيضًا استيراد تفريغ البيانات هذا.
عظيم، هذا كل شيء بالنسبة للجهة الخلفية.
كود الواجهة الأمامية
في هذا القسم من المقالة، سنقوم بإعداد تطبيق Android جديد، وإعداد ViewModel، وتنفيذ واجهة المستخدم، وتثبيت Parse SDK وتكوينه، وأخيرًا جلب البيانات من قاعدة بيانات Back4app في الوقت الفعلي.
المشروع الأولي
كما هو مذكور في قسم المتطلبات الأساسية، ستتطلب منك الخطوات التالية تثبيت Android Studio. إذا لم يكن لديك بعد، فقم بتنزيله.
ابدأ بفتح Android Studio والنقر على زر “مشروع جديد”.
ثم حدد “نشاط فارغ” كقالب مشروعك، وانقر على “التالي”.
لإنشاء مشروعك، يجب عليك تقديم اسم واسم حزمة. أقترح عليك استخدام AndroidApp
كاسم مشروعك واسم المجال العكسي كحزمة مشروعك.
بعد الانتهاء من تهيئة كل شيء، انقر على “إنهاء” لإنشاء المشروع.
سيستغرق Android Studio دقيقتين تقريبًا لإعداد كل ما هو مطلوب. يتضمن ذلك إنشاء بنية ملف المشروع، وإعداد Gradle، وتثبيت التبعيات، وما إلى ذلك.
بمجرد أن يصبح مشروعك جاهزًا، استخدم المستكشف للانتقال إلى MainActivity.kt واستبدال محتوياته:
// app/src/main/java.<your_package_name>/MainActivity.kt
package <your.package.name>
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.sp
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MaterialTheme {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background,
) {
Text(text = "Back4app rocks!", fontSize = 18.sp)
}
}
}
}
}
تأكد دائمًا من استبدال باسم الحزمة الفعلي الخاص بك.
أخيرًا، حاول تشغيل التطبيق بالنقر على زر التشغيل الأخضر أو Shift + F10
على لوحة المفاتيح. إذا سار كل شيء على ما يرام، يجب أن يبدأ المحاكي، ويجب أن ترى رسالة صخور Back4app
على الشاشة.
نموذج العرض
لإدارة الحالة العامة لتطبيقنا، سنستخدم نموذج عرض ViewModel
. ولكن قبل ذلك، علينا قبل ذلك إنشاء صنف بيانات الملاحظات
بنفس السمات الموجودة في قاعدة بيانات Back4app الخاصة بنا.
قم بإنشاء فئة بيانات باسم ملاحظة
:
// app/src/main/java.<your_package_name>/Note.kt
package <your.package.name>
data class Note(
var objectId: String? = null,
var icon: String,
var title: String,
var content: String,
) {
companion object {
fun generateObjectId(): String {
val chars = ('a'..'z') + ('A'..'Z') + ('0'..'9')
return (1..10).map { chars.random() }.joinToString("")
}
}
}
- لقد حددنا طريقة
توليد معرف الكائن
الثابتة()
لتوليد معرّفات كائنات شبيهة ب Parse. objectId
لاغٍ لأننا سنفترض لاحقًا أنه إذا كانobjectId = = = لاغٍ،
فإن الكائن لم يُحفظ في قاعدة البيانات بعد.
بعد ذلك، أنشئ فئة AppViewModel
بالمحتويات التالية:
// app/src/main/java.<your_package_name>/AppViewModel.kt
package <your.package.name>
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel
class AppViewModel : ViewModel() {
val notes: MutableState<Map<String, Note>> = mutableStateOf(mapOf(
"7IggsqFAKt" to Note(
objectId = "7IggsqFAKt",
icon = "\uD83D\uDE80",
title = "Deploy app",
content = "Go ahead and deploy your backend to Back4app.",
),
"eFRNm0hTat" to Note(
objectId = "eFRNm0hTat",
icon = "\uD83C\uDFA8",
title = "Design website",
content = "Design the website for the conference.",
),
"uC7hTQmG5F" to Note(
objectId = "uC7hTQmG5F",
icon = "\uD83D\uDC42",
title = "Attend meeting",
content = "Attend meeting with the team to discuss the conference.",
),
))
companion object {
@Volatile
private var instance: AppViewModel? = null
fun getInstance(): AppViewModel {
return instance ?: synchronized(this) {
instance ?: AppViewModel().also { instance = it }
}
}
}
}
- استخدمنا خاصية
MutableState
في Compose لتشغيل تحديثات واجهة المستخدم في حالة تغيير البيانات. - يحتوي
MutableState
علىخريطة
لمعرفات الكائنات
والملاحظات،
والتي قمنا بتعبئتها بالبيانات. - للتأكد من وجود مثيل واحد فقط من
AppViewModel،
استخدمنا نمط المفرد.
يمكننا الآن الوصول إلى مثيل AppViewModel
في أنشطتنا عبر AppViewModel.getInstance()
.
النشاط الرئيسي
للمضي قدمًا، استبدل محتويات MainActivity.kt بالرمز التالي لعرض الملاحظات:
// app/src/main/java.<your_package_name>/MainActivity.kt
package <your.package.name>
import android.content.Context
import android.content.Intent
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.viewModels
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
import androidx.compose.material3.ExtendedFloatingActionButton
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
class MainActivity : ComponentActivity() {
private val viewModel = AppViewModel.getInstance()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val context = this as Context
setContent {
MainActivityContent(
viewModel = viewModel,
onNoteListItemClick = {
// TODO: Open note edit form
},
onNoteAddClick = {
// TODO: Open note create form
},
)
}
}
}
@Composable
fun MainActivityContent(
viewModel: AppViewModel,
onNoteListItemClick: (note: Note) -> Unit,
onNoteAddClick: () -> Unit,
) {
val notes = viewModel.notes.value
MaterialTheme {
Scaffold(
topBar = { TopAppBar(title = { Text("My Notes") }) },
floatingActionButton = {
ExtendedFloatingActionButton(
onClick = { onNoteAddClick() },
icon = { Icon(Icons.Filled.Add, contentDescription = "Add") },
text = { Text("Add") }
)
},
) { contentPadding ->
Box(modifier = Modifier.padding(contentPadding)) {
NoteList(notes, onNoteListItemClick = { onNoteListItemClick(it) })
}
}
}
}
@Composable
fun NoteListItem(note: Note, onNoteListItemClick: (note: Note) -> Unit) {
Row(
modifier = Modifier
.fillMaxWidth()
.clickable(onClick = { onNoteListItemClick(note) })
.padding(16.dp),
verticalAlignment = Alignment.CenterVertically,
) {
Text(text = note.icon, fontSize = 32.sp, modifier = Modifier.size(48.dp))
Spacer(modifier = Modifier.width(8.dp))
Column {
Text(text = note.title, fontSize = 18.sp)
Spacer(modifier = Modifier.height(4.dp))
Text(
text = note.content,
fontSize = 14.sp,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
}
}
}
@Composable
fun NoteList(notes: Map<String, Note>, onNoteListItemClick: (note: Note) -> Unit) {
LazyColumn {
items(notes.entries.toList()) { (_, note) ->
NoteListItem(note = note, onNoteListItemClick = onNoteListItemClick)
}
}
}
- يتم الآن جلب
الملاحظات
منAppViewModel
. - بدلًا من تحديد أحداث النقرات في مركبات، مررناها كوسائط.
- استخدمنا Compose لتصميم واجهة المستخدم. لجعلها أكثر سلاسة، قمنا بدمج
MaterialTheme
مع تخطيطالسقالة
.
إذا قمت بإعادة إنشاء التطبيق الآن، يجب أن ترى قائمة الملاحظات “المشفرة” على الشاشة.
نشاط نموذج الملاحظة
في هذا القسم، سنقوم بإضافة نشاط جديد يسمح للمستخدمين بإضافة ملاحظات وتعديلها.
ابدأ بإنشاء صنف جديد باسم FormActivity
بالمحتويات التالية:
// app/src/main/java.<your_package_name>/FormActivity.kt
package <your.package.name>
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Delete
import androidx.compose.material3.Button
import androidx.compose.material3.ExtendedFloatingActionButton
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.unit.dp
class FormActivity : ComponentActivity() {
private val viewModel = AppViewModel.getInstance()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val objectId = intent.getStringExtra("objectId")
val note = if (objectId !== null) viewModel.notes.value[objectId] else null
setContent {
FormActivityContent(
note,
onNoteAddClick = { icon: String, title: String, content: String ->
if (note !== null) return@FormActivityContent
val newNote = Note(
icon = icon,
title = title,
content = content,
)
newNote.objectId = Note.generateObjectId()
viewModel.notes.value += (newNote.objectId!! to newNote)
finish()
},
onNoteSaveClick = { icon: String, title: String, content: String ->
if (note === null) return@FormActivityContent
val updatedNote = note.copy()
updatedNote.icon = icon
updatedNote.title = title
updatedNote.content = content
viewModel.notes.value += (updatedNote.objectId!! to updatedNote)
finish()
},
onNoteDeleteClick = {
if (note === null) return@FormActivityContent
viewModel.notes.value = viewModel.notes.value.filter {
it.value.objectId != note.objectId
}
finish()
},
)
}
}
}
@Composable
fun FormActivityContent(
note: Note?,
onNoteAddClick: (icon: String, title: String, content: String) -> Unit,
onNoteSaveClick: (icon: String, title: String, content: String) -> Unit,
onNoteDeleteClick: () -> Unit,
) {
MaterialTheme {
Scaffold(
topBar = {
TopAppBar(title = { Text(note?.let { "Edit Note" } ?: ("Add Note")) })
},
floatingActionButton = {
if (note !== null) {
ExtendedFloatingActionButton(
onClick = { onNoteDeleteClick() },
icon = { Icon(Icons.Filled.Delete, "Delete") },
text = { Text("Delete") },
)
}
},
) { contentPadding ->
Box(modifier = Modifier.padding(contentPadding)) {
NoteForm(note = note, onNoteSave = { icon, title, content ->
if (note === null) {
onNoteAddClick(icon, title, content)
} else {
onNoteSaveClick(icon, title, content)
}
})
}
}
}
}
@Composable
fun NoteForm(
note: Note?,
onNoteSave: (icon: String, title: String, content: String) -> Unit
) {
var icon by remember { mutableStateOf(TextFieldValue(note?.icon ?: "")) }
var title by remember { mutableStateOf(TextFieldValue(note?.title ?: "")) }
var content by remember { mutableStateOf(TextFieldValue(note?.content ?: "")) }
Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp)
) {
TextField(
label = { Text(text = "Icon") },
value = icon,
onValueChange = { icon = it },
modifier = Modifier.fillMaxWidth()
)
Spacer(modifier = Modifier.height(16.dp))
TextField(
label = { Text(text = "Title") },
value = title,
onValueChange = { title = it },
modifier = Modifier.fillMaxWidth()
)
Spacer(modifier = Modifier.height(16.dp))
TextField(
label = { Text(text = "Content") },
value = content,
onValueChange = { content = it },
modifier = Modifier.fillMaxWidth()
)
Spacer(modifier = Modifier.height(16.dp))
Button(
onClick = { onNoteSave(icon.text, title.text, content.text) },
Modifier.fillMaxWidth()
) {
Text(text = "Save")
}
}
}
- يُستخدم هذا النموذج لكل من إضافة الملاحظات وتحريرها. لتحديد الإجراء، نقارن
معرف الكائن = = = لا شيء
. في حالة كانتفارغة،
فهو إجراء إضافة، وإلا فهو إجراء تحرير. - إذا كان
objectId !== فارغًا،
فإننا نجلبالملاحظة
من الحالة ونملأ النموذج. - لكي تعمل
MutableState
بشكل صحيح كان علينا التعامل مع محتوياتها على أنها غير قابلة للتغيير. لهذا السبب قمنا أحيانًا بنسخ المحتويات بدلًا من تعديلها. - لقد تعاملنا مع حالة نموذج التأليف عن طريق
mutableStateOf()
.
بعد ذلك، قم بتسجيل FormActivity
في أسفل التطبيق
في AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<application>
<!-- ... -->
<activity android:name=".FormActivity"/>
</application>
</manifest>
أخيرًا، أنشئ نية
جديدة على onNoteListItemClick
و onNoteAddClick
في MainActivity.kt:
// app/src/main/java.<your_package_name>/MainActivity.kt
class MainActivity : ComponentActivity() {
// ...
override fun onCreate(savedInstanceState: Bundle?) {
// ...
setContent {
MainActivityContent(
viewModel = viewModel,
onNoteListItemClick = {
// triggers the edit action, since `objectId` is provided
val intent = Intent(context, FormActivity::class.java)
intent.putExtra("objectId", it.objectId)
context.startActivity(intent)
},
onNoteAddClick = {
// triggers the add action, since no `objectId` is present
val intent = Intent(context, FormActivity::class.java)
context.startActivity(intent)
},
)
}
}
}
لا تنس استيراد النية
في أعلى الملف:
import android.content.Intent
إذا قمت بإعادة إنشاء التطبيق، ستلاحظ أن لدينا الآن تطبيقًا يعمل. يتيح لنا التطبيق إضافة الملاحظات وتعديلها وحذفها.
المشكلة الوحيدة هي أن إعادة تشغيل التطبيق يعيد ضبط حالته (إلى الملاحظات “المشفرة”).
في القسم التالي، سنقوم بتوصيل التطبيق بالواجهة الخلفية لتطبيق Back4app. سيسمح لنا ذلك باستمرار الحالة ومزامنتها بين أجهزة متعددة.
تثبيت Parse SDK
كما تعلم، يعتمد Back4app على منصة Parse. إذا أردنا التفاعل مع قاعدة بيانات Back4app أو Back4app بشكل عام، علينا تثبيت Parse SDK.
ابدأ بإضافة مستودع JitPack إلى settings.gradle:
// settings.gradle
pluginManagement {
repositories {
// ...
maven { url "https://jitpack.io" }
}
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
// ...
maven { url "https://jitpack.io" }
}
}
بعد ذلك، أضف حافظة Android Parse SDK إلى build.gradle الخاص بمستوى التطبيق :
// app/build.gradle
dependencies {
// ...
implementation "com.github.parse-community.Parse-SDK-Android:parse:4.2.0"
}
قم بمزامنة إعدادات Gradle وتأكد من عدم وجود أخطاء.
تكوين Parse SDK
للاتصال بالواجهة الخلفية لتطبيق Back4app، سيتعين عليك تزويد Parse SDK بمعرف التطبيق ومفتاح العميل. للحصول على بيانات الاعتماد الخاصة بك، انتقل إلى تطبيق Back4app الخاص بك واختر “إعدادات التطبيق > الأمان والمفاتيح” في الشريط الجانبي.
ثم أضفها إلى strings.xml الخاص بك هكذا:
<!-- app/src/main/res/values/strings.xml -->
<resources>
<string name="app_name">back4app-android-app</string>
<string name="back4app_server_url">https://parseapi.back4app.com/</string>
<string name="back4app_app_id">your_parse_app_id</string>
<string name="back4app_client_key">your_parse_client_key</string>
</resources>
تأكد من استبدال
your_parse_app_id
وyour_parse_client_client_key
ببيانات اعتمادك.
بعد ذلك، قم بتعديل AndroidManifest.xml لتمكين الوصول إلى الإنترنت وإرفاق البيانات الوصفية لبيانات الاعتماد:
<!-- app/src/main/AndroidManifest.xml -->
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<!-- these two permissions enable internet access -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<application>
<!-- ... -->
<!-- newly added metadata -->
<meta-data
android:name="com.parse.SERVER_URL"
android:value="@string/back4app_server_url" />
<meta-data
android:name="com.parse.APPLICATION_ID"
android:value="@string/back4app_app_id" />
<meta-data
android:name="com.parse.CLIENT_KEY"
android:value="@string/back4app_client_key" />
</application>
</manifest>
آخر شيء علينا القيام به هو تهيئة Parse. للتأكد من تهيئة Parse قبل أي أنشطة، سننشئ صنفًا جديدًا باسم App،
والذي يرث من صنف التطبيق
.
أنشئ App.kt وقم بتهيئة Parse هكذا :
// app/src/main/java/<your_package_name>/App.kt
package <your.package.name>
import android.app.Application
import com.parse.Parse
class App : Application() {
override fun onCreate() {
super.onCreate()
Parse.initialize(
Parse.Configuration.Builder(this)
.applicationId(getString(R.string.back4app_app_id))
.clientKey(getString(R.string.back4app_client_key))
.server(getString(R.string.back4app_server_url))
.build()
)
}
}
ثم قم بتسجيل فئة التطبيق
في AndroidManifest.xml:
<!-- app/src/main/AndroidManifest.xml -->
<application
android:name=".App"
...
>
<!-- ... -->
</application>
أعد إنشاء التطبيق مرة أخرى وتحقق من نافذة Logcat بحثًا عن أي أخطاء. إذا لم يكن هناك أي أخطاء فإن الاتصال ب Back4app قد نجح.
تحميل الملاحظات من Back4app
آخر شيء علينا القيام به قبل اكتمال تطبيقنا هو تحميل الملاحظات من قاعدة بيانات Back4app وإلقاء نظرة على كيفية استخدام Parse عملياً.
ابدأ بالانتقال إلى نموذج AppViewModel
. أزل البيانات من الخريطة وأضف مكوِّن البدء
:
// app/src/main/java/<your_package_name>/AppViewModel.kt
package <your.package.name>
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel
class AppViewModel : ViewModel() {
val notes: MutableState<Map<String, Note>> = mutableStateOf(mapOf())
init {
val query = com.parse.ParseQuery.getQuery<com.parse.ParseObject>("Note")
query.orderByDescending("createdAt")
query.findInBackground { notes, e ->
if (e == null) {
for (parseNote in notes) {
val note = Note(
objectId = parseNote.objectId,
icon = parseNote.getString("icon")!!,
title = parseNote.getString("title")!!,
content = parseNote.getString("content")!!,
)
this.notes.value += (note.objectId!! to note)
}
} else {
println("Error: ${e.message}")
}
}
}
companion object {
// ...
}
}
يستخدم هذا الرمز Parse SDK لجلب الملاحظات من قواعد البيانات، وتحويلها إلى فئة بيانات الملاحظات،
وحفظها على الخريطة.
بعد ذلك، أضف الطرق الثلاثة التالية إلى الملاحظة
:
// app/src/main/java/<your_package_name>/Note.kt
package <your.package.name>
import com.parse.ParseObject
import com.parse.ParseQuery
data class Note(
var objectId: String? = null,
var icon: String,
var title: String,
var content: String,
) {
fun addToParse(callback: (objectId: String) -> Unit) {
if (objectId !== null) throw Exception("Note is already saved to Parse!")
val parseNote = ParseObject("Note")
parseNote.put("icon", icon)
parseNote.put("title", title)
parseNote.put("content", content)
parseNote.saveInBackground {
if (it !== null) throw Exception("Error: ${it.message}")
objectId = parseNote.objectId
callback(parseNote.objectId)
}
}
fun updateToParse(callback: (objectId: String) -> Unit) {
if (objectId === null) throw Exception("Note hasn't been saved to Parse yet!")
val query = ParseQuery.getQuery<ParseObject>("Note")
val parseNote = query.get(objectId)
parseNote.put("icon", icon)
parseNote.put("title", title)
parseNote.put("content", content)
parseNote.saveInBackground {
if (it !== null) throw Exception("Error: ${it.message}")
callback(parseNote.objectId)
}
}
fun deleteFromParse(callback: () -> Unit) {
if (objectId === null) throw Exception("Note hasn't been saved to Parse yet!")
val query = ParseQuery.getQuery<ParseObject>("Note")
val parseNote = query.get(objectId)
parseNote.deleteInBackground {
if (it !== null) throw Exception("Error: ${it.message}")
callback()
}
}
}
- يضيف
AddToParse()
ملاحظة جديدة إلى خادم Parse بتفاصيلها. إذا نجحت، فإنها تخزن المعرف الفريد للملاحظة وتخطر عند الانتهاء. - يُحدِّث
updateToParse()
معلومات ملاحظة موجودة على خادم Parse. إذا نجحت، فإنها تشير إلى اكتمالها بعد إجراء التغييرات. - يزيل
الحذف من Parse()
ملاحظة محفوظة من خادم Parse. إذا نجحت، فإنها تؤكد الحذف عند الانتهاء.
أخيرًا، عدِّل طرائق النقر في FormActivity
لاستدعاء الطرائق المحددة حديثًا:
// app/src/main/java/<your_package_name>/NoteFormActivity.kt
class FormActivity : ComponentActivity() {
// ...
override fun onCreate(savedInstanceState: Bundle?) {
// ...
setContent {
FormActivityContent(
note,
onNoteAddClick = { icon: String, title: String, content: String ->
if (note !== null) return@FormActivityContent
val newNote = Note(
icon = icon,
title = title,
content = content,
)
newNote.addToParse {
viewModel.notes.value += (it to newNote)
finish()
}
},
onNoteSaveClick = { icon: String, title: String, content: String ->
if (note === null) return@FormActivityContent
val updatedNote = note.copy()
updatedNote.icon = icon
updatedNote.title = title
updatedNote.content = content
updatedNote.updateToParse {
viewModel.notes.value += (it to updatedNote)
finish()
}
},
onNoteDeleteClick = {
if (note === null) return@FormActivityContent
viewModel.notes.value = viewModel.notes.value.filter {
it.value.objectId != note.objectId
}
note.deleteFromParse {
finish()
}
},
)
}
}
}
هذا كل شيء!
يعمل التطبيق الآن بشكل كامل وتمت مزامنته مع الواجهة الخلفية ل Back4app. حاول التلاعب بالتطبيق عن طريق تغيير البيانات والتحقق مما إذا كانت التغييرات تنعكس في عرض قاعدة البيانات.
الخاتمة
في هذه المقالة، قمنا بنجاح ببناء واجهة خلفية للهاتف المحمول واتصلنا بها من تطبيق Android الخاص بنا. استخدمنا حل Back4app’s BaaS الخاص بـ Back4app للواجهة الخلفية، وفي الواجهة الأمامية، استخدمنا Kotlin مع Jetpack Compose.
بحلول الآن، يجب أن يكون لديك فهم جيد لكيفية عمل الخلفيات الخلفية للأجهزة المحمولة وأن تكون قادرًا على بناء خلفيتك الخاصة. اعرض الشيفرة المصدرية النهائية على مستودع back4app-android-appo.