أرشيف لـ6 يونيو, 2013

50 : اندرويد : اعادة استخدام التنسيقات عبر استخدام include tag

facebook-group

 

ملاحظة : الموضوع عبارة عن حلقة من حلقات سلسلة برمجة وتطوير اندرويد Android Development

اندرويد :   اعادة استخدام التنسيقات عبر استخدام <include/>

السلام عليكم ورحمة الله وبركاته

سوف تتعلم ضمن هذا الدرس مايلي :

  1. انشاء تنسيق قابل لاعادة الاستخدام
  2. استخدام تاغ <include>
  3. استخدام تاغ <merge>

يجب ان تطلع ايضا على

بالرغم من ان اندرويد يزودنا بمجموعة متنوعة من ال widgets التي تحوي على مجموعة كبيرة من العناصر تفاعلية الصغيرة والقابلة لاعادة الاستخدام, ولكنك قد تحتاج إلى اعادة استخدام مكونات اكبر والتي تتطلب تنسيقا خاصا.

لكي تستطيع ان تعيد استخدام تنسيقات كاملة بشكل فعالي, بامكانك استخدام كل من تاغي <include/>  و <merge/> وذلك بهدف تضمين تنسيق ضمن التنسيق الحالي.

إن اعادة استخدام التنسيقات عملية فعالة جدا , وتمكنك من انشاء تنسيقات معقدة وقابلة لاعادة الاستخدام.

على سبيل المثال, لوحة panel تحوي على زر (yes/no) , او شرط تقدم progress bar مع توصيف نصي.

هذا يعني ايضا بانه أي عنصر من عناصر تطبيقك سيكون متعارف عليه عبر التنسيقات المتعددة , ويمكن استخلاصه ومعالجته بشكل منفصل, ومن ثم تضمينه في كل تنسيق.

اذن , بما اك تستطيع انشاء عناصر واجهة مستخدم مستقلة عبر كتابة views بحسب رغبتك, فإنه بإمكانك بشكل اسهل ان تقوم باعادة استخدام ملف التنسيقات.

إنشاء تنسيق قابل لاعادة الاستخدام Re-usable Layout

في حال كنت تعرف مسبقا التنسيق الذي ترغب باعادة استخدامه, انشأ ملف xml جديد وعرف التنسيق.

على سبيل المثال, فيما يلي تنسيق من   G-Kenya codelab, يقوم هذا التنسيق بتعريف شريط عنوان title bar  لكي يتم تضمينه ضمن كل فعالية (titlebar.xml):

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width=”match_parent”
    android:layout_height="wrap_content"
    android:background="@color/titlebar_bg">

    <ImageView android:layout_width="wrap_content"
               android:layout_height="wrap_content" 
               android:src="@drawable/gafricalogo" />
</FrameLayout>

استخدام تاغ <include/>

ضمن التنسيق الذي ترغب في ان تضيف إليه العنصر القابل لاعادة الاستخدام, اضف تاغل <include/>

على سبيل المثال, فيما يلي تنسيق من  G-Kenya codelab يقوم بتضمين شريط العنوان title bare من التنسيق اعلاه:

فيما يلي ملف التنسيق:

 

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" 
    android:layout_width=”match_parent”
    android:layout_height=”match_parent”
    android:background="@color/app_bg"
    android:gravity="center_horizontal">

    <include layout="@layout/titlebar"/>

    <TextView android:layout_width=”match_parent”
              android:layout_height="wrap_content"
              android:text="@string/hello"
              android:padding="10dp" />

    ...

</LinearLayout>

بإمكانك ايضا ان تقوم ب Override  لكل المعاملات (أي واحدة من الخصائص التي من النمط android:layout_*) للتنسيق المضمن عبر تحديد هذه الخصائص ضمن تاغ <include/>. على سبيل المثال:

<include android:id=”@+id/news_title”
         android:layout_width=”match_parent”
         android:layout_height=”match_parent”
         layout=”@layout/title”/>

على كل الاحوال , في حال رغبت بالقيام ب override لخاصية من خصائص ال layout ضمن تاغ <include> , فإنه يتوجب عليك ان تقوم ب override  لكل من android:layout_height  و android:layout_width  لكي تتاثر بقية الخصائص بشكل فعلي.

استخدام تاغ <merge>

   تساعدك تاغ <merge/>  لازالة ال view groups  المتكررة ضمن هرمية ال views وذلك عندما تضمن احد التنسيقات ضمن تنسيق اخر.

مثلا اذا كان لدينا تنسيق ما محاط ب linearlayout ورغبنا بتضمينه ضمن تنسيق اخر محاط ايضا ب linearlayout عندها فإن تكرار التنسيق الخطي لن يفيدنا بشيء سوى تبطيء الاداء.

لذلك نستخدم <merge> لنتجاوز هذه المشكلة, حيث نضع تاغ <merge> عنصر root ضمن التنسيق القابل لاعادة الاستخدام , وذلك بدل من التنسيق الخطي linearlayout, كما يلي:

