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

logo-samandehi

برنامه نويسي اندرويد 10- همزمانی - Thread ها

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

در این جلسه نما و عملکرد زیر که در مورد آموزش Thread هست ساخته خواهد شد. توجه داشته باشید که فرم سوم را خالی قرار داده ام تا شما بتوانید با قالب از پیش آماده شده برنامه های خود را نوشته و تست کنید تا سریعتر پیش روید.

 


 

 

به این نکات توجه کنید که:

♦ با زدن دکمه No Thread ، دایره در حال چرخیدن ( Progress Bar ) می ایستد. علت این است که کد زمانبری که نوشته شده است در Thread جدایی اجرا نشده و در UI Thread یا همان Main Thread اجرا می شود لذا Update شدن صفحه به تأخیر می افتد. اگر این کد کمی طولانی تر شود و زمان بیشتری ببرد، باعث می شود اندروید پیغامی مبنی بر عدم پایداری برنامه به شما بدهد و دکمه Wait و Force Close برای شما بیاید. راه پیشگیری از این اتفاق استفاده از Thread جدا گانه است.

♦ بعد از زدن دکمه Start Single Thread، همان عمل بالا یکبار اجرا می شود اما این بار توسط Thread ، لذا توقفی در UI مشاهده نخواهد شد.

♦ بعد از زدن دکمه Start Parallel Threads، همان عمل بالا چهار بار اجرا می شود اما همزمان توسط چهار Thread مختلف. علی رقم انتظار شما، Thread ها لزوماً به ترتیبی که آغاز شده اند پایان نمی پذیرند، چرا که ممکن است در اعمال همزمان Thread ـی از Thread دیگر عقب یا جلو بیافتد.

♦ با زدن دکمه Clear محتویات Log ها خالی خواهد شد.

♦ دکمه Prev در صفحه اول و دکمه Next در صفحه آخر غیرفعال است ( قابل توجه در بحثهای UI )

♦ با زدن دکمه Next و Prev بین Activity های مختلف انتقال پیدا می کنیم و Activity قبلی Finish می شود.

♦ در پنجره Part 2 با زدن دکمه Set and Start پیغامهای متوالی را با فاصله زمانی داخل EditText نمایش می دهیم.

♦ در صورتیکه Thread در حال اجرا باشد، پیغام در حال اجرا بودن نمایش داده می شود و خطایی بوجود نمی آید.

♦ در صورتیکه متن Log از صفحه تجاوز کند، Scroll بطور اتوماتیک به ته لیست می رود.

♦ با زدن کلید Stop عمل تأخیر و شمارش پایان می یابد ( Thread پایان می یابد )

♦ اگر بطور ناگهان از به سایر Activity ها برویم، خود به خود عمل Stop اجرا می شود. ( به متد onPause در کد توجه شود )

♦ با زدن کلید Back در هر صفحه کل برنامه بسته خواهد شد و هیچ اثری از آن روی Memory و CPU باقی نخواهد ماند.(به متد onKeyDown در کد توجه شود)

 

آموزش:

» کار را بر روی پروژه ساخته شده در قسمت 12 ام آموزش ( برنامه نویسی جاوا - مقدماتی 2 ) ادامه می دهیم. لذا اگر آنرا ندارید از آموزش مذکور دانلود کرده و طبق آموزشهای قبل تر ، آنرا Import کنید.

» یک پکیج با آدرس com.uncocoder.course.lessons.thread در src بسازید

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

» سه فایل Layout می سازیم که به سه Activity جدید تغذیه کنیم. بنابراین طبق آموزشهای گذشته Layout های زیر را بسازید و سپس کدهای نوشته شده در هر بخش را به آن بدهید. درست است که این قسمت آموزش Thread است اما UI را بگونه ای طراحی کرده ام که بتوانید خواص خیلی مهم و کاربردی UI را به همراه کاربردشان درک و بکارگیرید. بنابراین به UI دقت مضاعف داشته باشد.

