با حمایت ما%۵
تخفیف بگیرد

logo-samandehi

برنامه نويسي اندرويد 12- پروژه « شمارنده »

مقدمه:

این پروژه یک نمونه خوب و معتبر از استانداردهای طراحی برنامه و شیء گرایی است. توضیحات بسیار کامل در میان کد ها ارائه شده است و با وجود آن توضیح اضافه تری را مفید نمی دانم. این پروژه گرد آورنده حدود 4 قسمت از آموزش است بدون آنکه چیزی از آن 4 پروژه را از دست دهیم. پس آنرا خیلی خوب مطالعه و بررسی کنید و روشهای بکاربرده شده را به یاد داشته باشید.

 

تصویر متحرک از خروجی این جلسه :

 

 

آموزش:

» نکته خاصی نیست بجز اینکه فایلهای زیر را مطالعه و وارد یک پروژه جدید بکنید، یا از سورس اصلی پروژه در انتهای متن استفاده نمایید.

 

محتویات فایل AndroidManifest.xml :

 



  1.     package="com.uncocoder.course.project.counter"
        android:versionCode="100"
        android:versionName="1.00" >

       

       
       

       
                android:name="com.uncocoder.course.project.counter.G"
            android:icon="@drawable/icon"
            android:label="Course Counter" >
                        android:name=".MainActivity"
                android:theme="@android:style/Theme.NoTitleBar" >
               
                   

                   
               

           
       

 

محتویات فایل dialog_alarm.xml که یک layout است:



  1.     android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:minHeight="150dip"
        android:minWidth="150dip"
        android:orientation="vertical" >

                android:id="@+id/txt_message"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="8dip"
            android:layout_marginTop="8dip"
            android:gravity="center"
            android:text="NO MESSAGE" />

                android:layout_width="fill_parent"
            android:layout_height="0dip"
            android:layout_weight="1"
            android:orientation="vertical" >
       


                android:layout_width="fill_parent"
            android:layout_height="wrap_content" >

                        android:id="@+id/btn_ok"
                android:layout_width="0dip"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:minWidth="150dip"
                android:singleLine="true"
                android:text="OK, I'm awake" />

                        android:id="@+id/btn_snooze"
                android:layout_width="80dip"
                android:layout_height="wrap_content"
                android:text="Snooze" />
       

 

 

