android中Handler的初步认识(三)

        在上一个例子中,最终我们发现,其实用到的线程只有一个,那就是程序的主线程(UI线程)。那么怎么把那个例子改成用新建的线程来实现呢,今天我尝试了一下,写了下面这个小程序。

        当然,首先要声明一下,今天的这个例子并不是推荐的写法,而是我为了学习多线程而写的例子(貌似更常用的是AsyncTask,而不是Thread和Handler去更新UI)。


        在今天的这个例子中,我用到了Looper,先说说Looper是什么


在API中是这么解释Lopper的:Class used to run a message loop for a thread。我的理解是Looper是用来控制message queue的类


Looper常用的几个用法有:

Looper.prepare()                安卓的主线程中会默认调用这个方法来创建消息队列。但是,如果我们自己新建的线程,如果需要消息队列,则需要手动调用这个方法。

Looper.loop()                     这个方法用在prepare()方法之后,调用该方法之后,进入消息循环。

Looper.getMainLooper()  我在代码中用到了这个方法,这个方法的作用是获得主线程的Looper实例

Looper.myLooper()            这个方法用到获取当前线程的Looper实例


今天这个例子和第二篇中实现的功能一下,我只不过改了一个写法而已,下面是代码:

package com.example.handler2;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ProgressBar;

public class MainActivity extends Activity {

	Button startButton = null;
	Button stopButton = null;
	ProgressBar progressbar = null;
	Thread counter = null;

	//获取主线程的looper
	Looper looper = Looper.getMainLooper();

	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		startButton = (Button) findViewById(R.id.startButton);
		stopButton = (Button) findViewById(R.id.stopButton);
		progressbar = (ProgressBar) findViewById(R.id.progressBar);
		
		//为button绑定onclicklistener
		startButton.setOnClickListener(new ButtonOnclickListener());
		stopButton.setOnClickListener(new stopOnclickListener());
	}

	class ButtonOnclickListener implements OnClickListener{
		public void onClick(View v) {
			progressbar.setVisibility(View.VISIBLE);
			counter = new Thread(){
				int i = 1;
				@Override
				public void run() {
					// TODO Auto-generated method stub
					i += 10;
					Message msg = handler.obtainMessage();
					msg.arg1 = i;
					
					//让线程延迟一秒
					try {
						Thread.sleep(1000);
					} catch (Exception e) {
						e.printStackTrace();
					}
					Log.i("run", "run "+i+"%");
					Log.i("run", Thread.currentThread().getName());
					msg.sendToTarget();  			
			
				}
			};
			counter.start();
		}		
	}
	
	class stopOnclickListener implements OnClickListener{
		public void onClick(View v) {		
			//从message queue 中去掉run
			handler.removeCallbacks(counter);
			//让progressbar置成隐藏
			progressbar.setVisibility(View.GONE);
		}		
	}
	
	//将handler与主线程关联
	Handler handler = new Handler(looper){
		public void handleMessage(android.os.Message msg) {
			
			int i =msg.arg1;
			//根据message中传来的参数控制进度条
			progressbar.setProgress(i);
			
			Log.i("run", Thread.currentThread().getName());

						
			if(i<100){
				handler.post(counter);
			}else{
				handler.removeCallbacks(counter);
				progressbar.setVisibility(View.GONE);
			}
		};
	};	
}

       
         这段代码,和第二篇中最大的差别就是,当我点击启动按钮后,调用的不是主线程的run,而是我新建的线程。

        但是因为安卓不允许我们在主线程之外的线程中对UI进行修改,所以我在新建的线程中只是进行计数,然后将计数的结果通过message传递到主线程中,在主线程中更新进度条。

         


遗留问题:

         本来这个例子到这里就结束了,但是,我为了深入了解一下就在我新建的线程的run中和主线程Handler的handlerMessage方法中打印了当前线程的名称:

结果如下:


android中Handler的初步认识(三)        


        按照我最初的理解,在日志中应该是主线程和我的线程交替写入日志,但是实际的情况是在第一次是counter线程,后面打印的都是主线程

        请问各位,有谁知道这是为什么吗?


        我看到在API中Handler的post方法是这么说明的:Causes the Runnable r to be added to the message queue. The runnable will be run on the thread to which this handler is attached.

         难道是,我使用了post方法,就相当于把counter线程的run中的代码拷贝中主线程中去执行了吗?如果有谁知道麻烦为我解答一下,不甚感激!

android中Handler的初步认识(三),布布扣,bubuko.com

android中Handler的初步认识(三)

上一篇:ios 获取当前wifi名称


下一篇:IOS UI 第三篇:基本UI