<merge xmlns:android="http://schemas.android.com/apk/res/android">

    <Button
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content"
        android:text="@string/add"/>

    <Button
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content"
        android:text="@string/delete"/>

</merge>

الآن , وعند تضمين هذا التنسيق ضمن التنسيق الاساسي ( عبر استخدام تاغ <include/>), فإن النظام يتجاهل عنصر <merge> ويضع العناصر الموجودة ضمنه (الازرار) ضمن التنسيق الاساسي .

وبهذه المعلومات المفيدة ننهي حلقة اليوم

وإلى لقاء في حلقة قريبة , وإلى ذلك الحين استودعكم الله والسلام عليكم ورحمة الله وبركاته.

Advertisements

, , , , , , , , ,

أضف تعليق

49 : اندرويد : امثلة هرمية التنسيقات optimizing Layout Hierarchies

 

ملاحظة : الموضوع عبارة عن حلقة من حلقات سلسلة برمجة وتطوير اندرويد Android Development

اندرويد :   امثلى هرمية التنسيقات Optimizing Layout Hierarchies

السلام عليكم ورحمة الله وبركاته

 نتعلم في هذا الدرس مايلي:

  1. فحص تنسيقك Inspect Your Layout
  2. تنقيح تنسيقك Revise Your Layout

يجب ان تقرأ ايضا

يسود اعتقاد خاطىء بان استخدام بنى التنسيقات الاساسية تقود إلى افضل اداء فعال لهذه التنسيقات.

على كل الاحوال, إن كل تنسيق او widget تضيفه إلى تطبيقك يتطلب تهيئة initialization  , تنسيق layout, ورسم drawijng.

على سبيل المثال, ان الاستخدام المتعشش لمستنسخات من تنسيقات من نمط LinearLayout قد تقود إلى هرمية عميقة لل views بشكل مفرط.

علاوة على ذلك , إن تعشيش عدة مستنسخات من LinearLayout التي تستخدم معامل layout_weight قد تكون مكلفة وخصوصا لان كل ابن يحتاج لا، يتم قياسه مرتين. هذا الموضوع مهم جدا خصوصا عندما يكون من المتطلب ان يتم القيام ب inflated للتنسيق بشكل متكرر, على سبيل المثال عندما تستخدم ListView او GridView.

سوف نتعلم ضمن هذا الرس عن كيفية استخدام Hierarchy Viewer و Layoutopt  لتفحص وتقوم بامثلة لتنسيقك.

فحص تنسيقك Inspect Your Layout

 تتضمن ادوات android SDK اداة تدعى Hierarchy Viewerوهي بدورها تمكنك من تحليل تنسيقك اثناء عمل تطبيقك.يساعدك استخدام هذه الاداة على اكتشاف نقط الضعف في اداء تنسيقك.

يعمل Hierarchy Viewerعبرالسماح لك باختيار اجرائيات قيد العمل على جهاز موصول او على المحاكي, ومن ثم يعرض لك شجرة التنسيقlayout tree. الاشارات الضوئية على كل كتلة تمثل اداء قياساتها, تنسيقها ورسمها, وتساعدك في اكتشاف بعض نقاط الضعف المحتملة.

على سبيل المثال, الصورة رقم 1 عبارة عن تنسيق يستخدم بمثابة عنصر ضمن listView.يظهر هذا التنسيق صورة صغيرة على اليسار ووعنصرين متجاورين نصيين على اليمين.

من المهم جدا – فيما يخص التنسيقات التي يجري القيام ب inflated لها عدة مرات (كما في المثال التالي)- ان تتم امثلتها لان فوائد الاداء هنا سوف تتضاعف(نتيجة تكرار العملية).

الشكل 1 : شكل لتنسيق يشكل عنصر ضمن ListView

الشكل 1 : شكل لتنسيق يشكل عنصر ضمن ListView

تتوافر اداة hierarchyviewer  ضمن <sdk>/tools/.

عند فتح هذه الاداة, سوف تظهر Hierarchy Viewer لقائمة من الاجهزة المتاحة ومكوناتها التي تعمل.

انقر على Load View Hierarchy لتستعرض هرمية التنسيقات للعنصر الذي تم اختياره.

على سبيل المثال, الشكل 2 , يبين التنسيق الخاص بعنصر القائمة الذي تم توضيحه في الشكل 1.

الشكل 2 : هرمية التنسيق للعنصر في الشكل 1 , باستخدام مستنسخات متعششة من LinearLayout

الشكل 2 : هرمية التنسيق للعنصر في الشكل 1 , باستخدام مستنسخات متعششة من LinearLayout

الشكل3 : بالنقر على عقدة من الهرمية , سوف يظهر لنا ارقام تدل على  الاداء.

الشكل3 : بالنقر على عقدة من الهرمية , سوف يظهر لنا ارقام تدل على الاداء.

في الشكل 2, بإمكانك ان ترى 3 مستويات من الهرمية مع مشاكل في محاذاة وتنسيق العناصر النصية.

