为了避免ANR,我们会通常把 耗时操作放在子线程里面去执行,因为子线程不能更新UI,所以当子线程需要更新的UI的时候就需要借助到安卓的消息机制,也就是Handler机制了。
注意:在安卓的世界里面,当 子线程 在执行耗时操作的时候,不是说你的主线程就阻塞在那里等待子线程的完成——也不是调用 Thread.wait()或是Thread.sleep()。安卓采取的方法是,主线程应该为子线程提供一个Handler,以便完成时能够提交给主线程。以这种方式设计你的应用程序,将能保证你的主线程保持对输入的响应性并能避免由于5秒输入事件的超时引发的ANR对话框。
一个程序的运行,就是一个进程的在执行,一个进程里面可以拥有很多个线程。
- 主线程:也叫UI线程,或称ActivityThread,用于运行四大组件和处理他们用户的交互。 ActivityThread管理应用进程的主线程的执行(相当于普通Java程序的main入口函数),在Android系统中,在默认情况下,一个应用程序内的各个组件(如Activity、BroadcastReceiver、Service)都会在同一个进程(Process)里执行,且由此进程的主线程负责执行。
ActivityThread既要处理Activity组件的UI事件,又要处理Service后台服务工作,通常会忙不过来。为了解决此问题,主线程可以创建多个子线程来处理后台服务工作,而本身专心处理UI画面的事件。
- 子线程: 用于执行耗时操作,比如 I/O操作和网络请求等。(安卓3.0以后要求耗访问网络必须在子线程种执行)更新UI的工作必须交给主线程,子线程在安卓里是不允许更新UI的。
- Handler的简单使用
既然子线程不能更改界面,那么我们现在就借助Handler让我们更改一下界面:
主要步骤是这样子的:
1、new出来一个Handler对象,复写handleMessage方法
2、在需要执行更新UI的地方 sendEmptyMessage 或者 sendMessage
3、在handleMessage里面的switch里面case不同的常量执行相关操作
- 代码
-
import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.util.Log; import android.view.View; import android.widget.TextView; public class MainActivity extends Activity { private TextView mTv; private Handler mHandler; private static final int MSG_UPDATE_TEXT = 0x2001; // 更新文本 方式一用的常量 private static final int MSG_UPDATE_WAY_TWO = 0x2002; // 更新文本 方式二用的常量 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mHandler=new Handler(){ @Override public void handleMessage(Message msg) { switch (msg.what){ case MSG_UPDATE_TEXT: mTv.setText("让Handler更改界面"); break; case MSG_UPDATE_WAY_TWO: mTv.setText("让Handler更改界面方式二"); break; } } }; mTv= (TextView) findViewById(R.id.mTv); mTv.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Log.d("Test", "点击文字"); // 方式一和方式二可以达到相同的效果,就是更改界面 // 方式一 //mHandler.sendEmptyMessage(MSG_UPDATE_TEXT); // 方式二 Message msg =Message.obtain(); msg.what= MSG_UPDATE_WAY_TWO; mHandler.sendMessage(msg); } }); } /* private void sonThreadUpdateUi(){ new Thread(new Runnable() { @Override public void run() { mTv.setText("子线程想要更改界面"); } }).start(); }*/ }
Handler的工作机制简单来说是这样的
Handler的工作机制简单来说是这样的
1. Message 消息 ,理解为线程间通讯的数据单元。例如后台线程在处理数据完毕后需要更新UI,则可发送一条包含更新信息的Message给UI线程。2. Message Queue 消息队列 ,用来存放通过Handler发布的消息,按照先进先出执行。3. Handler Handler是Message的主要处理者 ,负责将Message添加到消息队列以及对消息队列中的Message进行处理。4. Looper 循环器 ,扮演Message Queue和Handler之间桥梁的角色,循环取出Message Queue里面的Message,并交付给相应的Handler进行处理。5. 线程 UI thread 通常就是main thread ,而Android启动程序时会替它建立一个Message Queue。每一个线程里含有一个Looper对象以及一个MessageQueue数据结构。在你的应用程序里,可以定义Handler的子类别来接 收Looper所送出的消息。