第六步:Handler与多线程,简单使用。

直接上例子代码:

public class MainActivity extends Activity {

	private Button myButton = null;
	private ProgressBar myProgressBar = null;
	
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		myProgressBar = (ProgressBar)findViewById(R.id.myProgressBar);
		myButton = (Button)findViewById(R.id.myButton);
		myButton.setOnClickListener(new MyButtonListener());
	}
	
	class MyButtonListener implements OnClickListener{

		@Override
		public void onClick(View v) {
			// TODO Auto-generated method stub
			myProgressBar.setVisibility(View.VISIBLE);
			updateBarHandler.post(updateThread);
		}
		
		
	}
	
	Handler updateBarHandler = new Handler(){

		@Override
		public void handleMessage(Message msg) {
			// TODO Auto-generated method stub
			myProgressBar.setProgress(msg.arg1);
			updateBarHandler.post(updateThread);
		}
	};
	
	Runnable updateThread = new Runnable() {
		int length = 0;
		
		@Override
		public void run() {
			// TODO Auto-generated method stub
			length += 10;
			Message msg = updateBarHandler.obtainMessage();
			msg.arg1 = length;
			try{
				Thread.sleep(1000);
			}
			catch(InterruptedException e){
				e.printStackTrace();
			}
			updateBarHandler.sendMessage(msg);
			if (length == myProgressBar.getMax()){
				updateBarHandler.removeCallbacks(updateThread);
				myProgressBar.setVisibility(View.GONE);
			}
		}
	};

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.activity_main, menu);
		return true;
	}

}


这是简单使用Handler的一个例子,就是一个按钮,点击,进度条就会出现而且自动改变。

 

简单使用,首先要创建一个Handler实例。然后在创建一个线程Runnable.会自动重写Runnable的run方法,把需要新线程所需要做的工作放在run方法里面执行。

然后通过  Handler 的 post 方法将线程压入 消息队列 内执行。

    可以在线程的 run 方法内调用 handler.postDelayed(Runnable, 3000);//参数是 线程、时间(毫秒)  来循环调用自身

    可以通过  removeCallbacks 来让线程从消息队列中出列。

 

 

第一次补充:整理一下上面代码的思路,自己重新写了一次,大概也就理解了。

1、首先是声明控件、获取控件,对按钮进行与监听器的绑定。

 

2、然后就是实现Handler接口:Handler updateHandler = new Handler(){};   //注意是接口,后面不要漏掉了分号

接着就是重写 handlerMessage() 方法  //该方法是当Handler中的队列有新的Message时执行

然后在该方法体内更新ProgressBar的状态、然后在把线程重新压入一次消息队列里面

 

3、这一步应该是在上面之前就写的,创建一个新的线程,不然上面的一步找不到线程。

Runnable updateProgressBarThread = new Runnable(){}   //这里会自动重写run方法

然后设定一个成员变量作为ProgressBar的进度。

使用Message对象来接收从Handler中的消息---> Message msg = updateHandler.obtainMessage();

然后在使系统休眠1秒,为了能看清进度条的变动。然后把进度条的当前进度即刚刚设定的成员变量的值储存在Message对象内。

然后在把该Message发送给Handler---->updateHandler.sendMessage(msg);

在 线程内做一个判断,如果该成员变量等于或者超出ProgressBar的最大值时,就应该将进度条关闭,然后让线程从消息队列中出列

 

思路大体上就是这样,等看完第二个视频在回来更新Handler的复杂一点的使用方法。

 

 

 第二次补充:

    复杂的方法貌似也没有。只是更深入的介绍了Handler和多线程的联系。

其实上面的例子里面,不是多线程的例子,他只是用了自身的主线程来执行操作。并没有开辟一个新的线程来执行该操作,意思是不能达到我们所期望的多线程效果。

要想实现多线程有以下两个方法。

1、真正意义上的启动一个新的线程来执行Runnable。

           此方法不在需要Handler来把Runnable放到 消息队列里面了。//上面Handler的使用例子只是用当前的主线程来执行该操作而已。

         上面的代码,把“线程放到Handler里启动”的那段代码“updateHandler.post(updateThread)”

         修改成启动一个新的现成来执行该操作的代码---->    Thread t = new Thread(updateThread);   t.start();

        跟其他高级语言多线程的方法类似,也是创建一个新的线程,然后调用start()方法。  //start()方法会自动调用 run方法的。

 

    这是个人认为比较正宗、方便的多线程方法。

 

2、还是使用Handler,不过需要自己继承Handler重写他的构造函数,通过Looper对象来达到多线程的目的。 

具体看代码:

 

HandlerThread handlerThread = new HandlerThread("handler_thread");
handlerTHread.start();
MyHandler myHandler = new Myhandler(handlerThread.getLooper());
msg.sendToTarget();

class MyHandler extends Handler{
	public MyHandler(){
	
	}
	public MyHandler(Looper looper){
		super(looper);
	}
}

 

思路:

       1、创建一个HandlerThread实例,该实例将会自动循环的相应消息队列。

       2、创建一个继承Handler的类,重载该类的构造函数,其中通过将接收到的Looper对象传送到父类的构造函数内,父类就会启动一个新的线程来相应该 Looper

       3、创建该子类的实例,构造参数列表中要用HandlerThread的getLooper()方法将当前 消息队列 所捕获的消息传进该子类,该子类调用父类的构造函数,父类则会启动一个新的线程来执行该 消息。

 

关于线程间的通信问题。例子中使用了Message的agr1(还有个agr2)可以用来传递一些简单的int类型的数据,效率会比setData()更高。

下面就介绍了setData()传送数据的例子。

思路:(续上面使用子类继承Handler的方法)

       1、首先使用一个Message对象来接收该线程内所传递过来的消息---->   Message msg = myHandler.obtainMessage(); 

       2、接下来就是数据的传递了。这里要使用Bundle对象,传递方式与Map一样,采取 键值对 的形式传递的。

       3、这里要小讲一下Bundle对象,可以理解为限制性更多的Map类型,Map的键值对都是object类型,但是Bundler的 键 固定为 字符串,值可以支持大多数 基本数据类型  以及  基本数据类型数组。使用方法类似--->  Bundle.putInt("Age",  20);

      4、在发送消息之前调用msg的setData()即可---->msg.setData(Bundle);

      5、在线程里面接收数据的话同理,先创建Bundle对象然后通过msg.getData();在Bundle.getInt();就可以把数据取出来了。

 

小注:关于Message的agr1、agr2,还有一个obj(Object)也是可以传送过来的,传送的方法类似,msg.obj = "123";接收的时候只需要做一个 强制类型 转换即可。

----->   String number = (String)msg.obj;

 

此致,看完视频,暂时更新到这里,若还有新的想法,以后在回来修改。

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值