Android开发之异步详解(一)Thread+Handler

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

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

在Android实际开发工程中经常会进行一些诸如:文件读写、访问网络等耗时的操作,这些耗时的操作是不建议放到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)  在主线程中获取、处理消息。

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

为了让主线程能“适时”地处理新启动的线程所发送的消息,显然只能通过回调的方式来实现——我们者只要重写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/

时间: 2024-10-10 13:15:03

Android开发之异步详解(一)Thread+Handler的相关文章

Android开发之异步详解(二)之AsyncTask

请尊重他人的劳动成果,转载请注明出处:Android开发之异步详解(二)之AsyncTask http://blog.csdn.net/fengyuzhengfan/article/details/40212745 我曾在<Android开发之异步详解(一)之Thread+Handler>一文中介绍过通过Thread+Handler实现异步操作.感兴趣的朋友可以看一下. 虽然Thread+Handler可以实现更新主线程的UI并实现异步,但Thread+Handler模式需要为每一个任务创建一

Android 开发 之 Fragment 详解

作者 : 韩曙亮 转载请著名出处 : http://blog.csdn.net/shulianghan/article/details/38064191 1. Fragement 概述 Fragement 与 Activity 生命周期关系 : Fragement 嵌入到 Activity 组件中才可以使用, 其生命周期与 Activity 生命周期相关. -- stop 与 destroy 状态 : Activity 暂停 或者 销毁的时候, 其内部嵌入的所有的 Fragement 也会执行

搭建Android开发环境附图详解+模拟器安装(JDK+Eclipse+SDK+ADT)

——搭建android开发环境的方式有多种,比如:JDK+Eclipse+SDK+ADT或者JDK+Eclipse+捆绑好的AndroidSDK或者Android Studio. Google 决定将重点建设 Android Studio编译工具.Google 在去年年底终止支持其 Eclipse包括插件ADT.(Android Studio会是一个趋势). 这篇将仅作为一个笔记吧,因为之前一直使用Word,记事本记录一些笔记之类.(大神勿喷,如有错误不当的地方,还望指出.谢谢!) 搭建开发环境

【Android开发】InstanceState详解

首先来介绍onSaveInstanceState() 和 onRestoreInstanceState() .关于这两个方法,一些朋友可能在Android开发过程中很少用到,但在有时候掌握其用法会帮我们起到比较好的效果.尤其是在应用程序在不知道的情况下退出后,如何实现其数据保存的功能.先来让我们看下这两个方法的有什么样的作用. 1. 基本作用:  Activity的 onSaveInstanceState() 和 onRestoreInstanceState()并不是生命周期方法,它们不同于 o

Android开发之图片详解(4)

接上一篇. 主要研究下bitmap和drawable的使用,以及两者的区别. 先看测试代码: package com.example.imagetext; import java.util.ArrayList; import java.util.List; import com.example.imagetext.R.drawable; import android.annotation.SuppressLint; import android.app.Activity; import andr

Android 开发之动画详解

一.动画类型 Android的animation由四种类型组成:alpha.scale.translate.rotate XML配置文件中 alpha 渐变透明度动画效果 scale 渐变尺寸伸缩动画效果 translate 画面转换位置移动动画效果 rotate 画面转移旋转动画效果 Java Code代码中 AlphaAnimation 渐变透明度动画效果 ScaleAnimation 渐变尺寸伸缩动画效果 TranslateAnimation 画面转换位置移动动画效果 RotateAnim

Android开发之图片详解(3)

在Android中,Bitmap普遍是造成OOM的罪魁祸首,而且普遍都认为bitmap所占用的内存远大于Drawable,而且网上也提供了很多内存回收的方法以及建议,比如在activity销毁后主动去调用bitmap.recyle()方法等,那么到底是不是真的呢?我专门针对bitmap和drawble做了以下测试: 为了方便测出OOM,我专门将一张比较大的图片1270*1920放在了mdpi的文件夹下,而我的测试机是320dpi的,那么根据我上篇文章所讲到的,如果通过资源去加载bitmap,那么

Android开发 DialogFragment对话框详解

前言 在聊DialogFragment之前,我们看看以往我们在Android里实现一个对话框一般有这几种方式: Dialog 继承重写Dialog实现一个自定义的Dialog AlertDialog Android原生提供的对话框(底层是继承Dialog实现) PopupWindow 用弹出悬浮框,实现对话框.这种对话框可以用在指定位置显示,一般用于一些非常小的按键弹窗.怎么实现可以参考我的博客:https://www.cnblogs.com/guanxinjing/p/10156153.htm

Android:ViewPager扩展详解——带有导航的ViewPagerIndicator(附带图片缓存,异步加载图片)

大家都用过viewpager了, github上有对viewpager进行扩展,导航风格更加丰富,这个开源项目是ViewPagerIndicator,很好用,但是例子比较简单,实际用起来要进行很多扩展,比如在fragment里进行图片缓存和图片异步加载. 下面是ViewPagerIndicator源码运行后的效果,大家也都看过了,我多此一举截几张图: 下载源码请点击这里 ===========================================华丽的分割线==============