محتویات فایل form_counter.xml که یک layout است:



  1.     android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:orientation="vertical" >

                android:id="@+id/prg_counter"
            style="?android:attr/progressBarStyleHorizontal"
            android:layout_width="fill_parent"
            android:layout_height="4dip" />

                android:layout_width="fill_parent"
            android:layout_height="wrap_content" >

                        android:layout_width="0dip"
                android:layout_height="wrap_content"
                android:layout_weight="0.5"
                android:background="#252525"
                android:orientation="vertical"
                android:paddingBottom="4dip"
                android:paddingTop="4dip" >

                                android:id="@+id/TextView01"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginLeft="8dip"
                    android:text="Set alarm time (s):"
                    android:textColor="#bbbbbb"
                    android:textStyle="bold" />

                                android:id="@+id/edt_alarm_time"
                    android:layout_width="125dip"
                    android:layout_height="wrap_content"
                    android:layout_marginLeft="16dip"
                    android:layout_marginTop="2dip"
                    android:inputType="numberDecimal"
                    android:text="10" />
           


                        android:id="@+id/ImageView03"
                android:layout_width="2dip"
                android:layout_height="fill_parent"
                android:background="#888888" />

                        android:layout_width="0dip"
                android:layout_height="wrap_content"
                android:layout_weight="0.5"
                android:background="#252525"
                android:orientation="vertical"
                android:paddingBottom="4dip"
                android:paddingTop="4dip" >

                                android:id="@+id/TextView03"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginLeft="8dip"
                    android:text="Set snooze time (s):"
                    android:textColor="#bbbbbb"
                    android:textStyle="bold" />

                                android:id="@+id/edt_snooze_time"
                    android:layout_width="125dip"
                    android:layout_height="wrap_content"
                    android:layout_marginLeft="16dip"
                    android:layout_marginTop="2dip"
                    android:inputType="numberDecimal"
                    android:text="5" >

                   
               
           
       

                android:id="@+id/imageView1"
            android:layout_width="fill_parent"
            android:layout_height="2dip"
            android:background="#ffffff" />

                android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:background="#333333"
            android:orientation="vertical"
            android:paddingBottom="8dip"
            android:paddingTop="8dip" >

                        android:id="@+id/textView1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="8dip"
                android:text="What to do on Alarm?"
                android:textColor="#bbbbbb"
                android:textStyle="bold" />

                        android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:layout_marginLeft="16dip"
                android:layout_marginRight="16dip" >

                                android:id="@+id/chk_ring"
                    android:layout_width="0dip"
                    android:layout_height="wrap_content"
                    android:layout_weight="0.5"
                    android:checked="true"
                    android:text="Ring" />

                                android:id="@+id/chk_vibrate"
                    android:layout_width="0dip"
                    android:layout_height="wrap_content"
                    android:layout_weight="0.5"
                    android:checked="true"
                    android:text="Vibrate" />
           

                        android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:layout_marginLeft="16dip"
                android:layout_marginRight="16dip" >

                                android:id="@+id/chk_dialog"
                    android:layout_width="0dip"
                    android:layout_height="wrap_content"
                    android:layout_weight="0.5"
                    android:checked="true"
                    android:text="Dialog" />

                                android:id="@+id/chk_toast"
                    android:layout_width="0dip"
                    android:layout_height="wrap_content"
                    android:layout_weight="0.5"
                    android:checked="true"
                    android:text="Toast" />
           
       

                android:id="@+id/ImageView01"
            android:layout_width="fill_parent"
            android:layout_height="2dip"
            android:background="#ffffff" />

                android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:background="#333333"
            android:orientation="vertical"
            android:paddingBottom="8dip"
            android:paddingTop="8dip" >

                        android:id="@+id/TextView02"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="8dip"
                android:text="Select algorithm mode:"
                android:textColor="#bbbbbb"
                android:textStyle="bold" />

                        android:id="@+id/radioGroup1"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:layout_marginLeft="16dip"
                android:layout_marginRight="16dip"
                android:orientation="horizontal" >

                                android:id="@+id/rad_async"
                    android:layout_width="0dip"
                    android:layout_height="wrap_content"
                    android:layout_weight="0.5"
                    android:text="Async" />

                                android:id="@+id/rad_thread"
                    android:layout_width="0dip"
                    android:layout_height="wrap_content"
                    android:layout_weight="0.5"
                    android:checked="true"
                    android:text="Thread" />
           
       

                android:id="@+id/ImageView02"
            android:layout_width="fill_parent"
            android:layout_height="2dip"
            android:background="#ffffff" />

                android:layout_width="fill_parent"
            android:layout_height="0dip"
            android:layout_weight="1"
            android:orientation="vertical" >
       

                android:layout_width="fill_parent"
            android:layout_height="wrap_content" >

                        android:id="@+id/btn_start"
                android:layout_width="0dip"
                android:layout_height="wrap_content"
                android:layout_weight="0.5"
                android:singleLine="true"
                android:text="Start" />

                        android:id="@+id/btn_stop"
                android:layout_width="0dip"
                android:layout_height="wrap_content"
                android:layout_weight="0.5"
                android:singleLine="true"
                android:text="Stop" />
       

 

 

محتویات فایل G.java :


  1. package com.uncocoder.course.project.counter;

    import android.app.Application;
    import android.content.Context;

    /**
     * این روش یک تکنیک مناسب برای مقدار دهی اولیه متغیرهای قابل دسترس، در تمام کلاسها
     * است. با استفاده از تعریف ثابت ها، تنظیمات و ... در یک جای مشخص مثل اینجا، همیشه همه چیز
     * به سادگی در دسترس و قابل تنظیم است
     * از طرفی این کلاس از کلاس اپلیکیشن زیر کلاس شده و در فایل منیفست به عنوان فایل کلاس
     * اصلی اپلیکشن شناسانده شده است. لذا با اجرای برنامه این کلاس شروع به کار می کند و اولین
     * جایی که می رود در متد تعریف شده زیر است
     */
    public class G extends Application {

        /** تعریف یک عبارت برای درج در لگ کت، که با سایر پروژه ها تداخل نداشته باشد */
        public static final String LOG_TAG      = "COUNTER_PROJECT";

        public static final float  TICK_FACTOR  = 0.1f;
        public static final int    VIBRATE_TIME = 1000;

        /** تعریف اشاره گری به کانتکست که می تواند در بسیار از جاها مورد استفاده قرار گیرد نظیر نمایش تُست ها */
        public static Context      gContext;



        /**
         * با شروع برنامه از این مرحله کار آغاز می شود و پس از اتمام کارهای زیر، تازه به سراغ اکتیویتی اصلی
         * رفته و از آنجا ادامه می دهد
         */
        @Override
        public void onCreate() {
            super.onCreate();

            /** واریز کردن کانتکست برنامه در همان اوایل شروع برنامه جهت استفاده در همه کلاسهای نیازمند */
            gContext = getApplicationContext();
        }
    }

 

 

