现在我们通过一个更新ProgressBar的小案例来学习下Android的UI更新和消息机制。

如下图,点击“Start”按钮,进度条开始变化。



第一步:如下代码:

btnStart.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {for (int i = 0; i <= 100; i = i + 10) {bar.setProgress(i);try {Thread.sleep(1000);//每隔1S更新Bar} catch (InterruptedException e) {e.printStackTrace();}}}});

我们发现,

并没有进度条递变的效果,而是start按钮一直被占用,其他的任何操作都被阻塞了,还有可能报ANR。

因为只有一个主线程,而更新进度条是个耗时操作,程序就会暂时阻塞,所有我们可以另起一个线程来处理UI更新问题。

btnStart.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {new Thread() {public void run() {for (int i = 0; i <= 100; i = i + 10) {bar.setProgress(i);try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}};}.start();}});

这样的改变,或许能得到我们的需求,可以更新ProgressBar,但是如果你连续点击Start按钮,则会发现,进度条的变化凌乱了。因为这个操作是并发的,而界面只有一个,多次点击Button,则会多次创建多个线程,每个线程都会对界面进行改变,这样的操作是不安全的。所以Android规定,所有的UI更新操作必须放在UI线程中进行,即主线程中去执行。那么我们该怎么做才能让主线程同步操作来更新UI。

正确的做法:

Handler + Runnable

1)创建Runnable对象,UI更新操作主要在run()方法中。

2)创建Handler对象,调用handler.post(r),把r对象加入到线程队列中,然后线程队列就开始执行run()

3)run()中调用UI更新代码,如果是循环操作,可以用handler.postDelayed(r,1000).表示隔1秒后再把线程对象r加入到线程队列中,然后再去调用run().

注意:所有操作都在一个线程中,因为没有调用Thread的start()。

一般来说在工作线程中执行耗时任务,当任务完成时,会返回UI线程,一般是更新UI。这时有两种方法可以达到目的。一种是handler.sendMessage。发一个消息,再根据消息,执行相关任务代码。另一种是handler.post(r)。r是要执行的任务代码。意思就是说r的代码实际是在UI线程执行的。可以写更新UI的代码。(工作线程是不能更新UI的)

具体操作请看如下代码:

方法一:handler.post(r);

public class MainActivity2 extends Activity {ProgressBar bar = null;private Button btnStart = null;private Button btnEnd = null;Handler handler = new Handler();//创建Runnable对象Runnable r = new Runnable() {int i = 0;// 用来更新bar@Overridepublic void run() {System.out.println(Thread.currentThread().getId() + "-----run--->"+ Thread.currentThread().getName());i = i + 10;bar.setProgress(i);handler.postDelayed(r, 1000);}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);bar = (ProgressBar) findViewById(R.id.progressBar1);btnStart = (Button) findViewById(R.id.start);btnEnd = (Button) findViewById(R.id.stop);btnStart.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {System.out.println(Thread.currentThread().getId()+ "-----Main--->" + Thread.currentThread().getName());// 把r加入到线程队列,然后线程队列里就开始执行runnable对象中的run()handler.post(r);};});btnEnd.setOnClickListener(new View.OnClickListener() {public void onClick(View v) {handler.removeCallbacks(r);}});}}

方法2:handler.sendMessage();

Handler handler = new Handler() {public void handleMessage(Message msg) {switch (msg.what) {case 0x333:bar.setProgress(msg.arg1);postDelayed(r, 1000);break;}};};Runnable r = new Runnable() {int i = 10;@Overridepublic void run() {System.out.println(Thread.currentThread().getId() + "<>"+ Thread.currentThread().getName());Message msg = new Message();msg.what = 0x333;i = i + 10;msg.arg1 = i;handler.sendMessage(msg);};};start.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {handler.post(r);}});


更多相关文章

  1. Android(安卓)-HandleThread-给线程传参数
  2. 操作Android中联系人,通话记录,短息,的URI
  3. android线程间通信和主线程更新ui
  4. Android下的JNI创建多线程的方法
  5. Android实现录屏和截屏功能
  6. android ConcurrentHashMap的使用
  7. 理解杀进程的实现原理
  8. Android开发:关于Android冷启动优化(从3.63%降到0.95%)
  9. Android之网络操作 - 从网络获取图片或网页

随机推荐

  1. android 深入理解LayoutInflater
  2. libgdx一个完整的处理流程
  3. Parcel了解
  4. android中使用surfaceview进行视频播放
  5. Android(安卓)PopupMenu显示
  6. android获取网页数据的几种方式
  7. android中用到的资源Color
  8. AndroidAnnotations——Injecting Views
  9. 水波纹效果---3环波纹
  10. Android:Android布局方式