首页 > 代码库 > Android开发之异步具体解释(一)Thread+Handler

Android开发之异步具体解释(一)Thread+Handler

请尊重他人的劳动成果,转载请注明出处:  Android开发之异步具体解释(一)Thread+Handler 

http://blog.csdn.net/fengyuzhengfan/article/details/40211589

        在Android实际开发project中常常会进行一些诸如:文件读写、訪问网络等耗时的操作,这些耗时的操作是不建议放到UI线程里的。

所以我们会新开一个线程。在子线程中进行这些耗时的操作。耗时操作过程中。UI常常须要更新,但Android是不同意在子线程中改动UI的。所以就出现了Thread+Handler机制,Thread通过handler向主线程发送消息、传递数据,来更新UI。以下就介绍怎样通过Thread+Handler方式实现异步操作。


1.   什么是Handler消息传递机制?

        当一个程序第一次启动时,Android会同一时候启动一条主线程(MainThread),主线程主要负责处理与UI相关的事件,如用户的按键事件、用户接触屏幕的事件及屏幕画图事件,并把相关的事件分发到相应的组件进行处理。所以主线程通常又被叫做UI线程。

        Android的消息传递机制是还有一种形式的“事件处理‘这样的机制主要是为了解决Android 应用的多线程问题——Android平台仅仅同意UI线程改动Activity里的UI组件,这样就会导致新启动的线程无法动态改变界面组件的属性值。

但在实际Android应用开发中,尤其是涉及动画的游戏开发中,须要让新启动的线程周期性地改变界面组件的属性值,这就须要借助于 Handler的消息传递机制来实现了。

 

2.   Handler 类简单介绍


Handler类的主要作用有两个:

1)  在新启动的线程中发送消息。

2)  在主线程中获取、处理消息。

 

       上面的说法看上去非常easy,似乎仅仅要分成两步就可以:在新启动的线程中发送消息。然后在主线程中获取、并处理消息。但这个过程涉及一个问题:新启动的线程何时发送消息呢?主线程何时去获取并处理消息呢?这个时机显然不好控制。

       为了让主线程能“适时”地处理新启动的线程所发送的消息,显然仅仅能通过回调的方式来实现——我们者仅仅要重写Handler类中处理消息的方法,当新启动的线程发送消息时。消息会发送到与之关联的MessageQueue,而Handler会不断地从MessageQueue中获取并处理消息——这将导致Handler类中处理消息的方法被回调。

Handler类包括例如以下方法用于发送、处理消息:

1)        void  handleMessage(Message  msg):处理消息的方法。该方法通经常使用于被重写。

2)        final boolean hasMessages(intwhat):检査消息队列中是否包括what属性为指值的消息。

3)        final boolean hasMessages(intwhat, Object object):检査消息队列中是否包括 what属性为指定值且object属性为指定对象的消息。

4)        多个重载的Message obtainMessage():获取消息。sendEmptyMessage(int what):发送空消息。

5)        final booleansendEmptyMessageDelayed(int what, long delayMillis):指定多少毫秒之后发送空消息。

6)        final booleansendMessage(Message msg)马上发送消息。

7)        final booleansendMessageDelayed(Message msg, long delayMillis):指定多少毫秒之后发送消息。

借助于上面这些方法,程序能够方便地利用Handler来进行消息传递。

 

3.   Thread+Handler实现异步操作实例

 

package com.jph.sp;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.SimpleAdapter.ViewBinder;

/**
 * 获取全部软件信息
 * 1.通过异步的方式显示系统中全部软件
 * 2.单击打开指定软件
 * 3.将全部软件的包名和activity名保存的本地SharedPreferences
 * @author jph
 * Date:2014.09.21
 */