محتویات فایل  Counter.java :


  1. package com.uncocoder.course.project.counter;

    public abstract class Counter {

        /**
         * توجه داشته باشید که اشاره گرهای زیر پروتکتد هستند، چون نیاز است که در زیر کلاسهای
         * این کلاس به آن دسترسی داشته باشم اما در خارج از این کلاس و زیر کلاسهای آن، هیچ لزومی
         * به دسترسی برنامه نویسان دیگر به آن نیست
         */

        /** ذخیره ثانیه مورد نظر تا برافراشتن زنگ */
        protected int             mAlarmSeconds;

        /** ذخیره فواصل مورد نظر بر حسب ثانیه جهت ارسال یک مرحله پیشرفت به رابط گرافیک */
        protected int             mTickSeconds;

        /** ذخیره زمان سپری شده از ابتدای شروع شمارشگر جهت تست اینکه آیا به زمان مورد نظر رسیده ایم یا نه */
        protected int             mElapsedSeconds;

        /** ذخیره اینکه اگر دکمه خواب مجدد زده شد، چند ثانیه به تعویق افتد. همینطور یک مقدار پیش فرض */
        protected int             mSnoozeSeconds     = 10;

        /** اینکه اگر در مرحله دکمه خواب بودیم، فواصل اطلاع رسانی به رابط گرافیک چقدر باشد */
        protected int             mSnoozeTickSeconds = 1;

        /** تعریف اشاره گری به نمونه ای که قرار است به این کانتر گوش بدهد و پیامهای او را بفهمد */
        protected CounterListener mListener;

        /** انتخاب نامی برای این کانتر جهت نمایش در پنجره ها و خروجی ها */
        protected String          mName              = "NO NAME";



        /** تست کردن پارامترهای ورودی به کانستراکتور و ذخیره آن */
        public Counter(int seconds, int tickSeconds) {
            if (seconds <= 5) {
                seconds = 5;
            }
            mAlarmSeconds = seconds;

            if (tickSeconds <= 0) {
                tickSeconds = 1;
            }
            mTickSeconds = tickSeconds;
        }



        /**
         * یک متد آبسترکت، که هر زیر کلاس این کلاس را ملزم می کند که حتماً آنرا تعریف کنند وگرنه با خطای
         * محیط توسعه مواجه خواهیم شد. تعریف اینگونه متدها برای امنیت و اعتماد به کد است و جلوی بسیاری از
         * سهل انگاری برنامه نویسان را خواهد گرفت. می شد از واژه آبسترکت استفاده نکنیم، در این شرایط اگر
         * زیر کلاسی این متد را تعریف نمی کرد، خطایی در محیط توسعه داده نمی شود ولی کد اشتباه کار می کرد
         */
        public abstract void start();



        /** مانند توضیحات متد قبل */
        public abstract void stop();



        /** چون خود اشاره گر، خصوصی است آنرا با استفاده از متد های مناسب قابل دسترس می سازیم */
        public void setListener(CounterListener listener) {
            mListener = listener;
        }



        /** تعیین اینکه خواب مجدد چه خصوصیاتی داشته باشد */
        public void setSnoozeTime(int seconds, int tickSeconds) {
            if (seconds <= 2) {
                seconds = 2;
            }
            mSnoozeSeconds = seconds;

            if (tickSeconds <= 0) {
                tickSeconds = 1;
            }
            mSnoozeTickSeconds = tickSeconds;
        }



        /** به یک اشاره گر خصوصی با این کار دسترسی پیدا کرده ایم */
        public void setName(String name) {
            if (name == null) {
                return;
            }
            mName = name;
        }



        /** به یک اشاره گر خصوصی با این کار دسترسی پیدا کرده ایم */
        public String getName() {
            return mName;
        }



        /** ریست کردن مقادیر مهم برای خواب مجدد، و اجرای مجدد کانتر */
        public void snooze() {
            mElapsedSeconds = 0;
            mAlarmSeconds = mSnoozeSeconds;
            mTickSeconds = mSnoozeTickSeconds;

            /** */
            start();
        }



        /**
         * تعریف یک اینترفیس بسیار کاربردی و مهم است. از آن می توان به مقاصد بسیار زیادی نظیر
         * استفاده به عنوان لیسنر، دسته بندی کلاسها، بستن خطاهای برنامه نویس و ... استفاده کرد. در
         * اینجا با تعریف دو متد، هر کلاسی که از این اینترفیس استفاده کرده باشد را ملزم می کنیم که این
         * دو متد را تعریف شده داشته باشد.
         */
        public static interface CounterListener {

            /** با اتمام زنگ این متد از لیسنر کانتر اجرا می شود */
            public void onAlarm(Counter counter);



            /** با گذشتن یک مرحله از تیک این متد در لیسنر کانتر اجرا می شود */
            public void onTick(Counter counter, int percent);
        }
    }

 

 