بالنقر على هذه العناصر تظهر لنا الاوقات التي استهلكتها في كل مرحلة من مراحل الاجرائية (الشكل 3).

يصبح من الجلي ماهي العناصر التي تستلهك وقتا اكثر من غيرها في كل من القياس , التنسيق والتوضع , الاكساء render, وبذلك تعرف ماهي المواضع التي تحتاج إلى امثلة ضمن تنسيقك.

الاوقات اللازمة للقيام ب rendering لكامل عنصر القائمة ضمن التنسيق هي التالي :

  • Measure: 0.977ms
  • Layout: 0.167ms
  • Draw: 2.717ms

تنقيح تنسيقك Revise Your Layout

بما ان اداء التنسيق اعلاه يبين لنا انحطاطا يعزى إلى التنسيقات LinearLayout المتعششة, قد يتحسن الاداء عبر القيام بتسطيح flattening التنسيق ( أي جعله سطحيا واقل عمقا واعرض , وهذا افضل من كونه ضيق واعمق).

 عند استخدام التنسيق النسبي relativeLayout على انه العقدة الجذر لهذا التنسيق, عندها يصبح بإمكانك ان ترى بان مستوى الهرمية قد انخفض إلى مستويين.

وسيظهر استكشاف التنسيق عبر الاداة بالشكل ادناه.

الشكل 4 : التنسيق الهرمي للشكل 1 , باستخدام التنسيق النسبي.

الشكل 4 : التنسيق الهرمي للشكل 1 , باستخدام التنسيق النسبي.

اوقات الrendering  الجديدة هي التالية :

  • Measure: 0.598ms
  • Layout: 0.110ms
  • Draw: 2.146ms

قد يبدوا هذا التحسين صغيرا نسبيا, ولكن هذا الوقت يضاعف عدة مرات لان هذا التنسيق يعاد استخدامه بالنسبة لكل عنصر من عناصر ال list.

تعزى هذه الفروقات في الوقت إلى استخدام layout_weight ضمن التنسيق الخطي LinearLayout, والتي بدورها تبطى من سرعة القياس.

ما مضى كان مثالا بسيطا يبين لنا كيف ان لكل تنسيق الاستخدام الامثل له , ويتوجب عليك ان تاخذ بعين الاعتبار فيما اذا كان استخدام خاصية weight  ضرورية ام لا.

وإلى لقاء قريب في درس لاحق

وإلى ذلك الحين استودعكم الله والسلام عليكم ورحمة الله وبركاته

, , , , , , , ,

أضف تعليق

48 : اندرويد : تحسين اداء التنسيق Improving Layout Performance

 

ملاحظة : الموضوع عبارة عن حلقة من حلقات سلسلة برمجة وتطوير اندرويد Android Development

اندرويد :   تحسين اداء التنسيق Improving Layout Preformance

السلام عليكم ورحمة الله وبركاته

 المتطلبات

  • نسخة Android 1.5  ( API Level 3) او اعلى

يجب ايضا الاطلاع على

تعتبر التنسيقات layouts جزء اساسي من تطبيق اندرويد , والتي تؤثر بشكل مباشر على تجربة المستخدم.

في حال قمت بتنجيز تنسيقات بشكل ضعيف, عندها قد يقود تنسيقك إلى استهلاك مخيف للذاكرة مع واجهات بطيئة.

يتضمن android SDK اداوت تساعدك لتحديد المشاكل التي تظهر ضمن اداء التنسيقات, والتي عند استفادتك منها مع ما سوف نتعرض له ضمن هذه الدروس , سوف تصبح قادرا على بناء واجهات جيدة مع اقل استهلاك ممكن للذاكرة.

الدروس القادمة تتضمن مايلي:

  1. امثلة هرمية التنسيقاتOptimizing Layout Hierarchies
  • إن صفحات الويب المعقدة تبطأ زمن التحميل, كذلك ايضا في حال كان ا لتنسيق لديك معقدا جدا فإنه قد يؤدي إلى مشاكل في الاداء. يبين لنا هذا الدرس كيف بامكاننا استخدام ادوات SDK لنستكشف ونعاين عبرها تنسيقاتنا ونكتشف مشاكل الاداء التي قد تكمن فيها.
  1. اعادة استخدام التنسيقات عبر استخدام <include/>
  • في حال كانت واجهات تطبيقك تكرر بعض بنى التنسيقات في عدة اماكن, فإن هذا الدرس يبين لك كيفك تبني بنى تنسيقات layout constructs تتميز بالفعالية واعادة الاستخدام , وبذلك يصبح بإمكانك تضمينهم ضمن واجهات المستخدم المناسبة للتنسيقات.
  1. تحميل ال views فقط عند الطلب
  • قد تحتاج في بعض الاحيان ان تقوم باظهار تنسيق معين فقط عند الجاجة, وفي بعض الاحيان فور تشغيل الفعالية. يبين لنا هذا الدرس كيف بإمكانا تحسين الاداء الابتدائي للتنسيقات عبر تحميل اجزاء من التنسيق بحسب الطلب
  1. جعل الانزلاق ضمن ListView سلس smooth
    • في حال كنت قد قمت بإنشاء مستنسخ من listView يحوي على محتويات ثقيلة او معقدة في كل عنصر من عناصر ال list, عندها قد يصبح اداء هذه القائمة ليس بالمستوى المتوقع.
    •  يزودنا هذا الدرس بملاحظات عن كيفية تحسي اداء هذه القوائم.