public class ScanPackage1 extends Activity {
	/**扫描成功**/
	private final static int FLAG_LOAD_SUCCESS=0x10001;
	private final static int SCANNING=0x10002;	
	private ListView list;
	private List<Map<String, Object>>items=new ArrayList<Map<String,Object>>();
	private SimpleAdapter adapter;
	// 取得全部安装软件信息
	private List<PackageInfo> allPackageInfos;
	// 取得自己安装的软件信息
	private List<PackageInfo> userPackageInfos;
	// 取得系统安装的软件信息
	private List<PackageInfo> sysPackageInfos;	
	Handler mHandler=new Handler(){
		@Override
		public void handleMessage(Message msg) {
			// TODO Auto-generated method stub
			switch (msg.what) {
			case FLAG_LOAD_SUCCESS://完毕扫描
				
				break;
			case SCANNING://正在扫描					
				items.add((Map<String, Object>) msg.obj);
				//通知适配器数据改变
				adapter.notifyDataSetChanged();				
				break;

			default:
				break;
			}			
		}			
	};
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.sp_layout);
		list=(ListView)findViewById(R.id.list);
		new ScanThread().start();
		adapter=new SimpleAdapter(this, items, R.layout.line, new String[]{
				"imgIco","appName","packageName"
		}, new int[]{R.id.imgIco,R.id.tvAppName,R.id.tvAppDesc});
		list.setAdapter(adapter);
		//ViewBinder该类能够帮助SimpleAdapter载入图片(如:Bitmap,Drawable)
		adapter.setViewBinder(new ViewBinder() {			
			@Override
			public boolean setViewValue(View view, Object data,
					String textRepresentation) {
				// TODO Auto-generated method stub
				 if(view instanceof ImageView  && data instanceof Drawable){    
		              ImageView iv = (ImageView) view;    
		              iv.setImageDrawable((Drawable) data);		               
		               return true;    
		           }else{
		        	   return false;  
		           }   
			}
		});
		list.setOnItemClickListener(new OnItemClickListener() {
			@Override
			public void onItemClick(AdapterView<?

> arg0, View arg1, int arg2, long arg3) { // TODO Auto-generated method stub try { PackageInfo pInfo=allPackageInfos.get(arg2); Intent intent=new Intent(); intent.setComponent(new ComponentName(pInfo.packageName, pInfo.activities[0].name)); startActivity(intent); } catch (Exception e) { // TODO: handle exception e.printStackTrace(); } } }); } // ***************--------*创建一个线程载入安装程序*--------------*******************// private class ScanThread extends Thread { @Override public void run() { // 取得系统安装全部软件信息 allPackageInfos = getPackageManager().getInstalledPackages( PackageManager.GET_UNINSTALLED_PACKAGES | PackageManager.GET_ACTIVITIES); // 定义用户安装软件信息包 userPackageInfos = new ArrayList<PackageInfo>(); // 定义系统安装软件信息包 sysPackageInfos = new ArrayList<PackageInfo>(); // 循环取出全部软件信息 for (int i = 0; i < allPackageInfos.size(); i++) { // 得到每一个软件信息 PackageInfo temp = allPackageInfos.get(i); ApplicationInfo appInfo = temp.applicationInfo; if ((appInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0 || (appInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { //系统软件 sysPackageInfos.add(temp); } else { //用户自己安装软件 userPackageInfos.add(temp); } //获取程序的图标 Drawable ico=ScanPackage1.this.getPackageManager().getApplicationIcon(appInfo); //获取程序的名称 String appName=(String) ScanPackage1.this.getPackageManager().getApplicationLabel(appInfo); Map<String, Object>item=new HashMap<String, Object>(); //获取程序的包名 String packageName=appInfo.packageName; item.put("imgIco", ico); item.put("appName", appName); item.put("packageName", packageName); Message message = new Message(); message.what =SCANNING; message.obj = item; mHandler.sendMessage(message); } saveInfo(sysPackageInfos, userPackageInfos); mHandler.sendEmptyMessage(FLAG_LOAD_SUCCESS); } }; /** * 将系统中所装程序的信息写入到配置文件 * @param sysPackageInfos 系统安装软件信息包 * @param userPackageInfos 用户安装软件信息包 */ private void saveInfo(List<PackageInfo> sysPackageInfos,List<PackageInfo> userPackageInfos) { //将用户安装的软件加入到加入到系统软件的集合中 sysPackageInfos.addAll(userPackageInfos); SharedPreferences sp = this.getSharedPreferences("appInfs", MODE_PRIVATE); Editor editor = sp.edit(); for (int i = 0; i < sysPackageInfos.size(); i++) { try { //获取程序的包名 String packageName = sysPackageInfos.get(i).packageName; // 取出activity信息 ActivityInfo activityInfo = sysPackageInfos.get(i).activities[0]; // 取出activity名字 String activityName=activityInfo.name; //将程序的信息写入到配置文件 editor.putString(packageName, activityName); } catch (Exception e) { // TODO: handle exception e.printStackTrace(); } } editor.commit(); } }

 

代码分析:

       上面代码,中UI 通过代码new ScanThread().start();启动一个子线程来扫描全部软件包。然后子线程将扫描结果通过mHandler.sendMessage(message);时时的发送给UI线程。

UI线程收到子线程的消息后获取消息携带的数据,然后更新到ListView上。这样就实现了异步操作。

 假设你认为这篇博文对你有帮助的话,请为这篇博文点个赞吧!

也能够关注fengyuzhengfan的博客。收看很多其它精彩!http://blog.csdn.net/fengyuzhengfan/   

 

Android开发之异步具体解释(一)Thread+Handler