Android开发速成简洁教程十九:线程 Bezier曲线

移动开发 Android
Android中使用线程Thread的方法和Java SE相同。和大多数OS系统一样,Android中也有称为UI Thread的主线程。UI Thread 主要用来给相应的Widget分发消息,包括绘制(Drawing)事件。UI Thread 也是用来处理用户交互事件的线程。

Android中使用线程Thread的方法和Java SE相同。和大多数OS系统一样,Android中也有称为UI Thread的主线程。UI Thread 主要用来给相应的Widget分发消息,包括绘制(Drawing)事件。UI Thread 也是用来处理用户交互事件的线程。比如:如果你按下屏幕上某个按钮,UI 线程则将Touch 事件通知对应的控件(Widgets),Widget 则将其状态设置成“按下”,并把“重绘”(Invalidate)事件发到Event Queue中去。 UI线程从Event Queue中读取事件后通知Widgets重画自身。 

如果你的应用设计不好的话, UI线程的这种单线程模式就会导致非常差的用户响应性能。特别是你将一些费时的操作如网络访问或数据库访问也放在UI线程中,这些操作会造成用户界面无反应,最糟糕的是,如果UI线程阻塞超过几秒(5秒),著名的ANR对话框就会出现: 

 

所以在设计应用时,需要把一些费时的任务使用单独的工作线程来运行避免阻塞UI线程,但是如果在工作线程中想更新UI线程的话,不能直接在工作线程 中更新UI,这是因为UI线程不是“Thread Safe”。因此所有UI相关的操作一般必须在UI Thread中进行。 

Android OS提供了多种方法可以用在非UI线程访问UI线程。 

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