وإلى لقاء قريب في درس لاحق

وإلى ذلك الحين استودعكم الله والسلام عليكم ورحمة الله وبركاته

, , , , , , ,

أضف تعليق

47 : اندرويد : الحفاظ على التوافقية مع الاصدارات القديمة Remaining Backward Compatible

 

ملاحظة : الموضوع عبارة عن حلقة من حلقات سلسلة برمجة وتطوير اندرويد Android Development

اندرويد :   الحفاظ على التوافقية مع الاصدارات القديمة Remaining Backward Compatible

السلام عليكم ورحمة الله وبركاته

 سوف نتعلم ضمن هذا الدرس مايلي:

  1. تحديد الحد الادنى المستهدف من مستويات API
  2. تزويد صندوق البحث للاجهزة القديمة
  3. التحقق من Android Build Version  في زمن التنفيذ

إن كل من عنصر وشريط الاحداث action bar  متوافران فقط منذ الاصدار 3.0 لاندرويد فما اعلى.

لكي ندعم منصات العمل القديمة, بإمكاننا العودة لاستخدام صندوق البحث search dialog.

إن صندوق البحث search dialog  عبارة عن واجهة مستخدم مزودة من قبل النظام , والتي تتوضع في اعلى التطبيق عند استدعائها.

تحديد الحد الادنى المستهدف من مستويات API

لكي نعد صندوق البحث search dialog  , يجب في البداية ان نصرح ضمن ملف ال manifest – عن الترميز ادناه – في التطبيقات التي ترغب بان تدعم الاجهزة القديمة , (وكذلك الاصدارات اللاحقة للاصدار 3.0).

عندما تقوم بذلك, يقوم تطبيقك بشكل اوتوماتيكي باستخدام شريط الاحداث action bar ضمن اندرويد 3.0 او اعلى , ويستخدم نظام القائمة التقليدي traditional menu system  على الاجهزة القديمة.

<uses-sdk android:minSdkVersion="7" android:targetSdkVersion="15" />

<application>
...

تزويد الاجهزة القديمة بصندوق البحث Provide the Search Dialog for Older Devices

لكي تقوم باستدعاء صندوق البحث على الاجهزة القديمة , قم باستدعاء التابع onSearchRequested() في  كل مكان يقوم به السمتخدم باختيار عنصر القائمة المخصص للبحث من خيارات القائمة.

وبما ان اندرويد ذو الاصدار 3.0 فما اعلى يظهر SearchView  في شريط الاحداث action bar(كما تم توضيحه في بداية الدرس), لذلك فإن الاصدارات الاقدم من 3.0 سوف تستدعي التابع onOptionsItemSelected()عندما يختار المستخدم عنصر البحث من القائمة.

 

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case R.id.search:
            onSearchRequested();
            return true;
        default:
            return false;
    }
}

التحقق من Android Build Version  في زمن التنفيذ

في زمن التنفيذ, تحقق من نسخة الجهاز لتتاكد من عدم حصول استخدام غير مدعوم ل SearchView على الاجهزة القديمة.

في الترميز التالي , يتم ذلك عبر التابع onCreateOptionsMenu() :

 

@Override
public boolean onCreateOptionsMenu(Menu menu) {

    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.options_menu, menu);

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
        SearchManager searchManager =
                (SearchManager) getSystemService(Context.SEARCH_SERVICE);
        SearchView searchView =
                (SearchView) menu.findItem(R.id.search).getActionView();
        searchView.setSearchableInfo(
                searchManager.getSearchableInfo(getComponentName()));
        searchView.setIconifiedByDefault(false);
    }
    return true;
}

 وبهذا القدر ننهي هذه اللمحة عن امكانية البحث ضمن اندرويد , وإلى لقاء قريب ضمن موضوع اخر من السلسلة المترجمة حول اندرويد

وإلى ذلك الحين استودعكم الله والسلام عليكم ورحمة الله وبركاته.

, , , , ,

أضف تعليق

46 : اندرويد : تخزين المعطيات والبحث ضمنها Storing and Searching for Data

 

ملاحظة : الموضوع عبارة عن حلقة من حلقات سلسلة برمجة وتطوير اندرويد Android Development

اندرويد :   تخزين المعطيات والبحث ضمنها  Storing and Searching for Data

السلام عليكم ورحمة الله وبركاته

 سوف نتعلم ضمن هذا الدرس ما يلي:

  1. إنشاء الجدول الافتراضي Create the Virtual Table
  2. تعبئة الجدول الافتراضي بالمعطيات Populate the Virtual Table
  3. البحث عن الاستعلام Search for the Query

