1. 程式人生 > >Android初級開發----用Handle機制更新UI介面

Android初級開發----用Handle機制更新UI介面

  1. 引入:
    之前對Android講義的一個小專案——–隨指尖移動的小球進行修改,利用View中的invalidate()方法實現每次觸碰螢幕更新(UI執行緒)小球的位置並且附加判斷大小,實現觸碰更新小球大小隨之更改顏色.
    API引入:

invalidate()
每次執行invalidate()方法都會呼叫ondraw()

更新介面操作
ondraw()用於重新整理介面此處為canvas(畫布)
2. 簡單原始碼:

變色小球1.0

新建一個DrawView類繼承View



package com.example.drawview_without_thread;


import android.content.Context;
import
android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.widget.Button; public class DrawView extends View{ public float currentX = 200
; //球起始位置 public float currentY = 500; // String touchsign = "Never touch"; boolean range = true; //大小判斷標記 Paint p = new Paint(); //畫筆 public DrawView(Context context) { //建構函式1 直接定義檢視 //final DrawView draw = new DrawView(this); super(context); } public
DrawView(Context context,AttributeSet set) { //建構函式2 傳入AttributeSet set在佈局檔案xml中載入屬性 super(context,set); } int [] colors = new int[]{ Color.RED, Color.BLUE, Color.GREEN, Color.MAGENTA, Color.YELLOW, }; int size = 10; //初始半徑10 static int colornum = 0; //大小,顏色下標序號 @Override public void onDraw(Canvas canvas){ //canvas 畫布 super.onDraw(canvas); if (size >= 350) { range = false; //大小判斷 }if(size <= 20) { range = true; } //半徑視情況 改變 if (range) { size += 15; Log.d("DrawTest", "半徑遞增:"+ size ); } else { size -= 15; Log.d("DrawTest", "半徑遞減:"+ size ); } colornum = ++colornum % colors.length; //每次觸碰滾動換色 p.setColor(colors[colornum]); Log.d("Color", "新畫筆顏色"+colornum); //設定位置,大小,顏色 canvas.drawCircle(currentX, currentY, size, p); //設定點的半徑和位置 } @Override //touch reaction public boolean onTouchEvent(MotionEvent event){ currentX = event.getX(); currentY = event.getY(); //touchsign = "touched"; //改變表示已經觸碰 invalidate(); //用來重新整理View,系統會自動回撥 View的onDraw()方法 // 只要是view的子類,都會從view中繼承invalidate和postInvalidate這兩個方法。 // // 當invalidate方法被呼叫的時候,就是在告訴系統,當前的view發生改變,應該儘可能快的來進行重繪。 // // 這個方法僅能在UI(主)執行緒中被呼叫。如果想要在工作執行緒中進行重新整理介面,那麼其他的方法將會被呼叫,這個方法就是postInvalidate方法。 return true; } }

為了讓每次點選都改變小球位置,通過一個顏色陣列colors來獲取當前週期性改變的顏色,於是我想為什麼不額外建立一個執行緒實現改變顏色呢?
問題引入:

Android制訂了一條規則:它只允許(主)User Interface執行緒修改Activity裡的UI元件,當程式第一次啟動,Main Thread主要負責處理與UI相關的事件,如按鈕和使用者螢幕點選事件.
  • 引用Handler類
    官方文件解釋

    Handler
    A Handler allows you to send and process Message and Runnable objects associated with a thread’s MessageQueue. Each Handler instance is associated with a single thread and that thread’s message queue. When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it – from that point on, it will deliver messages and runnables to that message queue and execute them as they come out of the message queue.

    Handler : 解決,處理.這裡可以理解為訊息處理器.
    大概的意思是,一個Handler可以讓你傳送訊息,這個訊息會推入MessageQueue(訊息佇列)裡等待處理.
  • MessageQueue管家——–Looper
    Looper類中的loop()方法會不斷的取出訊息佇列的Message傳送給Handler,並且將Message傳遞給Handler的handleMessage()方法中.
  • handleMessage() 常用結構:
    大概流程可以參考此圖:

Dh

final Handler handler = new Handler()
        {
            @Override
            public void handleMessage(Message msg)     //接受通過Looper從MessageQueue佇列提取對應傳送過來的訊息.
            {
                if (msg.what == 0x123) {
                    //新執行緒要做的事...                    
                }
                super.handleMessage(msg);
            }
        };     
//              激發事件
                @Override
                public void run() {

                   Log.d("Sent", "向處理器傳送訊息");
                   handler.sendEmptyMessage(0x123);

               }
           }).start();

通過對msg的判斷新訊息是否符合該處理操作,如果符合則對應處理.

所以利用額外的一個執行緒實現週期性改變,如今不用每次點選螢幕只要啟動執行緒就會在原地週期改變顏色.注意的是,我們不是新建一個執行緒來改變UI介面,而是新建一個執行緒來發送訊息給Handler,讓位於主執行緒的Handler更新介面

變色小球2.0

修改DrawView的部分程式碼,並且在MainActivity新建Handler處理器,相關程式碼如下:

修改DrawView:

@Override
    public void onDraw(Canvas canvas){          //canvas 畫布
        super.onDraw(canvas);
        if (size >= 350) {
            range = false;  //大小判斷
        }if(size <= 20) {
            range = true;
        }
        //半徑視情況 改變
        if (range) {
            size += 15;
            Log.d("DrawTest", "半徑遞增:"+ size );
        }
        else {
            size -= 15;
            Log.d("DrawTest", "半徑遞減:"+ size );
        }

        Log.d("Color", "新畫筆顏色"+colornum);
        //設定位置,大小,顏色
        canvas.drawCircle(currentX, currentY, size, p); //設定點的半徑和位置
    }

    public void thread_change() {//通過UI執行緒的handler來呼叫

        colornum = ++colornum % colors.length;  //週期性滾動換色
        p.setColor(colors[colornum]);

        Log.d("DrawTest", "新執行緒重設畫筆顏色");
        invalidate();    //加入了原地更新介面的方法  
    }

修改MainActivity:
加入Handler

//處理器
        final Handler handler = new Handler()
        {
            @Override
            public void handleMessage(Message msg)     //接受通過Looper從MessageQueue佇列提取對應傳送過來的訊息.
            {
                if (msg.what == 0x123) {
                    draw.thread_change();
                }
                super.handleMessage(msg);
            }
        };


        //按鈕
        Button shine = (Button)findViewById(R.id.shine);
        shine.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View arg0) {
                Log.d("DrawTest", "點選按鈕");

                new Timer().schedule(new TimerTask() {

                    @Override
                    public void run() {

                        Log.d("DrawTest", "向處理器傳送訊息");
                        handler.sendEmptyMessage(0x123);

                    }
                }, 0, 500);       //新執行緒用timer週期性的向handler傳送訊息,此處也可以通過start()來啟動新執行緒
            }
        });

此時handleMessage()就是在主執行緒執行的,所以可以進行UI操作.

參考來源:<瘋狂android講義>p208,<第一行程式碼>p348