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 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 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 ; } }

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

更多相关文章

  1. Android(安卓)Handler 消息传递机制
  2. Android(安卓)多线程编程:IntentService & HandlerThread
  3. Android(安卓)Service——在子线程中更新UI
  4. Android(安卓)Handler使用
  5. android - 为响应度而设计 - 开发文档翻译
  6. Android自用-----AsyncTask实现异步处理任务
  7. Android的Handler总结
  8. android的消息处理机制(图+源码分析)
  9. Android,Thread+Handler 线程 消息循环

随机推荐

  1. Android之圆形旋转动画
  2. android中使用local_manifest.xml添加软
  3. Android(安卓)display架构分析(五)
  4. Android自学笔记(番外篇):全面搭建Linux环境
  5. Android中visibility属性VISIBLE、INVISI
  6. Android链式方法显示Dialog
  7. 【Android(安卓)总结】缩写
  8. 14 Android(安卓)android 按钮效果的两种
  9. [置顶] androidの下拉菜单Spinner使用
  10. Android(安卓)实现部分文字高亮的三种方