هنالك عدة طرق لكي تخزن بها معطياتك, مثل تخزينها ضمن قاعدة معطيات اونلاين online database , او ضمن قاعدة معطيات محلية local SQLite database, او حتى ضمن ملف نصي.

القرار راجع لك لكي تقرر الحل الافضل الذي يناسب تطبيقك.

ضمن هذا الدرس سوف نبين لك كيف تنشأ جدول SQLite  افتراضي , الذي بدوره يستطيع ان يزودك بآليات بحث نصية قوية ومتكاملة.

يتم ملأ الجدول بالمعطيات من ملف نصي يحوي على ثنائيات من  “كلمة ” و”تعريفها” ضمن كل سطر من اسطر الملف.

إنشاء الجدول الافتراضي Create the Virtual Table

يتصرف الجدول الافتراضي بشكل مشابه لجدول SQLite, ولكنه يقرأ ويكتب الاغراض ضمن الذاكرة عبر الاستدعاءات callbacks, بدل من كتابتها او قرائتها ضمن ملف قاعدة المعطيات.

لكي ننشأ جدول افتراضي, نقوم بإنشاء صف لهذا الجدول:

public class DatabaseTable {
    private final DatabaseOpenHelper mDatabaseOpenHelper;

    public DatabaseTable(Context context) {
        mDatabaseOpenHelper = new DatabaseOpenHelper(context);
    }
}

أنشأ صف داخلي ضمن الصف DatabaseTable, الذي بدوره يقوم ب extends  للصف SQLiteOpenHelper.

يقوم الصف SQLiteOpenHelper يتعريف التوابع المجردة  abstract methods  التي يتوجب عليك ان تقوم ب Override  لها , وبذلك يصبح بالامكان انشاء جدولك الافتراضي وتحديثه عند الحاجة.

على سبيل المثال, فيما يلي بعض الرماز الذي يقوم بالتصريح عن جدول لقاعدة المعطيات الذي بدوره سوف يحوي على كلمات لتطبيق القاموس:

public class DatabaseTable {

    private static final String TAG = "DictionaryDatabase";

    //The columns we'll include in the dictionary table
    public static final String COL_WORD = "WORD";
    public static final String COL_DEFINITION = "DEFINITION";

    private static final String DATABASE_NAME = "DICTIONARY";
    private static final String FTS_VIRTUAL_TABLE = "FTS";
    private static final int DATABASE_VERSION = 1;

    private final DatabaseOpenHelper mDatabaseOpenHelper;

    public DatabaseTable(Context context) {
        mDatabaseOpenHelper = new DatabaseOpenHelper(context);
    }

    private static class DatabaseOpenHelper extends SQLiteOpenHelper {

        private final Context mHelperContext;
        private SQLiteDatabase mDatabase;

        private static final String FTS_TABLE_CREATE =
                    "CREATE VIRTUAL TABLE " + FTS_VIRTUAL_TABLE +
                    " USING fts3 (" +
                    COL_WORD + ", " +
                    COL_DEFINITION + ")";

        DatabaseOpenHelper(Context context) {
            super(context, DATABASE_NAME, null, DATABASE_VERSION);
            mHelperContext = context;
        }

        @Override
        public void onCreate(SQLiteDatabase db) {
            mDatabase = db;
            mDatabase.execSQL(FTS_TABLE_CREATE);
        }

        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            Log.w(TAG, "Upgrading database from version " + oldVersion + " to "
                    + newVersion + ", which will destroy all old data");
            db.execSQL("DROP TABLE IF EXISTS " + FTS_VIRTUAL_TABLE);
            onCreate(db);
        }
    }
}

تعبئة الجدول الافتراضي Populate the Virtual Table

الجدول الآن بحاجة لمعطيات ليقوم بتخزينها.

الترميز التالي يبين لك كيف بإمكانك ان تقوم بالقراءة من ملف نصي (located in res/raw/definitions.txt)  يحوي على الكلمات وتعريفاتها, كيفية المرور على الملف , وكيفية ادخال كل سطر من اسطر الملف كسطر ضمن الجدول الافتراضي.

يتم انجاز ذلك كله ضمن thread اخر وذلك لمنع حجب وقفل واجهة المستخدم UI locking.

اضف الرماز التالي إلى الصف الداخلي DatabaseOpenHelper .

ملاحظة : قد ترغب ايضا استدعاء callback لتنبيه واجهات المستخدم الخاصة بفعاليتك عند انتهاء هذا ال thread  من عمله.

private void loadDictionary() {
        new Thread(new Runnable() {
            public void run() {
                try {
                    loadWords();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }).start();
    }

private void loadWords() throws IOException {
    final Resources resources = mHelperContext.getResources();
    InputStream inputStream = resources.openRawResource(R.raw.definitions);
    BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));

    try {
        String line;
        while ((line = reader.readLine()) != null) {
            String[] strings = TextUtils.split(line, "-");
            if (strings.length < 2) continue;
            long id = addWord(strings[0].trim(), strings[1].trim());
            if (id < 0) {
                Log.e(TAG, "unable to add word: " + strings[0].trim());
            }
        }
    } finally {
        reader.close();
    }
}

