鍍金池/ 教程/ Android/ 線程 Bezier 曲線
Dialog 顯示圖像
線程 Bezier 曲線
創(chuàng)建應(yīng)用程序框架
引路蜂二維圖形庫(kù)簡(jiǎn)介及顏色示例
Android 應(yīng)用基本概念
Intents 和 Intent Filters
安裝開(kāi)發(fā)環(huán)境
Option Menu 畫筆示例
自定義對(duì)話框 Transform
數(shù)據(jù)綁定 Data Binding
概述
Broadcast Receiver 短信觸發(fā)示例
發(fā)布應(yīng)用
自定義 Adapter 顯示列表
RadioButton 多邊形及路徑繪制
訪問(wèn) Internet 繪製在線地圖
第一個(gè)應(yīng)用 Hello World
Activities
Button 畫刷示例
使用資源 Resources
Context Menu 繪制幾何圖形
用戶界面設(shè)計(jì)
引路蜂二維圖形繪制實(shí)例功能定義

線程 Bezier 曲線

Android 中使用線程 Thread 的方法和 Java SE 相同。和大多數(shù) OS 系統(tǒng)一樣,Android 中也有稱為 UI Thread 的主線程。UI Thread 主要用來(lái)給相應(yīng)的 Widget 分發(fā)消息,包括繪制(Drawing)事件。UI Thread 也是用來(lái)處理用戶交互事件的線程。比如:如果你按下屏幕上某個(gè)按鈕,UI 線程則將Touch 事件通知對(duì)應(yīng)的控件(Widgets),Widget 則將其狀態(tài)設(shè)置成“按下”,并把“重繪”(Invalidate)事件發(fā)到 Event Queue 中去。 UI 線程從 Event Queue 中讀取事件后通知Widgets 重畫自身。

如果你的應(yīng)用設(shè)計(jì)不好的話, UI 線程的這種單線程模式就會(huì)導(dǎo)致非常差的用戶響應(yīng)性能。特別是你將一些費(fèi)時(shí)的操作如網(wǎng)絡(luò)訪問(wèn)或數(shù)據(jù)庫(kù)訪問(wèn)也放在 UI 線程中,這些操作會(huì)造成用戶界面無(wú)反應(yīng),最糟糕的是,如果 UI 線程阻塞超過(guò)幾秒(5秒),著名的 ANR 對(duì)話框就會(huì)出現(xiàn):

http://wiki.jikexueyuan.com/project/android-development-tutorial/images/29.png" alt="" />

所以在設(shè)計(jì)應(yīng)用時(shí),需要把一些費(fèi)時(shí)的任務(wù)使用單獨(dú)的工作線程來(lái)運(yùn)行避免阻塞 UI 線程,但是如果在工作線程中想更新 UI 線程的話,不能直接在工作線程中更新 UI,這是因?yàn)?UI 線程不是“Thread Safe”。因此所有 UI 相關(guān)的操作一般必須在 UI Thread 中進(jìn)行。

Android OS 提供了多種方法可以用在非 UI 線程訪問(wèn) UI 線程。

  • Activity.runOnUiThread(Runnable)
  • View.post(Runnable)
  • View.postDelayed(Runnable, long)
  • Handler

Bezier 示例動(dòng)態(tài)顯示 Bezier 曲線,使用了 Activity.runOnUiThread 來(lái)更新屏幕,完整代碼如下:

