第一篇博文啊,学习编程一年了,迷茫混乱中走来,大致确定了学习的方向,这阵子突然发现以前学过的好多些东西都差不多忘了,想要复习才发现手头没有笔记,好好反思下以前的学习方法,计算机方面的学习确实很难做到写笔记,但没有笔记又不能总结复习,于是找到了博客这东西,以前在学习过程中遇到问题,百度一下,很多技术性的解答都出自博客,从那些博客中确实学到很多,也解决了很多问题,在此表示感谢。话说回来,既然准备走上IT这条路,养成一个好的习惯是很有必要的,于是准备写博客,帮助自己复习记忆,也可以给别人一些帮助。。。下面开始第一篇博客!
Handler的使用
“Android UI操作并不是线程安全的并且这些操作必须在UI线程中执行”。对于这句话的理解,真是费了很大劲啊,现在来说说这句话的意思,就是对于主界面中的控件的操作,比如Button上的文字改变,TextView中的内容改变,显示Toast,ProgressBar更新等涉及控件改变的操作,都必须在UI线程中进行,那要是我在一个新线程中进行了某些操作,操作完成了,想要弹出一个Toast告诉用户,这时是不能在新线程中直接调用Toast的,于是Handler的概念就出来了,通过发送Message信息,在UI线程中调用Handler对象接收Message消息,并根据收到的消息内容进行不同的操作。这样就解决了不能在UI线程意外的线程中改变UI控件。
下面是Handler的具体用法
一、Handler的定义:
Handler主要接收子线程发送的数据, 并用此数据配合主线程更新UI,用来跟UI主线程交互用。比如可以用handler发送一个message,然后在handler的线程中来接收、处理该消息,以避免直接在UI主线程中处理事务导致影响UI主线程的其他处理工作,Android提供了Handler作为主线程和子线程的纽带;也可以将handler对象传给其他进程,以便在其他进程中通过handler给你发送事件;还可以通过handler的延时发送message,可以延时处理一些事务的处理。
通常情况下,当应用程序启动时,Android首先会开启一个主线程 (也就是UI线程) , 主线程为管理界面中的UI控件,进行事件分发。如果此时需要一个耗时的操作,例如:联网读取数据,或者读取本地较大的一个文件的时候,你不能把这些操作放在主线程中,如果你放在主线程中的话,界面会出现假死现象,如果5秒钟还没有完成的话,会收到Android系统的一个错误提示"强制关闭".
这个时候我们需要把这些耗时的操作,放在一个子线程中,因为子线程涉及到UI更新,但是当子线程中有涉及到操作UI的操作时,就会对主线程产生危险,也就是说,更新UI只能在主线程中更新,在子线程中操作是危险的. 这个时候,Handler就出现了来解决这个复杂的问题,由于Handler运行在主线程中(UI线程中),它与子线程可以通过Message对象来传递数据,这个时候,Handler就承担着接受子线程传过来的(子线程用sedMessage()方法传递)Message对象,(里面包含数据), 把这些消息放入主线程队列中,配合主线程进行更新UI。
二、Handler的特点
handler可以分发Message对象和Runnable对象到主线程中, 每个Handler实例,都会绑定到创建他的线程中(一般是位于主线程), 也就是说Handler对象初始化后,就默认与对它初始化的进程的消息队列绑定,因此可以利用Handler所包含的消息队列,制定一些操作的顺序。
三、Handler中分发消息的一些方法
post(Runnable)
postAtTime(Runnable,long)
postDelayed(Runnable long)
post类方法允许你排列一个Runnable对象到主线程队列中
sendEmptyMessage(int)
sendMessage(Message)
sendMessageAtTime(Message,long)
sendMessageDelayed(Message,long)
sendMessage类方法, 允许你安排一个带数据的Message对象到队列中,等待更新.
四、小例子
package com.example.testhandler;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
/**
* @author cen
*Handler可以传Message对象,也可以传Runnable对象,就是线程对象
*其中对于Message对象,是调用sendMessage()方法,对于Runnable对象就是调用post()方法
*Handler的使用方法:
*1.首先在子线程中创建Message类的对象,并调用obtain方法,然后进行赋值,然后调用sendMessage()方法
*2.在主线程中创建新的Handler对象,调用handleMessage()方法用于接收子线程传来的消息
*关于Looper:
*Looper是消息队列,默认只在主线程中创建,在其他线程中需要调用Looper.prepare方法创建消息队列,然后调用Looper.loop方法进入消息循环
*Handle只是针对那 些有Looper的线程,不管是UI线程还是子线程,只要你有Looper,我就可以往你的消息队列里面添加东西,并做相应的处理。
*/
public class MainActivity extends Activity {
Handler mHandler;
private static final int downloading=1;
private static final int download=100;
ProgressBar mprogressBar;
TextView mtextview;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();//初始化的方法
setListener();//设置按钮监听事件
initHandler();//初始化Handler的方法
}
private void initHandler() {
mHandler=new Handler(){
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case downloading:
mtextview.setText(msg.arg1+"%");
mprogressBar.setProgress(msg.arg1);//设置进度条里的值为每次循环递增的值
break;
case download:
Toast.makeText(MainActivity.this, "下载完成", 0).show();
break;
}
}
};
}
private void setListener() {
//设置监听事件的内容就是加一个按钮的时间,然后在事件里添加一个线程
findViewById(R.id.btdowmload).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
new Thread(){//新建一个线程
public void run() {
for (int i = 0; i < 100; i++) {
SystemClock.sleep(500);//每次循环之前都休眠500毫秒
Message msg=Message.obtain();//Message对象,获取消息
msg.what=downloading;//定义消息码,就理解成唯一标识码,为了和主线程的Handler一一对应用的
msg.arg1=i;//设置msg的值
mHandler.sendMessage(msg);//发送消息
}
Message msg=Message.obtain();//循环结束后发送,这里没有发送任何值,只发送了一个标识码
msg.what=download;//设置标识码为download
mHandler.sendMessage(msg);
};
}.start();
}
});
}
private void initView() {
// TODO Auto-generated method stub
mprogressBar=(ProgressBar) findViewById(R.id.progressbar);
mtextview=(TextView) findViewById(R.id.tvprogress);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}