public long addWord(String word, String definition) {
    ContentValues initialValues = new ContentValues();
    initialValues.put(COL_WORD, word);
    initialValues.put(COL_DEFINITION, definition);

    return mDatabase.insert(FTS_VIRTUAL_TABLE, null, initialValues);
}

قم باستدعاء التابع loadDictionary()  في الوقت المناسب لتملأ الجدول بالمعلومات المناسبة.

المكان المناسب لهذا الاستدعاء ضمن التابع onCreate()ضمن صف DatabaseOpenHelper , وذلك فورا بعد انشاء الجدول:

@Override
public void onCreate(SQLiteDatabase db) {
    mDatabase = db;
    mDatabase.execSQL(FTS_TABLE_CREATE);
    loadDictionary();
}

البحث عن الاستعلام Search for the Query

ما ان يصبح لديك الجدول الافتراضي بعد انشاءه وتعبيئته بالمعطيات, استخدم الاستعلام المزود من قبل SearchView  للبحث عن المعطيات.

اضف التوابع التالية إلى الصف DatabaseTable  لبناء عبارة SQL التي تقوم بالبحث عن الاستعلام:

 

public Cursor getWordMatches(String query, String[] columns) {
    String selection = COL_WORD + " MATCH ?";
    String[] selectionArgs = new String[] {query+"*"};

    return query(selection, selectionArgs, columns);
}

private Cursor query(String selection, String[] selectionArgs, String[] columns) {
    SQLiteQueryBuilder builder = new SQLiteQueryBuilder();
    builder.setTables(FTS_VIRTUAL_TABLE);

    Cursor cursor = builder.query(mDatabaseOpenHelper.getReadableDatabase(),
            columns, selection, selectionArgs, null, null, null);

    if (cursor == null) {
        return null;
    } else if (!cursor.moveToFirst()) {
        cursor.close();
        return null;
    }
    return cursor;
}

يتم البحث عن الاستعلام عبر استدعاء التابع getWordMatches().اي نتائج مطابقة سوف يتم اعادتها ضمن Cursor  التي بإمكانك التجوال ضمنها او استخدامها لبناء ListView.

يقوم هذا المثاال باستدعاء التابع getWordMatches()  ضمن تابع handleIntent()  الخاص بفعالية البحث searchable activity.

تذكر بأن فعالية البحث تتلقى الاستعلام ضمن intent ACTION_SEARCH  عبر ال extra, وذلك بسبب ال intent filter  الذي قمت بإنشاءه مسبقا:

DatabaseTable db = new DatabaseTable(this);

...

private void handleIntent(Intent intent) {

    if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
        String query = intent.getStringExtra(SearchManager.QUERY);
        Cursor c = db.getWordMatches(query, null);
        //process Cursor and display results
    }
}

وإلى لقاء قريب في الحلقة المقبلة

وإلى ذلك الحين استودعكم الله والسلام عليكم ورحمة الله وبركاته

, , , , ,

أضف تعليق

46 : اندرويد : اعداد واجهة المستخدم الخاصة بالبحث Setting Up the Search Interface

 

ملاحظة : الموضوع عبارة عن حلقة من حلقات سلسلة برمجة وتطوير اندرويد Android Development

اندرويد :   اعداد واجهة المستخدم الخاصة بالبحث Setting Up Search Interface

السلام عليكم ورحمة الله وبركاته

سوف نتعلم ضمن هذا الدرس مايلي :

  1. اضافة view خاص بالبحث إلى شريط الاحداث Action Bar
  2. إنشاء الاعدادات الخاصة بالبحث Create a Searchable Configuration
  3. إنشاء فعالية قابلة للبحث Create a Searchable Activity

قبل البدء يجب قراءة

  1. شريط الاحداث Action Bar

انطلاقا من اصدار 3.0 من اندرويد , اصبح استخدام العنصر  SearchView  ضمن شريط الاحداث action bar  عبارة عن الطريقة المثلى  لتحقيق امكانية البحث ضمن تطبيقك.

وكما هو الحال بالنسبة للعناصر الموجودة ضمن شريط الاحداث action bar فإنه بإمكانك ان تعرف وتهيئ العنصر SearchView  لكي يظهر في كل الاوقات, وذلك عندما يكون هنالك متسع له, او ان يظهر بشكل حدث قابل للطي, حيث يقوم  بعرض عنصر SearchView  بشكل ايقونة بشكل ابتدائي, ومن ثم يشغل كل شريط الاحداث على شكل  حقل خاص للبحث عندما ينقر المستخدم على هذه الايقونة.

ملاحظة : لاحقا ضمن هذا الدرس, سوف تتعلم كيف بإمكانك ان تجعل تطبيقك متوافقا مع اصدار 2.1 من اندرويد(API level 7) وذلك بالنسبة للاجهزة التي لا تدعم SearchView.