public class Bezier extends Graphics2DActivity
implements OnClickListener,Runnable{ 

 /**
     * The animation thread.
     */
    private Thread thread;
    private volatile boolean stopThread=false;
    private boolean stopOrNot=false;
    boolean drawn;
    /**
     * The random number generator.
     */
    static java.util.Random random = new java.util.Random();
    /**
     * The animated path
     */
    Path path = new Path();
    /**
     * Red brush used to fill the path.
     */
    SolidBrush brush = new SolidBrush(Color.RED);
    private static final int NUMPTS = 6;
    private int animpts[] = new int[NUMPTS * 2];
    private int deltas[] = new int[NUMPTS * 2];
    long startt, endt;

 private Button btnOptions;
 @Override
 protected void drawImage() {
   drawDemo(100, 100);

 }

 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.beziers);
  graphic2dView
     = (GuidebeeGraphics2DView) findViewById(R.id.graphics2dview);
  btnOptions = (Button) findViewById(R.id.btnStopStart);
  btnOptions.setOnClickListener(this);
  reset(100,100);
  if (thread == null) {
            thread = new Thread(this);
            thread.start();
        }

 } 

 @Override
 public void onClick(View view) {

  if(!stopOrNot){
   btnOptions.setText("Start");
      stopThread=true;
  }
  else{
   stopThread=false;
   btnOptions.setText("Stop");
   if (thread == null) {
             thread = new Thread(this);
             thread.start();
         }
  }
  stopOrNot=!stopOrNot;

 } 
    /**
     * Generates new points for the path.
     */
    private void animate(int[] pts, int[] deltas,
      int i, int limit) {
        int newpt = pts[i] + deltas[i];
        if (newpt <= 0) {
            newpt = -newpt;
            deltas[i] = (random.nextInt() & 0x00000003)
            + 2;
        } else if (newpt >= limit) {
            newpt = 2 * limit - newpt;
            deltas[i] = -((random.nextInt() & 0x00000003)
              + 2);
        }
        pts[i] = newpt;
    } 

    /**
     * Resets the animation data.
     */
    private void reset(int w, int h) {
        for (int i = 0; i < animpts.length; i += 2) {
            animpts[i + 0]
                    = (random.nextInt() & 0x00000003)
                    * w / 2;
            animpts[i + 1]
                    = (random.nextInt() & 0x00000003)
                    * h / 2;
            deltas[i + 0]
                   = (random.nextInt() & 0x00000003)
                   * 6 + 4;
            deltas[i + 1]
                   = (random.nextInt() & 0x00000003)
                   * 6 + 4;
            if (animpts[i + 0] > w / 2) {
                deltas[i + 0] = -deltas[i + 0];
            }
            if (animpts[i + 1] > h / 2) {
                deltas[i + 1] = -deltas[i + 1];
            }
        }
    } 

    final Runnable updateCanvas = new Runnable() {
  public void run() {
   int offsetX = (graphic2dView.getWidth() -
     SharedGraphics2DInstance.CANVAS_WIDTH) / 2;
   int offsetY = (graphic2dView.getHeight()
     - SharedGraphics2DInstance.CANVAS_HEIGHT) / 2;
   graphic2dView.invalidate(offsetX,offsetY,
     offsetX+100,offsetY+100);
  }
 };
    /**
     * Sets the points of the path and draws and fills the path.
     */
    private void drawDemo(int w, int h) {
        for (int i = 0; i < animpts.length; i += 2) {
            animate(animpts, deltas, i + 0, w);
            animate(animpts, deltas, i + 1, h);
        }
        //Generates the new pata data.
        path.reset();
        int[] ctrlpts = animpts;
        int len = ctrlpts.length;
        int prevx = ctrlpts[len - 2];
        int prevy = ctrlpts[len - 1];
        int curx = ctrlpts[0];
        int cury = ctrlpts[1];
        int midx = (curx + prevx) / 2;
        int midy = (cury + prevy) / 2;
        path.moveTo(midx, midy);
        for (int i = 2; i <= ctrlpts.length; i += 2) {
            int x1 = (curx + midx) / 2;
            int y1 = (cury + midy) / 2;
            prevx = curx;
            prevy = cury;
            if (i < ctrlpts.length) {
                curx = ctrlpts[i + 0];
                cury = ctrlpts[i + 1];
            } else {
                curx = ctrlpts[0];
                cury = ctrlpts[1];
            }
            midx = (curx + prevx) / 2;
            midy = (cury + prevy) / 2;
            int x2 = (prevx + midx) / 2;
            int y2 = (prevy + midy) / 2;
            path.curveTo(x1, y1, x2, y2, midx, midy);
        }
        path.closePath();
        // clear the clipRect area before production 

        graphics2D.clear(Color.WHITE);
        graphics2D.fill(brush, path); 

        this.runOnUiThread(updateCanvas); 
    }

    public void run() {
        Thread me = Thread.currentThread(); 

        if (!drawn) {
            synchronized (this) {
                graphics2D.clear(Color.WHITE);
                graphics2D.fill(brush, path);
                graphic2dView.refreshCanvas();
                drawn = true;
            }
        }
        while (thread == me && !stopThread) {
            drawDemo(100,100);
        }
        thread = null;
    }
}

http://wiki.jikexueyuan.com/project/android-development-tutorial/images/30.png" alt="" />

除了上述的方法外,Android 還提供了 AsyncTask 類以簡(jiǎn)化工作線程與 UI 線程之間的通信。這里不詳述。此外,上面 Bezier 曲線動(dòng)畫在屏幕上顯示時(shí)有閃爍的現(xiàn)象,這是動(dòng)態(tài)顯示圖像的一個(gè)常見(jiàn)問(wèn)題,后面將專門討論。