دروس تطوير تطبيقات الأندرويد4
كيفية التأكد من صحة المدخلات باستخدام Regular Expressions وكيفية إظهار رسالة خطأ.سنقوم باستدعاء المكتبةimport java.util.regex.*;
وسنقوم في داخل المجموعة المجهولة الخاصة بزر الاتصال بعمل باستدعاء دالة validatePhoneNumber (سنقوم بكتابة محتواها بعد قليل) لتتحقق من البيانات التي قام بإدخالها المستخدم. والآن، عند استدعاء الدالة الخاصة بالزر (عند ضغط الزر) سنستخدم جملة if على الشكل التالي:callButton.setOnClickListener(new Button.OnClickListener() { public void onClick(View v) { if(validatePhoneNumber(phoneNumber.getText().toString())) { Intent callIntent = new Intent(Intent.ACTION_CALL,Uri.parse("tel:" + phoneNumber.getText())); callIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(callIntent); } else { showDialog(1); } }
بالنسبة لما ورد في جملة else، سنقوم بتجاهله حاليا.علينا الآن كتابة محتوى الدالة validatePhoneNumber على الشكل التالي: (وهي ستكون كدالة تابعة للمجموعة المجهولة Anonymous Class):private boolean validatePhoneNumber(String number) { Pattern phoneNumber1 = Pattern.compile("(\\d{2}-)?\\d{7}"); Matcher matcher = phoneNumber1.matcher(number); return matcher.matches(); }
عند استدعاء هذه الدالة، نستدعي بداية الدالة Pattern.compile التي تقوم بإنشاء رقم بناء على الصيغة التي عرفناها (وهناك قواعد عديدة لصيغ التحقق وقمت باختيار(\\d{2}-)?\\d{7}والتي تعني أن المستخدم يمكنه ادخال رقمين في البداية ووضع – بعدهم ومن ثم اكمال الرقم بسبعة أعداد. كما يحق له عدم ادخال الرقمين الأولين وعدم ادخال – ولكنه يجب أن يدخل سبعة أعداد. فمثلا الرقم 01-1234567 هو رقم صحيح، والرقم 1234567صحيح ولكن 1-1234567 والرقم 123456 هو غير صحيح.).تقوم الدالةmatcher(number);
بمقارنة الرقم المدخل من قبل المستخدم بالرقم المنشأ الذي يتبع الصيغة التي عرّفناها. تقوم الدالةvalidatePhoneNumber(...);
بإعادة صح أم خطأ True or Flase .المجموعة المجهولة الخاصة بالزر تصبح على النحو التالي:callButton.setOnClickListener(new Button.OnClickListener() { public void onClick(View v) { if(validatePhoneNumber(phoneNumber.getText().toString())) { Intent callIntent = new Intent(Intent.ACTION_CALL,Uri.parse("tel:" + phoneNumber.getText())); callIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(callIntent); } else { showDialog(1); } } private boolean validatePhoneNumber(String number) { Pattern phoneNumber1 = Pattern.compile("(\\d{2}-)?\\d{7}"); Matcher matcher = phoneNumber1.matcher(number); return matcher.matches(); } });
نتحول الآن الى كيفية إظهار رسالة خطأ والتي استدعيناها في جملة ال Else في الدالة السابقة عبر استدعاءshowDialog(1);
وهي دالة موجودة في مجموعة Activity التي يتبع لها تطبيقنا ككل. تقوم دالة أخرى موجودة في ال Activity أيضا وتسمىonCreateDialog(int id)
استقبال الطلب الذي أطلقته الدالة السابقةshowDialog(1)
استدعاء المكتبات والمجموعات التالية:import android.app.Dialog; import android.app.AlertDialog; import android.content.DialogInterface;
الآن كتابة محتوى الدالةonCreateDialog(int id)
بالشكل التالي:protected Dialog onCreateDialog(int id) { if (id == 1){ return new AlertDialog.Builder(AndroidPhoneDialer.this) .setTitle("Error") .setMessage("please enter a valid number") .setPositiveButton("OK", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { /* User clicked OK so do some stuff */ } }) .create(); } else { } }
ولاحظوا كيفية تحديد النص المراد عرضه. إمكانية عمل شيء معين في حال ضغط المستخدم زر ال OK في رسالة الخطأ. ولاحظوا أيضا رقم ١ في showDialog ويمكننا طبعا تمرير أرقام مختلفة لعرض رسائل مختلفة بحسب الحالة، وهذا يتم عبر If .اذا يصبح الملف المصدري ArdroidCaller.java كاملا:package android_programmers_guide.AndroidPhoneDialer; import android.app.Activity; import android.os.Bundle; import android.content.Intent; import android.net.Uri; import android.widget.Button; import android.widget.EditText; import android.view.View; import java.util.regex.*; import android.app.Dialog; import android.app.AlertDialog; import android.content.DialogInterface; public class ArdroidCaller extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); final EditText phoneNumber = (EditText) this.findViewById(R.id.phoneNumber); final Button callButton = (Button) this.findViewById(R.id.callButton); callButton.setOnClickListener(new Button.OnClickListener() { public void onClick(View v) { if(validatePhoneNumber(phoneNumber.getText().toString())) { Intent callIntent = new Intent(Intent.ACTION_CALL,Uri.parse("tel:" + phoneNumber.getText())); callIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(callIntent); } else { showDialog(1); } } private boolean validatePhoneNumber(String number) { Pattern phoneNumber1 = Pattern.compile("(\\d{2}-)?\\d{7}"); Matcher matcher = phoneNumber1.matcher(number); return matcher.matches(); } }); } protected Dialog onCreateDialog(int id) { return new AlertDialog.Builder(AndroidPhoneDialer.this) .setTitle("Error") .setMessage("please enter a valid number") .setPositiveButton("OK", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { } }) .create(); } }
استخدام زر القائمة Menu وكيفية اضافة خيارات لهما سنقوم بعمله بكل بساطة هو انشاء المشروع التالي:والذي سيقوم باستخدام زر القائمة لعرض محتوياتها، ولكل خيار، سنقوم بعمل نشاط Activity معين. اذا سنبدأ بكيفية توظيف زر القائمة.نقوم بداية باستدعاء المكتبات التالية:import android.view.Menu; import android.view.MenuItem;
ومن ثم نقوم بإعادة كتابة Override الدالة الموجودة في مجموعة Activity والمسماة onCreateOptionsMenu على النحو التالي:@Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); menu.add(0, 0, 0, "Act1"); menu.add(0, 1, 0, "Act2"); return true; }
الدالة menu.add لها عدة أشكال ولكننا سنستعمل:add (int groupId, int itemId, int order, CharSequence title)
حيث أن أول عنصر يدل على رقم المجموعة الخاصة بخيارات القوائم، وافترضت أنهم في مجموعة واحدة، لذلك قمت بوضع 0 عند استدعاء الدالة كما هو الحال في عنصر order حيث أنني لا أهتم بترتيب الخيارات. itemId هو ما يهمني لذلك استخدمت الترقيم لمعرفة هوية الخيار.الدالة onCreateOptionsMenu تقوم بتعبئة الخيارات في القائمة عند تشغيل البرنامج. لذلك، سنقوم بإعادة كتابة دالة أخرى موجودة في Activity والتي يتم استدعاؤها بمجرد اختيار أي خيار في القائمة وهي onOptionsItemSelected. في هذه الدالة، سنستخدم Switch المعروفة وذلك لاطلاق النشاط المقترن بالخيار الذي اختير من قبل المستخدم على النحو التالي:public boolean onOptionsItemSelected (MenuItem item) { switch (item.getItemId()) { case 0: return true; case 1: return true; } return true; }
الشكل النهائي لملف:package android.programming.series.ArdroidMultiActs; import android.app.Activity; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; public class ArdroidMultiActs extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } @Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); menu.add(0, 0, 0, "Act1"); menu.add(0, 1, 0, "Act2"); return true; } public boolean onOptionsItemSelected (MenuItem item) { switch (item.getItemId()) { case 0: return true; case 1: return true; } return true; } }
كيفية عمل تطبيق متعدد الأنشطةلنتذكر قضية مهمة وهي أن كل نشاط له ملف مصدري .java وله ملف .xml خاص بتصميمه. وهذا ما سنفعله. سنقوم بإنشاء ملف xml للنشاط الأول تحت اسم act1.xml في res/layout وليكن كالتالي:<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_height="fill_parent" android:layout_width="fill_parent" android:padding="30dip" android:background="#8123f555" > <AutoCompleteTextView android:id="@+id/act1Test" android:layout_width="fill_parent" android:layout_height="wrap_content" /> </LinearLayout>
ثم نقوم بإنشاء ملف Act1.java داخل ال Package في src. المطلوب من النشاط هو عرض مربع النص التلقائي وهو الذي يقوم باقتراح عدة خيارات للمستخدم (نقوم بتحديدها مسبقا) ليكمل عنه الكلمة بدلا من كتابتها كاملة. سنقوم بوضع ما يلي في الملف:package android.programming.series.ArdroidMultiActs; import android.app.Activity; import android.os.Bundle; import android.widget.ArrayAdapter; import android.widget.AutoCompleteTextView; public class Act1 extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.act1); //android.R.layout.simple_dropdown_item_1line is an existing file that contains a style of presenting the list in the application ArrayAdapter<String> monthArray = new ArrayAdapter<String>(this,android.R.layout.simple_dropdown_item_1line,months); final AutoCompleteTextView textView = (AutoCompleteTextView) findViewById(R.id.act1Test); textView.setAdapter(monthArray); } static final String[] months = new String[] {"January","February","March", "April","May", "June","July","August","September","October","November", "December"}; }
بالنسبة للنشاط الثاني، نقوم بإنشاء ملف act2.xml :<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_height="fill_parent" android:layout_width="fill_parent" > <CheckBox android:id="@+id/act2CheckBox" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Act2 checkbox" /> <Button android:id="@+id/act2ColorButton" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Change Text Color" /> </LinearLayout>
والنشاط الثاني يقوم بعرض Check Box وزر خاص بتغيير لون النص. نقوم بوضع الكود التالي في Act2.java:package android.programming.series.ArdroidMultiActs; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.graphics.Color; import android.widget.CheckBox; public class Act2 extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.act2); final CheckBox checkbox = (CheckBox) this.findViewById(R.id.act2CheckBox); final Button changeButton = (Button) this.findViewById(R.id.act2ColorButton); changeButton.setOnClickListener(new Button.OnClickListener(){ public void onClick(View v) { changeColor(checkbox); } public void changeColor(CheckBox checkbox) { checkbox.setTextColor(Color.RED); } } ); } }
نعود الآن الى ملف ArdroidMultiActs.java لنضيف ما يلي لجملة ال Switch:public boolean onOptionsItemSelected (MenuItem item) { switch (item.getItemId()) { case 0: showAct1(); return true; case 1: showAct2(); return true; } return true; }
ونقوم الآن بكتابة الدالتين showAct1 و showAct2. مفهوم النوايا Intents:“النوايا Intents بكل بساطة هي وسيلة لتمرير المعلومات من نشاط لآخر وبكلمات أخرى، تمرير ما ينوي فعله المبرمج بين الأنشطة. ولكنها تستخدم فقط في حالة وددنا استخدام نشاط خارج التطبيق الذي نعمل عليه. مثلا، اذا أراد المبرمج من تطبيقه أن يأخذ كلمة معينة من المستخدم ليبحث عنها بين ملفات النظام فإنه سيقوم بتصميم نشاط تحتوي واجهته على حقل نصي يمكن للمستخدم الكتابة فيها، وما يتم ادخاله يتم تمريره الى نظام الأندرويد تحت نية عمل بحث في ملفات النظام (وال Intent اسمه في هذه الحالة: SEARCH_ACTION) الذي يستقبل الطلب ويفهم النية\المعلومة المرغوب تحقيقها ويستدعي بدوره نشاط البحث Search Activity. نلاحظ أن النية تم تمريرها الى نشاط خارج التطبيق، وهو نشاط يقوم عليه نظام التشغيل. بالنسبة للأنشطة التي ذكرتها في معرض حديثي عن تطبيق الرسائل النصية، فهي أنشطة داخل التطبيق الواحد ولا يتم استخدام مفهوم النوايا Intents عليهاوهذا غير صحيح بشكل كامل حقيقة. النوايا يمكن استخدامها داخل التطبيق الواحد، ويتم استدعاء الأنشطة المختلفة باستخدام هذا المفهوم، ولكن الذي كنت أقصده بما ذكرت في الأعلى هو عدم امكانية استخدام النوايا المعرفة مسبقا ك SEARCH_ACTION وغيرها لاستدعاء نشاط داخلي، بل يجب علينا تعريف نوايا خاصة بتطبيقنا. وهذا ما سنقوم به في داخل الدالتين أعلاه على النحو التالي:public void showAct1() { Intent autocomplete = new Intent(this, Act1.class); startActivity(autocomplete); } public void showAct2() { Intent autocomplete2 = new Intent(this, Act2.class); startActivity(autocomplete2); }
يصبح ملف ArdroidMultiActs.java كاملا:package android.programming.series.ArdroidMultiActs; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; public class ArdroidMultiActs extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } @Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); menu.add(0, 0, 0, "Act1"); menu.add(0, 1, 0, "Act2"); return true; } public boolean onOptionsItemSelected (MenuItem item) { switch (item.getItemId()) { case 0: showAct1(); return true; case 1: showAct2(); return true; } return true; } public void showAct1() { Intent autocomplete = new Intent(this, Act1.class); startActivity(autocomplete); } public void showAct2() { Intent autocomplete2 = new Intent(this, Act2.class); startActivity(autocomplete2); } }
يبقى لدينا إضافة ما يسمى Intents Filter وهو عبارة عن كود XML يتم وضعه في ArdroidMultiActs Manifest ومهمته تمرير النوايا الى لنشاط المقترن بها وتمييزها عن الآخرين بشكل صحيح. نقوم بإضافة ما يلي:<activity android:name=".Act1" android:label="activity 1"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".Act2" android:label="activity 2"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity>
ليصبح الملف كاملا:<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android.programming.series.ArdroidMultiActs" android:versionCode="1" android:versionName="1.0"> <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name=".ArdroidMultiActs" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".Act1" android:label="activity 1"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".Act2" android:label="activity 2"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> <uses-sdk android:minSdkVersion="6" /> </manifest>
نقوم بتشغيل التطبيق لنحصل على:
الاشتراك في:
تعليقات الرسالة
(
Atom
)