» از آنجایی که اضافه کردن هر Activity جدید مستلزم اضافه کردن بخشی دز فایل Manifest است آنرا ویرایش کرده و به شکل نهایی در پایین تغییر دهید. توجه کنید که چون قرار هست اولین Activity جدید ما، Activity اصلی پروژه شود، Intent Filter ها را از Activity قبلی بر می داریم و به این Activity جدید اضافه می کنیم.

» سپس وقت تعریف Activity هاست، بنابراین سه کلاس به پکیج بالا اضافه کرده و آنها را به شیوه پایین برنامه نویسی می کنیم. تمامی توضیحات مورد نیاز در متن برنامه به عنوان Comment قرار دارد.

♦ ( فایلهای مورد نیاز برای ساخت    form_thread3.xml،    form_thread2.xml،    form_thread1.xml   )

♦ ( فایلهای مورد نیاز برای ساخت    ThreadSample3Activity.java،    ThreadSample2Activity.java،    ThreadSample1Activity.java )

و در نهایت ساختار پروژه شما به شکل زیر خواهد شد:

 

 

 

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



  1.     android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:background="#888888"
        android:gravity="center"
        android:orientation="vertical" >

                android:id="@+id/textView1"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:gravity="left"
            android:paddingBottom="3dip"
            android:paddingTop="3dip"
            android:text="Thread Sample ( Page 1 )"
            android:textColor="#ffffff" />

                android:id="@+id/linearLayout1"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:background="#333333"
            android:gravity="center"
            android:padding="5dip" >

                        android:id="@+id/btn_no_thread"
                android:layout_width="0dip"
                android:layout_height="wrap_content"
                android:layout_weight="0.333"
                android:text="No Thread"
                android:textSize="12dip" />

                        android:id="@+id/btn_single_thread"
                android:layout_width="0dip"
                android:layout_height="wrap_content"
                android:layout_weight="0.333"
                android:text="Start Single Thread"
                android:textSize="12dip" />

                        android:id="@+id/btn_parallel_threads"
                android:layout_width="0dip"
                android:layout_height="wrap_content"
                android:layout_weight="0.333"
                android:text="Start Parallel Threads"
                android:textSize="12dip" />
       


                android:id="@+id/progressBar1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="3dip" />


                android:id="@+id/scroll_content"
            android:layout_width="fill_parent"
            android:layout_height="0dip"
            android:layout_margin="5dip"
            android:layout_weight="1"
            android:background="#000000"
            android:padding="3dip" >

                        android:id="@+id/linearLayout2"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:orientation="vertical" >

                                android:id="@+id/txt_log"
                    android:layout_width="fill_parent"
                    android:layout_height="wrap_content"
                    android:text="Log:"
                    android:textColor="#ffffff" />
           
       

                android:id="@+id/LinearLayout01"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:padding="5dip" >

                        android:id="@+id/btn_clear_log"
                android:layout_width="0dip"
                android:layout_height="40dip"
                android:layout_weight="0.2"
                android:text="Clear"
                android:textSize="12dip" />

                        android:id="@+id/linearLayout3"
                android:layout_width="0dip"
                android:layout_height="40dip"
                android:layout_weight="0.4" >
           

                        android:id="@+id/btn_prev"
                android:layout_width="0dip"
                android:layout_height="40dip"
                android:layout_weight="0.2"
                android:enabled="false"
                android:text="Prev"
                android:textSize="12dip" />

                        android:id="@+id/btn_next"
                android:layout_width="0dip"
                android:layout_height="40dip"
                android:layout_weight="0.2"
                android:text="Next"
                android:textSize="12dip" />
       

 

 

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



  1.     android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:background="#888888"
        android:gravity="center"
        android:orientation="vertical" >

                android:id="@+id/textView1"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:gravity="left"
            android:paddingBottom="3dip"
            android:paddingTop="3dip"
            android:text="Thread Sample ( Page 2 )"
            android:textColor="#ffffff" />

                android:id="@+id/linearLayout1"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:background="#333333"
            android:gravity="center"
            android:padding="5dip" >

                        android:id="@+id/linearLayout4"
                android:layout_width="0dip"
                android:layout_height="fill_parent"
                android:layout_weight="0.33"
                android:orientation="vertical" >

                                android:id="@+id/textView2"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:paddingLeft="5dip"
                    android:text="Interval (ms):"
                    android:textSize="10dip" />

                                android:id="@+id/edt_interval"
                    android:layout_width="fill_parent"
                    android:layout_height="35dip"
                    android:inputType="number"
                    android:text="500"
                    android:textSize="13dip" >

                   
               
           


                        android:id="@+id/btn_set_and_start"
                android:layout_width="0dip"
                android:layout_height="wrap_content"
                android:layout_weight="0.333"
                android:text="Set and Start"
                android:textSize="12dip" />

                        android:id="@+id/btn_stop"
                android:layout_width="0dip"
                android:layout_height="wrap_content"
                android:layout_weight="0.333"
                android:text="Stop"
                android:textSize="12dip" />
       

                android:id="@+id/prg_percent"
            style="?android:attr/progressBarStyleHorizontal"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="5dip"
            android:layout_marginRight="5dip"
            android:layout_marginTop="5dip" />


                android:id="@+id/scroll_content"
            android:layout_width="fill_parent"
            android:layout_height="0dip"
            android:layout_margin="5dip"
            android:layout_weight="1"
            android:background="#000000"
            android:padding="3dip" >

                        android:id="@+id/linearLayout2"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:orientation="vertical" >

                                android:id="@+id/txt_log"
                    android:layout_width="fill_parent"
                    android:layout_height="wrap_content"
                    android:text="Log:"
                    android:textColor="#ffffff" />
           
       

                android:id="@+id/LinearLayout01"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:padding="5dip" >

                        android:id="@+id/btn_clear_log"
                android:layout_width="0dip"
                android:layout_height="40dip"
                android:layout_weight="0.2"
                android:text="Clear"
                android:textSize="12dip" />

                        android:id="@+id/linearLayout3"
                android:layout_width="0dip"
                android:layout_height="40dip"
                android:layout_weight="0.4" >
           

                        android:id="@+id/btn_prev"
                android:layout_width="0dip"
                android:layout_height="40dip"
                android:layout_weight="0.2"
                android:text="Prev"
                android:textSize="12dip" />

                        android:id="@+id/btn_next"
                android:layout_width="0dip"
                android:layout_height="40dip"
                android:layout_weight="0.2"
                android:text="Next"
                android:textSize="12dip" />
       

 

 

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



  1.     android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:background="#888888"
        android:gravity="center"
        android:orientation="vertical" >

                android:id="@+id/textView1"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:gravity="left"
            android:paddingBottom="3dip"
            android:paddingTop="3dip"
            android:text="Thread Sample ( Page 3 )"
            android:textColor="#ffffff" />

                android:id="@+id/linearLayout1"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:background="#333333"
            android:gravity="center"
            android:padding="5dip" >

                        android:id="@+id/TextView01"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:gravity="left"
                android:paddingBottom="3dip"
                android:paddingTop="3dip"
                android:text="Do Your Tests!"
                android:textColor="#ffffff" />
       


                android:id="@+id/scrollView1"
            android:layout_width="fill_parent"
            android:layout_height="0dip"
            android:layout_margin="5dip"
            android:layout_weight="1"
            android:background="#000000"
            android:padding="3dip" >

                        android:id="@+id/linearLayout2"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:orientation="vertical" >

                                android:id="@+id/txt_log"
                    android:layout_width="fill_parent"
                    android:layout_height="wrap_content"
                    android:text="Log:"
                    android:textColor="#ffffff" />
           
       

                android:id="@+id/LinearLayout01"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:padding="5dip" >

                        android:id="@+id/btn_clear_log"
                android:layout_width="0dip"
                android:layout_height="40dip"
                android:layout_weight="0.2"
                android:text="Clear"
                android:textSize="12dip" />

                        android:id="@+id/linearLayout3"
                android:layout_width="0dip"
                android:layout_height="40dip"
                android:layout_weight="0.4" >
           

                        android:id="@+id/btn_prev"
                android:layout_width="0dip"
                android:layout_height="40dip"
                android:layout_weight="0.2"
                android:text="Prev"
                android:textSize="12dip" />

                        android:id="@+id/btn_next"
                android:layout_width="0dip"
                android:layout_height="40dip"
                android:layout_weight="0.2"
                android:enabled="false"
                android:text="Next"
                android:textSize="12dip" />
       

 

 

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

 



  1.     package="com.uncocoder.course.lessons"
        android:versionCode="1"
        android:versionName="1.0" >

       

                android:icon="@drawable/ic_launcher"
            android:label="@string/app_name" >
                        android:name=".AndroidCourseActivity"
                android:label="@string/app_name" >
           
                        android:name="com.uncocoder.course.lessons.thread.ThreadSample1Activity"
                android:theme="@android:style/Theme.NoTitleBar"
                android:label="@string/app_name" >
               
                   

                   
               

           
                        android:name="com.uncocoder.course.lessons.thread.ThreadSample2Activity"
                android:theme="@android:style/Theme.NoTitleBar"
                android:label="@string/app_name" >
           
                        android:name="com.uncocoder.course.lessons.thread.ThreadSample3Activity"
                android:theme="@android:style/Theme.NoTitleBar"
                android:label="@string/app_name" >
           
       

 

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


  1. package com.uncocoder.course.lessons.thread;

    import android.app.Activity;
    import android.content.Intent;
    import android.os.Bundle;
    import android.os.Handler;
    import android.util.Log;
    import android.view.KeyEvent;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.widget.Button;
    import android.widget.ScrollView;
    import android.widget.TextView;
    import com.uncocoder.course.lessons.R;

    public class ThreadSample1Activity extends Activity {

        /* تعریف اشاره گرهای مورد نیاز جهت اتصال به رابط گرافیک */
        private Button               btn_no_thread        = null;
        private Button               btn_single_thread    = null;
        private Button               btn_parallel_threads = null;
        private Button               btn_clear_log        = null;
        private Button               btn_next             = null;
        private ScrollView           scroll_content       = null;
        private TextView             txt_log              = null;

        /** متغیری برای اینکه تعیین کنیم آیا فقط روی لوگ کت نشان داده شود یا روی رابط گرافیک هم نشان داده شود */
        private final static boolean mCanLogToUi          = true;

        /** با استفاده از هندلر ها می توانیم از داخل هر تردی، مجموعه دستوری را در ترد اصلی اجرا کنیم */
        private Handler              handler              = new Handler();



        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.form_thread1);

            /* مقدار دهی اشاره گرهای رابط گرافیک و تعیین عملکرد آنها */
            initializeUi();
        }



        /** با استفاده از این می توانیم کنترل صفحه کلید سخت افزاری را در دست بگیریم */
        @Override
        public boolean onKeyDown(int keyCode, KeyEvent event) {
            if (keyCode == KeyEvent.KEYCODE_BACK) {
                /* به برنامه دستور خروج کامل را خواهیم داد */
                System.exit(0);
                return true;
            }

            /* اگر ما دستوری برای صفحه کلید نداشتیم، کار خودش را بکند */
            return super.onKeyDown(keyCode, event);
        }



        /** مقدار دهی اشاره گرهای رابط گرافیک و عملکرد آنها */
        private void initializeUi() {
            btn_no_thread = (Button) findViewById(R.id.btn_no_thread);
            btn_single_thread = (Button) findViewById(R.id.btn_single_thread);
            btn_parallel_threads = (Button) findViewById(R.id.btn_parallel_threads);
            btn_clear_log = (Button) findViewById(R.id.btn_clear_log);
            btn_next = (Button) findViewById(R.id.btn_next);
            scroll_content = (ScrollView) findViewById(R.id.scroll_content);
            txt_log = (TextView) findViewById(R.id.txt_log);

            btn_no_thread.setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View v) {
                    doWithoutThread();
                }
            });

            btn_single_thread.setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View v) {
                    doSingleThread();
                }
            });

            btn_parallel_threads.setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View v) {
                    doParallelThreads();
                }
            });

            btn_clear_log.setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View v) {
                    clearLog();
                }
            });

            btn_next.setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View v) {
                    /* اجرای اکتیویتی جدید و بستن کامل اکتیویری فعلی */
                    Intent intent = new Intent(ThreadSample1Activity.this, ThreadSample2Activity.class);
                    startActivity(intent);
                    finish();
                }
            });
        }



        /** صفجه حاول لوگ ها را خالی می کند و فقط یک عبارت لوگ در آن می نویسد */
        private void clearLog() {
            txt_log.setText("Log:");
        }



        /** یک عمل طولانی مدت که برای تست ها بکار می رود */
        private void heavyWeightWork() {
            String str = "";

            for (long i = 0; i < 1500; i++) {
                str += i + "\n";
            }
        }



        /** به پنجره لوگ کت و کنترل داخل برنامه دستور نمایش لوگ جدید را می دهیم */
        private void addLog(final String message) {

            if (mCanLogToUi) {

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

                    /** مجموعه دستور العملی که در ترد اصلی اجرا خواهد شد */
                    @Override
                    public void run() {
                        /* نمایش محتویات گذشته، رفتن به خط بعد و نمایش پیام جدید */
                        txt_log.setText(txt_log.getText().toString() + "\n" + message);

                        /* رفتن به انتهای لیست اسکرول */
                        scroll_content.fullScroll(View.FOCUS_DOWN);
                    }
                });
            }

            /* در هر صورت پیام را در لوگ کت می نویسیم */
            Log.i("LOG", message);
        }



        private void doWithoutThread() {
            addLog("With no thread Started");
            heavyWeightWork();
            addLog("With no thread Finished");
        }



        /** تست شماره یک */
        private void doSingleThread() {

            /* تعریف دستور العمل مورد نیاز برای اجرا، توجه کنید که سرخود اجرا نمی شود و ترد آنرا اجرا خواهد کرد */
            Runnable runnable = new Runnable() {

                @Override
                public void run() {
                    /* نمایش نام ترد که استارت شده است */
                    addLog(Thread.currentThread().getName() + " Started");

                    /* انجام عمل سنگین */
                    heavyWeightWork();

                    /* نمایش نام ترد که خاتمه یافته است */
                    addLog(Thread.currentThread().getName() + " Finished");
                }
            };

            /* تعریف یک نمونه از کلاس ترد و ارسال رانیبل مورد نظر به آن جهت اجرا */
            Thread thread = new Thread(runnable);

            /* تعیین نام ترد */
            thread.setName("Thread");

            /* شروع ترد یعنی اجرای دستورات داخل رانیبل */
            thread.start();
        }



        private void doParallelThreads() {
            /* تعریف دستور العمل مشترک مورد نیاز برای اجرا، توجه کنید که سرخود اجرا نمی شود و ترد آنرا اجرا خواهد کرد */
            Runnable runnable = new Runnable() {

                @Override
                public void run() {
                    /* نمایش نام ترد که استارت شده است */
                    addLog(Thread.currentThread().getName() + " Started");

                    /* انجام عمل سنگین */
                    heavyWeightWork();

                    /* نمایش نام ترد که خاتمه یافته است */
                    addLog(Thread.currentThread().getName() + " Finished");
                }
            };

            /* تعریف یک نمونه از کلاس ترد و ارسال رانیبل مورد نظر به آن جهت اجرا، همچنین تعریف نام ترد */
            Thread thread1 = new Thread(runnable);
            thread1.setName("Thread 1");

            /* تعریف یک نمونه از کلاس ترد و ارسال رانیبل مورد نظر به آن جهت اجرا، همچنین تعریف نام ترد */
            Thread thread2 = new Thread(runnable);
            thread2.setName("Thread 2");

            /* تعریف یک نمونه از کلاس ترد و ارسال رانیبل مورد نظر به آن جهت اجرا، همچنین تعریف نام ترد */
        &nb

مطالب مرتبط

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

دارولند

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

آف مکس

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

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

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

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

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

نمایندگی بوش

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

ایران بزرگ

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

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

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

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

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

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