Bezier 示例动态显示Bezier曲线,使用了Activity.runOnUiThread 来更新屏幕,完整代码如下:

  1. 1   public class Bezier extends Graphics2DActivity 
  2. 2   implements OnClickListener,Runnable{  
  3. 3     
  4. 4    /** 
  5. 5        * The animation thread. 
  6. 6        */ 
  7. 7       private Thread thread; 
  8. 8       private volatile boolean stopThread=false
  9. 9       private boolean stopOrNot=false
  10. 10      boolean drawn; 
  11. 11      /** 
  12. 12       * The random number generator. 
  13. 13       */ 
  14. 14      static java.util.Random random = new java.util.Random(); 
  15. 15      /** 
  16. 16       * The animated path 
  17. 17       */ 
  18. 18      Path path = new Path(); 
  19. 19      /** 
  20. 20       * Red brush used to fill the path. 
  21. 21       */ 
  22. 22      SolidBrush brush = new SolidBrush(Color.RED); 
  23. 23      private static final int NUMPTS = 6
  24. 24      private int animpts[] = new int[NUMPTS * 2]; 
  25. 25      private int deltas[] = new int[NUMPTS * 2]; 
  26. 26      long startt, endt; 
  27. 27       
  28. 28   private Button btnOptions; 
  29. 29   @Override 
  30. 30   protected void drawImage() { 
  31. 31     drawDemo(100100); 
  32. 32      
  33. 33   } 
  34. 34     
  35. 35   public void onCreate(Bundle savedInstanceState) { 
  36. 36    super.onCreate(savedInstanceState); 
  37. 37    setContentView(R.layout.beziers); 
  38. 38    graphic2dView 
  39. 39       = (GuidebeeGraphics2DView) findViewById(R.id.graphics2dview); 
  40. 40    btnOptions = (Button) findViewById(R.id.btnStopStart); 
  41. 41    btnOptions.setOnClickListener(this); 
  42. 42    reset(100,100); 
  43. 43    if (thread == null) { 
  44. 44              thread = new Thread(this); 
  45. 45              thread.start(); 
  46. 46          } 
  47. 47      
  48. 48   }  
  49. 49    
  50. 50   @Override 
  51. 51   public void onClick(View view) { 
  52. 52      
  53. 53    if(!stopOrNot){ 
  54. 54     btnOptions.setText("Start"); 
  55. 55        stopThread=true
  56. 56    } 
  57. 57    else
  58. 58     stopThread=false
  59. 59     btnOptions.setText("Stop"); 
  60. 60     if (thread == null) { 
  61. 61               thread = new Thread(this); 
  62. 62               thread.start(); 
  63. 63           } 
  64. 64    } 
  65. 65    stopOrNot=!stopOrNot; 
  66. 66      
  67. 67   }  
  68. 68      /** 
  69. 69       * Generates new points for the path. 
  70. 70       */ 
  71. 71      private void animate(int[] pts, int[] deltas, 
  72. 72        int i, int limit) { 
  73. 73          int newpt = pts[i] + deltas[i]; 
  74. 74          if (newpt <= 0) { 
  75. 75              newpt = -newpt; 
  76. 76              deltas[i] = (random.nextInt() & 0x00000003
  77. 77              + 2
  78. 78          } else if (newpt >= limit) { 
  79. 79              newpt = 2 * limit - newpt; 
  80. 80              deltas[i] = -((random.nextInt() & 0x00000003
  81. 81                + 2); 
  82. 82          } 
  83. 83          pts[i] = newpt; 
  84. 84      }  
  85. 85    
  86. 86      /** 
  87. 87       * Resets the animation data. 
  88. 88       */ 
  89. 89      private void reset(int w, int h) { 
  90. 90          for (int i = 0; i < animpts.length; i += 2) { 
  91. 91              animpts[i + 0
  92. 92                      = (random.nextInt() & 0x00000003
  93. 93                      * w / 2
  94. 94              animpts[i + 1
  95. 95                      = (random.nextInt() & 0x00000003
  96. 96                      * h / 2
  97. 97              deltas[i + 0
  98. 98                     = (random.nextInt() & 0x00000003
  99. 99                     * 6 + 4
  100. 100             deltas[i + 1
  101. 101                    = (random.nextInt() & 0x00000003
  102. 102                    * 6 + 4
  103. 103             if (animpts[i + 0] > w / 2) { 
  104. 104                 deltas[i + 0] = -deltas[i + 0]; 
  105. 105             } 
  106. 106             if (animpts[i + 1] > h / 2) { 
  107. 107                 deltas[i + 1] = -deltas[i + 1]; 
  108. 108             } 
  109. 109         } 
  110. 110     }  
  111. 111   
  112. 112     final Runnable updateCanvas = new Runnable() { 
  113. 113   public void run() { 
  114. 114    int offsetX = (graphic2dView.getWidth() - 
  115. 115      SharedGraphics2DInstance.CANVAS_WIDTH) / 2
  116. 116    int offsetY = (graphic2dView.getHeight() 
  117. 117      - SharedGraphics2DInstance.CANVAS_HEIGHT) / 2
  118. 118    graphic2dView.invalidate(offsetX,offsetY, 
  119. 119      offsetX+100,offsetY+100); 
  120. 120   } 
  121. 121  }; 
  122. 122     /** 
  123. 123      * Sets the points of the path and draws and fills the path. 
  124. 124      */ 
  125. 125     private void drawDemo(int w, int h) { 
  126. 126         for (int i = 0; i < animpts.length; i += 2) { 
  127. 127             animate(animpts, deltas, i + 0, w); 
  128. 128             animate(animpts, deltas, i + 1, h); 
  129. 129         } 
  130. 130         //Generates the new pata data. 
  131. 131         path.reset(); 
  132. 132         int[] ctrlpts = animpts; 
  133. 133         int len = ctrlpts.length; 
  134. 134         int prevx = ctrlpts[len - 2]; 
  135. 135         int prevy = ctrlpts[len - 1]; 
  136. 136         int curx = ctrlpts[0]; 
  137. 137         int cury = ctrlpts[1]; 
  138. 138         int midx = (curx + prevx) / 2
  139. 139         int midy = (cury + prevy) / 2
  140. 140         path.moveTo(midx, midy); 
  141. 141         for (int i = 2; i <= ctrlpts.length; i += 2) { 
  142. 142             int x1 = (curx + midx) / 2
  143. 143             int y1 = (cury + midy) / 2
  144. 144             prevx = curx; 
  145. 145             prevy = cury; 
  146. 146             if (i < ctrlpts.length) { 
  147. 147                 curx = ctrlpts[i + 0]; 
  148. 148                 cury = ctrlpts[i + 1]; 
  149. 149             } else { 
  150. 150                 curx = ctrlpts[0]; 
  151. 151                 cury = ctrlpts[1]; 
  152. 152             } 
  153. 153             midx = (curx + prevx) / 2
  154. 154             midy = (cury + prevy) / 2
  155. 155             int x2 = (prevx + midx) / 2
  156. 156             int y2 = (prevy + midy) / 2
  157. 157             path.curveTo(x1, y1, x2, y2, midx, midy); 
  158. 158         } 
  159. 159         path.closePath(); 
  160. 160         // clear the clipRect area before production  
  161. 161   
  162. 162         graphics2D.clear(Color.WHITE); 
  163. 163         graphics2D.fill(brush, path);  
  164. 164   
  165. 165         this.runOnUiThread(updateCanvas);  
  166. 166     } 
  167. 167      
  168. 168       
  169. 169   
  170. 170     public void run() { 
  171. 171         Thread me = Thread.currentThread();  
  172. 172   
  173. 173         if (!drawn) { 
  174. 174             synchronized (this) { 
  175. 175                 graphics2D.clear(Color.WHITE); 
  176. 176                 graphics2D.fill(brush, path); 
  177. 177                 graphic2dView.refreshCanvas(); 
  178. 178                 drawn = true
  179. 179             } 
  180. 180         } 
  181. 181         while (thread == me && !stopThread) { 
  182. 182             drawDemo(100,100); 
  183. 183         } 
  184. 184         thread = null
  185. 185     } 
  186. 186 } 

 

除了上述的方法外,Android还提供了AsyncTask类以简化工作线程与UI线程之间的通信。这里不详述。此外,上面Bezier曲线动画在屏幕上显示时有闪烁的现象,这是动态显示图像的一个常见问题,后面将专门讨论。

责任编辑:闫佳明 来源: imobilebbs
相关推荐

2013-12-26 15:10:08

Android开发应用和框架Linux 内核

2013-12-26 15:43:07

Android开发Android应用Activities

2013-12-26 15:18:09

Android开发安装开发环境

2013-12-27 14:05:22

Android开发Android应用Dialog

2013-12-27 14:34:46

Android开发Android应用短信触发示例

2013-12-27 16:06:10

Android开发Android应用发布应用

2013-12-27 13:27:05

Android开发Android应用RadioButton

2013-12-26 15:46:30

Android开发Android应用用户界面设计

2013-12-26 15:34:19

Android开发Android应用基本概念

2013-12-26 16:24:13

Android开发Android应用Intents

2013-12-27 13:49:22

Android开发Android应用Button

2013-12-27 12:51:44

Android开发Android应用引路蜂

2013-12-26 16:59:12

Android开发Android应用数据绑定Data Bi

2013-12-27 15:31:26

Android开发Android应用资源Resources

2013-12-26 16:46:21

2013-12-27 13:00:30

Android开发Android应用Context Men

2013-12-26 17:08:36

Android开发Android应用自定义Adapter显

2013-12-27 15:11:17

Android开发访问Internet绘制在线地图

2013-12-27 14:10:36

Android开发Android应用Transform

2013-12-27 12:42:15

Android开发Android应用引路蜂
点赞
收藏

51CTO技术栈公众号