اضافة Search View  إلى شريط الاحداث action bar

لكي تقوم بإضافة SearchView  إلى شريط الاحداث action bar, انشأ ملف xml بالاسم التالي : res/menu/options_menu.xml  ضمن مشروعك , واضف إليه الترميز(الكود) التالي ادناه:

يقوم هذا الترميز بتعريف كيفية انشاء عنصر بحث, حيث نقوم على سبيل المثال بتعريف الايقونة التي نرغب باستخدامها , والعنوان الذي نريد لهذا العنصر.

تمكن خاصية collapseActionView  ال SearchView  من ان يشغل المساحة المتوافرة من شريط الاحداث action bar وذلك في حال استخدامه , ومن ان يطوى في حال عدم استخدامه.

وبسبب المساحة المحدودة ضمن شريط الاحداث action bar المتواجدة على الاجهزة الصغيرة, فإنه ينصح باستخدام الخاصية collapsibleActionView, وذلك لتزودنا بتجربة افضل للمستخدم.

<?xml version=”1.0″ encoding=”utf-8″?>
<menu xmlns:android=”http://schemas.android.com/apk/res/android”&gt;
<item android:id=”@+id/search”
android:title=”@string/search_title”
android:icon=”@drawable/ic_search”
android:showAsAction=”collapseActionView|ifRoom”
android:actionViewClass=”android.widget.SearchView” />
</menu>

ملاحظة : في حال كان لديك ملف xml جاهز ضمن تطبيقك خاص بعناصر القائمة menu items, فإنه بإمكانك اضافة العنصر<item>إلى ذلك الملف بدلا من انشاء ملف جديد.

لكي تقوم بعرض SearchView  ضمن شريط الحداث action bare, قم ب inflate   لملف ال xml الخاص بموارد القائمة (res/menu/options_menu.xml) ضمن التابع onCreateOptionsMenu()ضمن فعاليتك.

 

@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.options_menu, menu);return true;
}

اذا قمت بتشغيل تطبيقك الآن , فسوف يظهر العنصرSearchView  ضمن شريط الاحداث الخاص بتطبيقك, ولكنه لا يعمل. الآن انت بحاجة إلى ان تعرف كيفية عمل وسلوك العنصر SearchView.

إنشاء الاعدادات الخاصة بالبحث Create a Searchable Configuration

تقوم الاعدادات الخاصة بالبحث searchable configurationبتعريف سلوكيات العنصر SearchView  , ويتم تعريفها ضمن الملف res/xml/searchable.xml.

في الحد الآدنى , فإن اعدادات البحث يجب ان تحوي على الخاصية android:label  والتي تملك نفس قيمة الخاصية android:label للعناصر التالية :  <application>  او  <activity>ضمن ملف manifest  ضمن اندرويد.

على كل الاحوال, فإننا ايضا ننصح بإضافة خاصية android:hint لنعطي المستخدم فكرة عما يجب ادخاله ضمن صندوق البحث:

<?xml version="1.0" encoding="utf-8"?>

<searchable xmlns:android="http://schemas.android.com/apk/res/android"
        android:label="@string/app_name"
        android:hint="@string/search_hint" />

ضمن ملف manifest الخاص بتطبيقك, صرح عن العنصر <meta-data>الذي يشيير إلى الملف res/xml/searchable.xml , وبذلك يصبح بإمكان تطبيقك معرفة مكان تواجد الملف.

صرح عن هذا العنصر <meta-data>  ضمن العنصر <activity>   الذي ترغب في ان يتم عرض SearchView  ضمنه.

<activity ... >
    ...
    <meta-data android:name="android.app.searchable"
            android:resource="@xml/searchable" />

</activity>

ضمن التابع onCreateOptionsMenu()الذي قمت بإنشاءه من قبل, ارفق اعدادات البحث مع العنصر SearchView عبر استدعاء التابع setSearchableInfo(SearchableInfo):

 

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.options_menu, menu);

    // Associate searchable configuration with the SearchView
    SearchManager searchManager =
           (SearchManager) getSystemService(Context.SEARCH_SERVICE);
    SearchView searchView =
            (SearchView) menu.findItem(R.id.search).getActionView();
    searchView.setSearchableInfo(
            searchManager.getSearchableInfo(getComponentName()));

    return true;
}

إن الاستدعاء للتابع getSearchableInfo()  يقوم باستحصال غرض  SearchableInfoالذي تم انشائه من قبل ملف xml الخاص باعدادات البحث.

ما إن يتم ارفاق اعدادات البحث بشكل صحيح مع ال SearchViewالخاص بك, حتى يقوم ال SearchView  بتشغيل فعالية مع ال ACTION_SEARCH Intent وذلك عندما يقوم المستخدم بتسجيل (اضافة) الامر الذي يرغب بالبحث عنه.

الآن , انت بحاجة إلى فعالية لهذه الACTION_SEARCH intent لتتعامل مع استعلام البحث الذي يدخله المستخدم.

إنشاء فعالية للبحث Create a Searchable Activity

