根據一個筆試題引出的思考

tangsilian發表於2016-04-21

題目:頁面上現有ProgressBar控制元件progressBar,請用書寫執行緒以10秒的的時間完成其進度顯示工作

效果如下

佈局檔案和簡單 就是一個Progressbar
Activity的程式碼如下(其實我一直不知道改把activity叫什麼好 視窗?或者活動?)

public class ProgressTest extends Activity {
    private ProgressBar prs1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        setContentView(R.layout.progressbar);
        prs1 = (ProgressBar) findViewById(R.id.progressBar1);
        Thread thread = new Thread(new Runnable() {

            @Override
            public void run() {
                // TODO Auto-generated method stub
                int progressBarMax =prs1.getMax();
                while(prs1.getProgress()!=progressBarMax){
                    int progressBarnew=progressBarMax/10;

                    prs1.setProgress(prs1.getProgress()+progressBarnew);
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    //註釋的程式碼可以讓他一直跑
                    /*if((prs1.getProgress()+progressBarnew)==progressBarMax){
                        prs1.setProgress(progressBarnew);   
                    }*/
                }



            }


        }) 
        ;
        thread.start();
    }
}

這是第一種方式 在oncreat方法中新啟一個執行緒來給進度條加進度
講道理 這是在子執行緒中更新ui吧。

那我們就來看另一種方法


public class ProgressTest extends Activity {
    private ProgressBar prs1;
    private Handler handler = new Handler();
    private Runnable myRunnable = new Runnable() {
        public void run() {
            handler.postDelayed(this, 1000);
            int progressBarMax = prs1.getMax();
            if (prs1.getProgress() <= progressBarMax) {
                int progressBarnew = progressBarMax / 10;
                prs1.setProgress(prs1.getProgress() + progressBarnew);
            }

        }
    };


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        setContentView(R.layout.progressbar);
        prs1 = (ProgressBar) findViewById(R.id.progressBar1);
         handler.post(myRunnable);

    }


}

這是另一種方法 post(runnable)與handler繫結的執行緒上執行,不需要另外新建執行緒。
看post原始碼

   public final boolean post(Runnable r)
    {
       return  sendMessageDelayed(getPostMessage(r), 0);
    }

其實也是sendMessage方法的一種 。。。
講道理還是sendmessage。。。

利用Timer類和Timertask來實現

public class ProgressTest extends Activity {
    private ProgressBar prs1;
    Timer time = new Timer();
    Button btn1;
    private Handler handler = new Handler() {

        public void handleMessage(Message msg) {

            if (msg.what == 1) {

                int progressmax = prs1.getMax();
                if (prs1.getProgress() != progressmax) {
                    int progressnew = progressmax / 10;
                    prs1.setProgress(prs1.getProgress() + progressnew);
                }

            }

        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        setContentView(R.layout.progressbar);
        prs1 = (ProgressBar) findViewById(R.id.progressBar1);
        time.schedule(new TimerTask() {

            @Override
            public void run() {
                // TODO Auto-generated method stub
                Message msg = new Message();
                msg.what = 1;
                handler.sendMessage(msg);
            }

        }, 0, 1000);

    }

}

TimerTask的run方法並不是多執行緒的run方法,雖然實現了Runnable,但是僅僅是為了表示它是可執行的,並不代表它必須通過執行緒的方式來執行的。
Timer和TimerTask的簡單組合是多執行緒的嘛?不是,一個Timer內部包裝了“一個Thread”和“一個Task”佇列,這個佇列按照一定的方式將任務排隊處理,包含的執行緒在Timer的構造方法呼叫時被啟動,這個Thread的run方法無限迴圈這個Task佇列,若佇列為空且沒發生cancel操作,此時會一直等待,如果等待完成後,佇列還是為空,則認為發生了cancel從而跳出死迴圈,結束任務;迴圈中如果發現任務需要執行的時間小於系統時間,則需要執行,那麼根據任務的時間片從新計算下次執行時間,若時間片為0代表只執行一次,則直接移除佇列即可。

但是是否能實現多執行緒呢?可以,任何東西是否是多執行緒完全看個人意願,多個Timer自然就是多執行緒的,每個Timer都有自己的執行緒處理邏輯,當然Timer從這裡來看並不是很適合很多工在短時間內的快速排程,至少不是很適合同一個timer上掛很多工,在多執行緒的領域中我們更多是使用多執行緒中的:

Executors.newScheduledThreadPool

來完成對排程佇列中的執行緒池的處理,內部通過new ScheduledThreadPoolExecutor來建立執行緒池的Executor的建立,當然也可以呼叫:

Executors.unconfigurableScheduledExecutorService

方法來建立一個DelegatedScheduledExecutorService其實這個類就是包裝了下下scheduleExecutor,也就是這只是一個殼,英文理解就是被委派的意思,被託管的意思。

相關文章