在Android中,主线程负责管理与UI相关的事件;在自己创建的子线程中,不能对UI组件进行 *** 作。
例如,如下代码在单击按钮时创建新线程,这时改变文本框的显示文本会crash:
public class MainActivity extends AppCompatActivity { protected void onCreate() { ... button.setonClickListener(new View.onClickListener( { public void onClick(View v) { Thread thread = new Thread(new Runnable()) { public void run() { textView.setText("xxxxxxx"); } }); thread.start(); } }); } }
因此,Android引入Handler消息机制,来实现在新创建的线程中 *** 作UI。
2 Handler与Looper,MessageQueue的关系关于详细的实现原理请参考老罗的讲解:
Android应用程序的消息处理机制(MessageQueue,Looper,Handler)_u012906122的专栏-CSDN博客
Handler类:
(1)在任意线程中发送消息
通过调用Handler的sendMessage()将消息发送到MessageQueue中。
(2)在主线程中获取并处理消息
覆写Handler类的handleMessage()方法。当Looper循环到该Message时,会回调Handler的handleMessage()处理消息。
Looper类:
管理MessageQueue。每个线程只能有一个Looper,loop()方法负责读取MessageQueue中的消息,读取到消息后把消息传给Handler进行处理。
Message类:
(1)Message:通过Handler发送和处理的消息对象。
(2)MessageQueue:FIFO消息队列。
Handler与Looper,MessageQueue的关系如下:
一个线程对应一个Looper对象,一个Looper对象对应一个MessageQueue,MessageQueue用于存放Message。
Handler发送Message给Looper管理的MessageQueue,Looper又从MessageQueue中取出消息,给Handler处理。
因此,如果要在程序中使用Handler,必须在当前线程中有一个Looper对象。线程中的Looper对象有以下两种创建方式:
(1)UI主线程中,系统默认已经初始化一个Looper对象了,程序可以直接创建Handler,发送和处理消息。
(2)子线程中,需要手动创建一个Looper对象,并通过loop()启动Looper。
[1]调用Looper的prepare()来为当前线程创建Looper对象,同时创建MessageQueue。
[2]创建Handler实例,覆写handleMessage()方法。
[3]调用Looper的loop()方法启动Looper。
注意:一个线程中,只有一个Looper和MessageQueue,但可以有多个Handler。
3 使用Handler实现进度条倒计时发送和处理消息都是在主线程
MainActivity.java
public class MainActivity extends Activity { public final static String TAG = "ProgressBar"; final int TIME = 20; final int TIMER_MSG = 0x001; private ProgressBar timer; private int mProgressStatus = 0; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); timer = (ProgressBar) findViewById(R.id.timer); handler.sendEmptyMessage(TIMER_MSG); //发送消息,启动进度条 Log.d(TAG, "onCreate tid:" + android.os.Process.myTid()); } Handler handler = new Handler() { @Override public void handleMessage(Message msg) { //当前进度大于0 if (TIME - mProgressStatus > 0) { mProgressStatus++; //进度+1 Log.d(TAG, "handleMessage mProgressStatus:" + mProgressStatus); Log.d(TAG, "handleMessage tid:" + android.os.Process.myTid()); timer.setProgress(TIME - mProgressStatus); //更新进度条的显示进度 handler.sendEmptyMessageDelayed(TIMER_MSG, 1000); } else { Toast.makeText(MainActivity.this, "时间到!", Toast.LENGTH_SHORT).show(); Log.d(TAG, "handleMessage timeout!"); } } }; }
GitHub - hanyuhang-hz/android-demos
4 使用Handler实现轮播广告使用Message类时注意:尽管Message类有public构造方法,但通常情况下,需要使用Message.obtain()或Handler.obtainMessage()从消息池中获得空消息对象,以节省资源。
Message对象属性描述如下:
属性
类型
描述
arg1
int
存储整型数据
arg2
int
存储整型数据
obj
Object
存储Object类型的任意对象
replyTo
Messenger
指定此Message发送到何处的Messenger
what
int
指定用户自定义的消息代码
MainActivity.java
public class MainActivity extends Activity { final int FLAG_MSG = 0x001; private ViewFlipper flipper; private Message message; //定义图片数组 private int[] images = new int[]{R.drawable.img1, R.drawable.img2, R.drawable.img3, R.drawable.img4, R.drawable.img5, R.drawable.img6, R.drawable.img7, R.drawable.img8}; private Animation[] animation = new Animation[2]; //定义动画数组,为ViewFlipper指定切换动画 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); flipper = (ViewFlipper) findViewById(R.id.viewFlipper); for (int i = 0; i < images.length; i++) { ImageView imageView = new ImageView(this); imageView.setImageResource(images[i]); //将遍历的图片保存在ImageView中 flipper.addView(imageView); //加载图片 } animation[0] = AnimationUtils.loadAnimation(this, R.anim.slide_in_right); //右侧平移进入动画 animation[1] = AnimationUtils.loadAnimation(this, R.anim.slide_out_left); //左侧平移退出动画 flipper.setInAnimation(animation[0]); //为flipper设置图片进入动画效果 flipper.setOutAnimation(animation[1]); //为flipper设置图片退出动画效果 message=Message.obtain(); message.what=FLAG_MSG; handler.sendMessage(message); } Handler handler = new Handler() { //创建android.os.Handler对象 @Override public void handleMessage(Message msg) { if (msg.what == FLAG_MSG) { flipper.showPrevious(); } message=handler.obtainMessage(FLAG_MSG); //获取要发送的消息 handler.sendMessageDelayed(message, 3000); } }; }
GitHub - hanyuhang-hz/android-demos
子线程中,需要手动创建一个Looper对象,并通过loop()启动Looper。
[1]调用Looper的prepare()来为当前线程创建Looper对象,同时创建MessageQueue。
[2]创建Handler实例,覆写handleMessage()方法。
[3]调用Looper的loop()方法启动Looper。
MainActivity.java
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Log.d("Looper", "onCreate tid:" + android.os.Process.myTid()); LooperThread thread=new LooperThread(); //创建一个线程 thread.start(); //开启线程 } }
LooperThread.java
public class LooperThread extends Thread { public Handler handler; @Override public void run() { super.run(); Looper.prepare(); //初始化Looper对象 //实例化一个Handler对象 handler = new Handler() { public void handleMessage(Message msg) { Log.i("Looper", "handle msg:" + String.valueOf(msg.what)); Log.d("Looper", "handleMessage tid:" + android.os.Process.myTid()); } }; Message m=handler.obtainMessage(); //获取一个消息 m.what=0x7; //设置Message的what属性的值 handler.sendMessage(m); //发送消息 Log.i("Looper", "send msg:" + String.valueOf(m.what)); Log.d("Looper", "sendMessage tid:" + android.os.Process.myTid()); Looper.loop(); //启动Looper } }
https://github.com/hanyuhang-hz/android-demos
注意:Looper.loop()之后的代码不会被执行,因为loop()函数是一个循环。只有调用了Handler.getLooper().quit()后,loop()方法才会终止,后面的代码才会运行。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)