首页 > 代码库 > Android多线程更新UI的方式

Android多线程更新UI的方式

  Android下,对于耗时的操作要放到子线程中,要不然会残生ANR,本次我们就来学习一下Android多线程更新UI的方式。

  首先我们来认识一下anr:

  anr:application not reponse:应用程序无响应
  主线程:UI线程
  anr产生的原因:主线程需要做很多重要的事情,响应点击事件,更新ui,如果在主线程里面阻塞时间过久,应用程序就会无响应,为了避免应用程序出现anr,所有的耗时的操作,都应该放在子线程中执行。

  认识了anr后,我们就来学习一下怎样在Android下开启多线程,并更新ui了。一共有两种方式:

第一种采用:Handler。

  Handler获取当前线程中的looper对象,looper用来从存有Message的Message Queue里取出message,再由Handler进行message的分发和处理。

handler进制的原理

  android提供了handler和looper来满足线程间的通信。Handler先进先出原则。looper用来管理特定线程内对象之间的消息交换(message Exchange).

     1)looper:一个线程可以产生一个looper对象,由它来管理此线程里的message queue(消息队列)

      2)handler:你可以构造一个handler对象来与looper沟通,以便push新消息到messagequeue里;或者接收looper(从messagequeue里取出)所送来的消息。

我们使用的时候呢,需要在子线程中定义message,并把要返回的obj对象,传递给msg,同时由于handler不止要处理这一种类型,所以我们还要定义what的类型,以便让handler分类处理。

	Message msg = new Message();	msg.what = CHANGE_UI;	msg.obj = result;	handler.sendMessage(msg);

 

好的接下来我们就实例来使用handler。

		   new Thread(){			   public void run() {				   try {					URL url = new URL(path);					HttpURLConnection conn = (HttpURLConnection) url.openConnection();					conn.setRequestMethod("GET");					conn.setConnectTimeout(5000);					conn.setRequestProperty("User-Agent", "");										int code = conn.getResponseCode();					if(code==200){						InputStream is = conn.getInputStream();						String result = StreamTools.readInputStream(is);												//tv_content.setText(result);						Message msg = new Message();						msg.what = CHANGE_UI;						msg.obj = result;						handler.sendMessage(msg);																	}else{						Message msg = new Message();						msg.what = ERROR;						handler.sendMessage(msg);					}									} catch (Exception e) {					// TODO Auto-generated catch block					e.printStackTrace();										Message msg = new Message();					msg.what = ERROR;					handler.sendMessage(msg);														}				   				   			   };		   }.start();

 这里采用的 StreamTools.readInputStream的实现是这样的,目的是把输入流转化为字符串。

/**	 * 把输入流转化为字符串	 * @param is	 * @return	 */	public static String readInputStream(InputStream is){		try {			ByteArrayOutputStream baos = new ByteArrayOutputStream();			int len = 0;			byte[] buffer = new byte[1024];			while((len = is.read(buffer))!=-1){				baos.write(buffer,0,len);			}			is.close();			baos.close();			byte[] result = baos.toByteArray();						//试着解析网址返回的字符串,			String temp = new String(result);			if(temp.contains("utf-8")){				return temp;			}else if(temp.contains("gbk")){				return new String(result,"gbk");			}						return temp;			//return new String(result);		} catch (Exception e) {			// TODO Auto-generated catch block			e.printStackTrace();			return "获取失败";		}			}

 

其中handler的实现是这样的。

		private Handler handler = new Handler(){		public void handleMessage(android.os.Message msg) {			switch (msg.what) {			case ERROR:				Toast.makeText(MainActivity.this, "获取数据失败", 0).show();				break;			case CHANGE_UI:				tv_content.setText(msg.obj+"");				Toast.makeText(MainActivity.this, "获取数据失败", 0).show();				break;			}		};	};

 这样呢,我们便可以用handler,也即消息处理机制来更新UI了,

 

第二种方式。

  采用runOnUiThread(new Runnable()),这要实现Runnable借口,我们可以直接在这个线程中进行UI的更新。是api提供的方法,较为便捷。

  

	new Thread(){    		@Override    		public void run() {    			final String result = LoginServices.loginByGet(username, password);    			if(result != null){    				//成功    				runOnUiThread(new Runnable() {												@Override						public void run() {							// TODO Auto-generated method stub							Toast.makeText(MainActivity.this, result, 0).show();						}					});    			}else{    				//请求失败    				runOnUiThread(new Runnable() {												@Override						public void run() {							// TODO Auto-generated method stub							Toast.makeText(MainActivity.this, "请求失败", 0).show();						}					});    			}    			    		};    	}.start();

 

 

 

 

 

  

Android多线程更新UI的方式