محتویات فایل ThreadTypeCounter.java:


  1. package com.uncocoder.course.project.counter;

    import android.os.Handler;
    import android.util.Log;
    import android.widget.Toast;

    public class ThreadTypeCounter extends Counter {

        /** ذخیره اشاره گر به ترد این کلاس */
        private Thread  mThread;

        /** تعریف یک هندلر جهت اجرای قسمتهایی از کد، درون ترد اصلی */
        private Handler mHandler;



        /** ساخت کانستراکتور ( که حتماً پدر خود را صدا میکند تا پارامترها ست شود) خودش هم دستوری اضافه تر دارد */
        public ThreadTypeCounter(int seconds, int tickSeconds) {
            super(seconds, tickSeconds);
            mHandler = new Handler();
        }



        /**
         * نحوه شروع شدن این کانتر، توجه داشته باشید که به دلیل وجود داشتن این متد ( به عنوان یک متد
         * آبسترکت ) در کلاس کانتر ملزم به تعریف آن هستیم
         */
        @Override
        public void start() {
            Toast.makeText(G.gContext, "Counter started using Thread Algorithm", Toast.LENGTH_SHORT).show();

            mThread = new Thread(new Runnable() {

                @Override
                public void run() {
                    try {
                        /** اجرای کد تا زمانی که به زمان مناسب جهت هشدار برسیم */
                        while (mElapsedSeconds < mAlarmSeconds) {
                            int waitForSleep = mTickSeconds;

                            /**
                             * در صورتیکه مقدار مانده تا اعلام هشدار کمتر از مقدار تیک است، پس به اندازه تیک صبر نمی کنیم و
                             * به اندازه زمان باقی مانده صبر می کنیم
                             */
                            if (mAlarmSeconds - mElapsedSeconds < mTickSeconds) {
                                waitForSleep = mAlarmSeconds - mElapsedSeconds;
                            }

                            Thread.sleep(waitForSleep * 1000);

                            mElapsedSeconds += waitForSleep;

                            /** اجرای کد های درون آن، داخل ترد اصلی ( چون ممکن است نیاز باشد که رابط گرافیک آپدیت شود ) */
                            mHandler.post(new Runnable() {

                                @Override
                                public void run() {
                                    float percent = (float) mElapsedSeconds / (float) mAlarmSeconds * 100;
                                    mListener.onTick(ThreadTypeCounter.this, (int) Math.floor(percent));
                                }
                            });
                        }

                        if (mListener != null) {

                            /** اجرای کد های درون آن، داخل ترد اصلی ( چون ممکن است نیاز باشد که رابط گرافیک آپدیت شود ) */
                            mHandler.post(new Runnable() {

                                @Override
                                public void run() {
                                    mListener.onAlarm(ThreadTypeCounter.this);
                                }
                            });
                        }

                        Log.i(G.LOG_TAG, "from counter: alarm raised for " + mName);
                    }
                    catch (InterruptedException e) {
                        Log.i(G.LOG_TAG, "from counter: alarm stopped for " + mName);
                    }
                }
            });

            /** شروع ترد */
            mThread.start();
        }



        @Override
        public void stop() {
            if (mThread == null) {
                Log.d(G.LOG_TAG, "from counter: thread not exist and can't stop");
                return;
            }

            /** لغو عملیات ترد */
            mThread.interrupt();
        }
    }

 

 