يحاول ال SearchView  تشغيل فعالية عبر ال intent   ACTION_SEARCHوذلك عندما يقوم المستخدم بتسجيل استعلام ضمن صندوق البحث.

تقوم فعالية البحث searchable activity يفتلرة لل ACTION_SEARCH Intent  وتبحث عن نتائج الاستعلام ضمن هيكلية معطيات من الشكل data set.

لكي ننشأ فعالية بحث searchable activity  , نصرح عن فعالية من اختيارنا لتنقدح عند طلب ال ACTION_SEARCH intent  :

<activity android:name=".SearchResultsActivity" ... >
    ...
    <intent-filter>
        <action android:name="android.intent.action.SEARCH" />
    </intent-filter>
    ...
</activity>

ضمن فعالية البحث تلك , نعالج عملية استدعاء ال ACTION_SEARCH intent عبر التحقق من وجودها ضمن التابع onCreate()ضمن تلك الفعالية.

ملاحظة : في حال كانت فعالية البحث الخاصة بك تعمل ضمن single top mode  (android:launchMode=”singleTop”) , ويتم ايضا التعامل مع ACTION_SEARCHintent ضمن التابع.

ضمن “single top mode”  يتم انشاء مستنسخ وجيد من الفعالية , وبالتالي فإن الاستدعاءات المتبقية لتشغيل فعاليتك , لن تقوم بإنشاء فعالية اخرى ضمن المكدس stack.

هذا النمط من انماط التشغيل launch mode  مفيد عندما يكون بإمكان المستخدمين ان يبحثوا ضمن نفس الفعالية بدون الحاجةى إلى انشاء مستنسخ جديد من الفعالية في كل مرة.

 

public class SearchResultsActivity extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        ...
        handleIntent(getIntent());
    }

    @Override
    protected void onNewIntent(Intent intent) {
        ...
        handleIntent(intent);
    }

    private void handleIntent(Intent intent) {

        if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
            String query = intent.getStringExtra(SearchManager.QUERY);
            //use the query to search your data somehow
        }
    }
    ...
}

في حال قمت بتشغيل تطبيقك الآن , يصبح بإمكان عنصر ان يتلقى استعلامات المستخدم , ويقوم بتشغيل فعالية البحث searchable activity, عبر الACTION_SEARCH intent.

الآن الموضوع عندك لكي تحزر كيف سيتم تخزين المعطيات والبحث ضمنها عبر استخدام الاستعلام المعطى.

وسنوافيكم بالتفاصيل بالحلقة القادمة

وإلى ذلك الحين استودعكم الله والسلام عليكم ورحمة الله وبركاته

 

, , ,

أضف تعليق

45 : اندرويد : اضافة امكانية البحث adding search functionality

 

ملاحظة : الموضوع عبارة عن حلقة من حلقات سلسلة برمجة وتطوير اندرويد Android Development

اندرويد :  اضافة امكانية البحث Adding search functionality

السلام عليكم ورحمة الله وبركاتهnotify3

المتطلبات :

نسخة اندرويد 3.0 فما فوق ( مع قليل من الدعم لنسخة اندرويد 2.1 )

خبرة في بناء واجهات المستخدم على اندرويد.

يتوجب عليك ايضا الاطلاع على المواضيع التالية :

توفر امكانية البحث المدمجة مع اندرويد – فيما يخص التطبيقات –  طريقة متناسقة للبحث ومتجانسة وتجربة جيدة لكل المستخدمين.

هنالك طريقتين لتحقيق البحث ضمن تطبيقك , وذلك اعتمادا على نسخة اندرويد الموجودة على الجهاز.

تزودنا هذه المجموعة من الدروس بشرح لكيفية اضافة بحث ضمن التطبيق باستخدام SearchView,والذي تم طرحه ابتداءا من نسخة اندرويد 3.0, مع الحفاظ على التوافقية مع النسخ القديمة من اندرويد عبر استخدام صندوق البحث الافتراضي المزود من قبل النظام.

سنتناول في الدورس القليلة القادمة المواضيع التالية :

  1. اعداد واجهة المستخدم للبحث Setting Up the Search Interface
    1. نتعلم فيه كيف نضيف واجهة خاصة بالبحث ضمن تطبيقك , وكيف يتم اعداد الفعالية لتتعامل مع استعلامات البحث.
  2. التخزين و البحث عن المعطيات Storing and Searching for Data
    1. نتعلم فيه طريقة بسيطة لحفظ المعطيات والبحث فيها  ضمن جدول افتراضي لقاعدة المعطيات SQLite(virtual database table)
  3. الحفاظ على التوافقية مع الاصدارات القديمة Remaining Backward Compatible
    1. نتعلم فيه كيف نجعل ميزات البحث متوافقة مع الاجهزة القديمة.

إلى لقاء في الحلقة القادمة لنتابع ما بدأنا بالحديث عنه ضمن هذه الحلقة

وإلى ذلك الحين استودعكم الله والسلام عليكم ورحمة الله وبركاته

,

أضف تعليق