Android的UI操作不是线程安全的(出于提高性能考虑,避免实现多线程同步等机制所引入的延时),若多个线程同时对UI元素进行操作,可能导致线程安全问题。因此,Android中做了严格的规定:只有UI主线程才能对UI进行设置与操作。

在实际编程中,为了避免UI界面长时间得不到响应而导致的ANR(Application Not Responding)异常,通常将网络访问、复杂运算等一些耗时的操作被放在子线程中执行。这就需要子线程在运行完毕后将结果返回到主线程并通过UI进行显示。在Android中,是通过Handler+Loop+MessageQueue实现线程间通信的。

先看两个实例:

实例1:模拟通过网络下载数据并返回UI显示。

操作过程为:1.UI线程获得用户请求。2.启动子线程完成网络数据下载(网络下载过程通过强制子线程休眠若干秒来模拟)。3.子线程将下载的数据返回UI线程并显示。

主要代码如下:

publicclassMainActivityextendsActionBarActivity{privateButtonmButton;privateTextViewmTextView;privateHandlermHandler;privateThreadmNetAccessThread;privateProgressDialogmProgressDialog;privateintmDownloadCount=0;@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.fragment_main);mButton=(Button)findViewById(R.id.btReqNet);mTextView=(TextView)findViewById(R.id.tvDownload);//设置按钮的点击事件监听器mButton.setOnClickListener(newOnClickListener(){@OverridepublicvoidonClick(Viewv){showProgressDialog("","正在下载...");//启动子线程进行网络访问模拟mNetAccessThread=newChildTread();mNetAccessThread.start();}});//继承Handler类并覆盖其handleMessage方法mHandler=newHandler(){//覆盖Handler类的handleMessage方法//接收子线程传递的数据并在UI显示@OverridepublicvoidhandleMessage(Messagemsg){switch(msg.what){case1:mTextView.setText((String)msg.obj);dismissProgressDialog();break;//可以添加其他情况,如网络传输错误//case...default:break;}}};}classChildTreadextendsThread{@Overridepublicvoidrun(){//休眠6秒,模拟网络访问延迟try{Thread.sleep(6000);}catch(InterruptedExceptione){e.printStackTrace();}//将结果通过消息返回主线程Messagemsg=newMessage();msg.what=1;mDownloadCount++;msg.obj=newString("第"+mDownloadCount+"次从网上下载的数据");mHandler.sendMessage(msg);}};/***开启progressDialog.**@paramtitle对话框标题.*@paramcontent对话框正文.*/protectedvoidshowProgressDialog(Stringtitle,Stringcontent){mProgressDialog=newProgressDialog(this);if(title!=null)mProgressDialog.setTitle(title);if(content!=null)mProgressDialog.setMessage(content);mProgressDialog.show();}/***关闭progressDialog.**/protectedvoiddismissProgressDialog(){if(mProgressDialog!=null){mProgressDialog.dismiss();}}}

程序运行效果:

点击下载按钮,UI线程通过handler.sendMessage()向子线程发送消息,子线程收到消息后启动数据下载(通过休眠线程模拟)。

wKioL1Q45jnRyNfNAAB1lcKvu-o305.jpg

下载完毕,子线程将下载数据返回主线程并显示。

wKioL1Q4563zuwMZAACM4fmNrKU067.jpg

实例2:模拟子线程向主线程发送消息。

操作过程为:1.UI线程获得用户输入的消息内容。2.通过Handler将消息发送给子线程。3.子线程获得消息并通过Toast将内容打印。

主要代码如下:

publicclassMainActivityextendsActionBarActivity{privateEditTextmEditText;privateButtonmButton;privateHandlermHandler;privateThreadmChildTread;@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.fragment_main);mEditText=(EditText)findViewById(R.id.etEditText);mButton=(Button)findViewById(R.id.btButton);//设置按钮的点击事件监听器mButton.setOnClickListener(newOnClickListener(){@OverridepublicvoidonClick(Viewv){Messagemsg=newMessage();msg.what=1;msg.obj=mEditText.getText();//将消息发送到子线程mHandler.sendMessage(msg);mEditText.setText("");}});//启动子线程进行msg接收mChildTread=newChildTread();mChildTread.start();}/***子线程为内部类,可以直接访问其外部类的mHandler变量**/classChildTreadextendsThread{@Overridepublicvoidrun(){//以下三步是handlerlooper机制工作的固定模式Looper.prepare();mHandler=newHandler(){publicvoidhandleMessage(Messagemsg){//processincomingmessageshereswitch(msg.what){case1://子线程无权操作UI,只能通过Toast.makeText将收到的消息显示Stringst=msg.obj.toString();if(st==null||st.equals(""))st="收到的消息内容为空";elsest="收到来自主线程的消息:"+st;Toast.makeText(MainActivity.this,st,6000).show();break;//可以添加其他情况,如传输错误//case...default:break;}}};Looper.loop();}};}程序运行效果:

wKioL1Q46pnjjJMDAAB3ZtMgIgY620.jpgwKioL1Q46neDgzh5AACNfaspK8Y747.jpg


小结:Android通过Handler+Looper+MessageQueue机制实现线程间的通信,本文通过两个简单的实例分别基于该机制实现了UI线程到子线程和子线程到UI线程的消息传递。下一篇博文将会对Handler Looper机制的原理进行深入研究。

更多相关文章

  1. Android中的线程池与任务队列
  2. Android下的多线程
  3. Handler解析(一):是如何实现线程之间的切换
  4. Android 接收RabbitMq服务器发送消息
  5. android 启动线程注意的问题
  6. Android开发学习笔记-关于Android的消息推送以及前后台切换

随机推荐

  1. Android 资源文件介绍
  2. Android(安卓)studio cmake报错
  3. 我的Android NDK之旅(五),在Mac上用eclipse
  4. ios与android的比较
  5. android上gdb coredump步骤
  6. android 中java编程的意外事件处理
  7. Android 应用程序发布流程注意事项(整理)
  8. Android 自定义组件02
  9. Android(安卓)开发源码分享
  10. Android 自定义View 解耦框架