محتویات فایل AsyncTypeCounter.java:


  1. package com.uncocoder.course.project.counter;

    import android.os.AsyncTask;
    import android.util.Log;
    import android.widget.Toast;

    /** تعریف یک کلاس از کانتر که به روش آسینک عمل کند */
    public class AsyncTypeCounter extends Counter {

        /** ذخیره اشاره گر به آسینک تسک، جهت متوقف کردن آن در صورت نیاز */
        private Task mTask;



        /** اجرای کانستراکتور والد، ولی خودش چیز بیشتری برای تعریف ندارد */
        public AsyncTypeCounter(int seconds, int tickSeconds) {
            super(seconds, tickSeconds);
        }



        /** شروع آسینک تسک */
        @Override
        public void start() {
            mTask = new Task();
            mTask.execute();
        }



        /** متوقف نمودن آسینک تسک */
        @Override
        public void stop() {
            mTask.cancel(true);
        }



        /** تعریف کلاسی از آسینک تسک برای پیاده سازی این الگوریتم */
        public class Task extends AsyncTask {

            /** ذخیره مقدار درصد برای ارسال توسط متد مربوطه */
            private int mPercent;



            /** قبل از شروع شماره، کدهای درون آن، در ترد اصلی اجرا می شوند */
            @Override
            protected void onPreExecute() {
                Toast.makeText(G.gContext, "Counter started using Async Algorithm", Toast.LENGTH_SHORT).show();
                super.onPreExecute();
            }



            /** با صدا شدن متد « پابلیش پروگرس » در متد « بک گراند » کدهای درون این متد در ترد اصلی اجرا می شوند */
            @Override
            protected void onProgressUpdate(Void... values) {
                if (mListener != null) {
                    /** صدا زدن متد مناسب از لیسنر کانتر */
                    mListener.onTick(AsyncTypeCounter.this, mPercent);
                }
                super.onProgressUpdate(values);
            }



            /** محتویات این متد، در یک ترد غیر از ترد اصلی اجرا می شود */
            @Override
            protected Void doInBackground(Void... params) {
                try {
                    /** اجرای کد تا زمانی که به زمان مناسب جهت هشدار برسیم */
                    while (mElapsedSeconds < mAlarmSeconds) {
                        int waitForSleep = mTickSeconds;

                        /**
                         * در صورتیکه مقدار مانده تا اعلام هشدار کمتر از مقدار تیک است، پس به اندازه تیک صبر نمی کنیم و
                         * به اندازه زمان باقی مانده صبر می کنیم
                         */
                        if (mAlarmSeconds - mElapsedSeconds < mTickSeconds) {
                            waitForSleep = mAlarmSeconds - mElapsedSeconds;
                        }

                        Thread.sleep(waitForSleep * 1000);
                        mElapsedSeconds += waitForSleep;
                        mPercent = (int) Math.floor((float) mElapsedSeconds / (float) mAlarmSeconds * 100);
                        publishProgress();
                    }

                    Log.i(G.LOG_TAG, "from counter: alarm raised for " + mName);
                }
                catch (InterruptedException e) {
                    Log.i(G.LOG_TAG, "from counter: alarm stopped for " + mName);
                }

                return null;
            }



            /** پس از خاتمه عملیات درون « بک گراند » کدهای درون این متد در ترد اصلی اجرا می شوند */
            @Override
            protected void onPostExecute(Void result) {
                if (mListener != null) {
                    /** */
                    mListener.onAlarm(AsyncTypeCounter.this);
                }
                super.onPostExecute(result);
            }
        }
    }

 

 

محتویات فایل MainActivity.java:


  1. package com.uncocoder.course.project.counter;

    import android.app.Activity;
    import android.app.Dialog;
    import android.content.Context;
    import android.media.Ringtone;
    import android.media.RingtoneManager;
    import android.net.Uri;
    import android.os.Bundle;
    import android.os.Vibrator;
    import android.util.Log;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.view.WindowManager;
    import android.widget.Button;
    import android.widget.CheckBox;
    import android.widget.EditText;
    import android.widget.ProgressBar;
    import android.widget.RadioButton;
    import android.widget.TextView;
    import android.widget.Toast;

    /**
     * این اکتویتی بدلیل نیاز به پاسخگویی به کلاس های کانتر باید ( لیسنر کانتر ) را تعریف کند، تا
     * آنها او را به عنوان گوش دهنده ( به خودشان ) بپ

مطالب مرتبط

آخرین شرکتهای طرف قرارداد

دارولند

طراحی فروشگاه اینترنتی

آف مکس

طراحی سایت تخفیف گروهی

نمایندگان بیمه ما

طراحی وب سایت و پورتال نمایندگان

پژند الکترونیک

طراحی وب سایت و پرتال

نمایندگی بوش

طراحی وب سایت شرکتی

ایران بزرگ

طراحی وب سایت، اتوماسیون اداری و خدمات شبکه پایگاه خبری ایران بزرگ

ستون فقرات تهران

طراحی پورتال تخصصی پزشکی ستون فقرات تهران

آخرین توییت ها

آخرین مقالات آموزشی

استفاده از تکنولوژی روز دنیا در شرکت فناوران راتا رایان