直接上例子代码:
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;
此致,看完视频,暂时更新到这里,若还有新的想法,以后在回来修改。