Android之消息机制与异步任务

功能:
  1. 测试Handler的使用
  2. Hander使用的小DEMO
  3. 测试AsyncTask的使用

一,.测试Handler的使用

1.相关API

Message :消息   

可理解为线程间通讯的数据单元, 可通过message携带需要的数据
创建对象:  Message.obtain(what)
封装数据
public int what    //id 标识
public int arg1
public int arg2

public Object obj

Handler : 处理器
Handler是Message的处理器,同时也负责消息的发送和移除的工作
发送即时消息:  sendMessage(Message msg)
发送延时消息:  sendMessageDelayed(Message msg, long time)
处理消息: handleMessage(Message msg)    (回调方法)

移除还未处理的消息: removeMessages(int what)

MessageQueue : 消息队列

用来存放通过Handler发送的消息
它是一个按Message的when排序的优先级队列

Looper(钩子) : 循环器

负责循环取出Message Queue里面的当前需要处理的Message
交给对应的Handler进行处理
处理完后, 将Message缓存到消息池中, 以备复用

 Message
	public int what;//标识(id)
	public int arg1;//保存int数据
	public int arg2;//保存int数据
	public Object obj;//保存任意数据
	long when;//记录应该被处理的时间值
	Handler target;//用来处理消息的Handler对象,就是发送消息的handler
	Runnable callback;//用来处理消息的回调器(一般不用)
	Message next;//指向下一个message用来形成一个链表
	private static Message sPool;//用来缓存处理过的数据
	
	Message obtain()//它利用了Message中消息池(sPool)
	
Handler :发送消息,处理消息,移除消息
	sendMessage(Message msg)
		sendMessageDelayed(msg,0);
	sendEmptyMessage(int what)
		sendMessageDelayed(what,0);
	sendEmptyMessage(what , 0)//发送不带数据的消息
		Message msg = Message.obtain();
		msg.what = what;
		return sendMessageDelayed(msg,delayMillis);
	sendMessageDelayed(Message,msg,long delayMillis)
		sendMessageAtTime(msg,SystemClock.uptimeMillis() + delayMillis);
	sendMessageAtTime(Message msg,long uptimeMillis)
		enqueueMessage(queue,msg,uptimeMillis);//将消息添加到消息队列
	enqueueMessage(MessageQueue queue,Message msg,long uptimeMillis);
		msg.target = this;//保存发送消息的Handler对象
		queue.enqueueMessage(msg,uptimeMillis);//调用消息队列保存消息对象
	
	removeMessages(int what) //移除消息	
		mQueue.removeMessages(this, what, null);//调用消息队列移除它内部的指定what的消息
	
	handleMessage(Message msg)	//处理消息的回调方法
	
	public void dispatchMessage(Message msg) {
		if(msg.callback!=null){//如果消息自己可以处理,让消息自己处理
			handleCallback(msg);
		}else{
			if(mCallback != null){//如果handler对象中有回调监听器,调用回调器来处理消息
				if(mCallback.handleMessage(msg)){
					return;
				}
			}
			handleMessage(msg);//让Handler的handleMessage()来处理
		}
	}
	
MessageQueue :存储消息的以message的when排序优先级队列
	enqueueMessage(Message msg,long when):将message添加到队列中
		msg.when = when;//指定消息应该被处理的时间
		for(;;){//将当前消息对象保存到消息队列中的一个合适的位置
			prev = p;
			p = p.next;
			if(p==null || when < p.when){
				break;
			}
			if(needWake && p.isAsynchronous()){
				needWake = false;
			}
		}//最终的结果是:消息队列是按when来排序的
		
		nativeWake(mPtr);//通过本地方法实现对处理等待状态的底层线程

	next()取出一个合适的Message对象,可能不会立即返回
		nativePollOnce(mPtr,nextPollTimeoutMillis);//本地方法,会导致可能处理等待状态,但不会阻塞主线程
		Message msg = mMssages;//取出消息队列中的第一个消息
		return msg;//返回
		
Loop:从MessageQueuek中获取当前需要处理的消息,并交给Handler处理
	loop():核心方法
		final Looper me = myLooper();//得到looper对象
		final MessageQueue queue = me.mQueue;//得到消息队列对象
		for(;;){//无限循环
			Message msg = queue.next();//从消息队列中取出消息
			
			msg.target.dispatchMessage(msg);//调用Handler去分发并处理消息
			
			msg.recycle();//回收利用Message
		}
	
Runnable对象的run()什么时候在分线程执行?
	将Runable传给Thread的构造方法:
	new Thread(new Runnable(){
		public void run(){//在分线程执行
		
		}
	}).start();

2.功能实现:

  • 点击GET请求获取: 显示提示正在加载的进度条, 分线程请求网络
  • 得到数据后, 将数据显示到输入框中, 同时隐藏进度条

3.代码实现

package com.example.atguigu_05;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.EditText;
import android.widget.ProgressBar;

/**
 * 测试Handler的基本使用
 * 
 * @author Xiaocici
 *  1.创建Handler成员变量对象,并重写其handleMessage()
 *  2.在分/主线程创建Message对象
 *  3.使用handler对象发送Message 
 *  4.在handleMessage()中处理消息
 */
public class HandlerTestActivity extends Activity {

	private ProgressBar pb_handler1_loading;
	private EditText et_handler1_result;

	// 1.创建Handler成员变量对象,并重写其handleMessage()
	private Handler handler = new Handler() {// 在主线程执行
		public void handleMessage(android.os.Message msg) {
			if (msg.what == 1) {
				// 4.在handleMessage()中处理消息
				String result = msg.toString();
				et_handler1_result.setText(result);
				pb_handler1_loading.setVisibility(View.INVISIBLE);
			}
		};
	};

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_handler_test);

		pb_handler1_loading = (ProgressBar) findViewById(R.id.pb_handler1_loading);
		et_handler1_result = (EditText) findViewById(R.id.et_handler1_result);
	}

	/*
	 * 1.主线程,显示提示视图(ProgressDialog/ProgressBar) 2.分线程,联网请求,并得到响应数据
	 * 3.主线程,显示数据/隐藏提示视图
	 */
	public void getSubmit1(View v) {
		// 1.主线程,显示提示视图(ProgressDialog/ProgressBar)
		pb_handler1_loading.setVisibility(View.VISIBLE);
		// 2.分线程,联网请求,并得到响应数据
		new Thread() {
			public void run() {
				String path = "http://192.168.51.65:8080/web/?name=Tom&age=12";
				try {
					final String result = requestToString(path);

					// 3.主线程,显示数据
					runOnUiThread(new Runnable() {
						public void run() {
							et_handler1_result.setText(result);
							pb_handler1_loading.setVisibility(View.INVISIBLE);
						}
					});
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			};
		}.start();
	}

	public void getSubmit2(View v) {
		// 1).主线程,显示提示视图(ProgressDialog/ProgressBar)
		pb_handler1_loading.setVisibility(View.VISIBLE);
		// 2).分线程,联网请求,并得到响应数据
		new Thread() {
			public void run() {
				String path = "http://192.168.51.65:8080/web/?name=Tom&age=12";
				try {
					final String result = requestToString(path);

					// 3).主线程,显示数据
					// 2.在分/主线程创建Message对象
					Message message = Message.obtain();
					message.what = 1;
					message.obj = result;
					// 3.使用handler对象发送Message
					handler.sendMessage(message);
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			};
		}.start();

	}

	/**
	 * 请求服务器端,得到返回的结果字符串
	 * 
	 * @param path
	 *            :
	 * @return
	 * @throws Exception
	 */
	public String requestToString(String path) throws Exception {
		URL url = new URL(path);
		HttpURLConnection connection = (HttpURLConnection) url.openConnection();
		connection.setConnectTimeout(5000);
		connection.setReadTimeout(5000);
		connection.connect();
		InputStream is = connection.getInputStream();
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		byte[] buffer = new byte[1024];
		int len = -1;
		while ((len = is.read(buffer)) != -1) {
			baos.write(buffer, 0, len);
		}
		baos.close();
		is.close();
		String result = baos.toString();
		return result;
	}
}
二.Hander使用的小DEMO

1.功能描述

1). 初始时

     显示10,可以通过点击按钮改变其值

2). 点击“自动增加”

     每隔1S上面的文本数值增加1,但最大显示20并作出提示

3). 点击“自动减少”

     每隔1S上面的文本数值减少1,但最小显示1并作出提示

4). 点击“暂停”

   上面的数值文本不再变化

2.代码实现:

package com.example.atguigu_05;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

/**
 * 使用Handler的小DEMO
 * 
 * @author Xiaocici
 *  1.手动增加/减少 
 *  2.自动增加/减少 
 *  3.限制数字的最大和最小值【1,20】
 *  4.限制Button的可操作性
 */
public class HandlerDemoActivity extends Activity implements OnClickListener {

	private static final int WHAT_INCREASE = 1;
	private static final int WHAT_DECREASE = 2;
	private TextView tv_demo_number;
	private Button btn_demo_increase;
	private Button btn_demo_decrease;
	private Button btn_demo_pause;

	private Handler handler = new Handler() {
		public void handleMessage(android.os.Message msg) {
			//得到当前显示的数值
			int number = Integer.parseInt(tv_demo_number.getText().toString());
			switch (msg.what) {
			case WHAT_INCREASE:
				//限制number<=20
				if(number==20){
					Toast.makeText(HandlerDemoActivity.this, "已经达到最大值", 0).show();
					btn_demo_pause.setEnabled(false);
					return;
				}
				number++;
				tv_demo_number.setText(number+"");
				//发送增加的延迟消息
				handler.sendEmptyMessageDelayed(WHAT_INCREASE, 1000);
				break;
			case WHAT_DECREASE:
				//限制number>=1
				if(number==1){
					Toast.makeText(HandlerDemoActivity.this, "已经达到最小值", 0).show();
					btn_demo_pause.setEnabled(false);
					return;
				}
				number--;
				tv_demo_number.setText(number+"");
				//发送减少的延迟消息
				handler.sendEmptyMessageDelayed(WHAT_DECREASE, 1000);
				break;

			default:
				break;
			}
		};
	};

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_handler_demo);
		init();
	}

	public void init() {
		tv_demo_number = (TextView) findViewById(R.id.tv_demo_number);
		btn_demo_increase = (Button) findViewById(R.id.btn_demo_increase);
		btn_demo_decrease = (Button) findViewById(R.id.btn_demo_decrease);
		btn_demo_pause = (Button) findViewById(R.id.btn_demo_pause);

		btn_demo_decrease.setOnClickListener(this);
		btn_demo_increase.setOnClickListener(this);
		btn_demo_pause.setOnClickListener(this);
	}

	@Override
	public void onClick(View v) {
		if (v == btn_demo_increase) {// 自动增加 what=1
			//限制button可操作性
			btn_demo_decrease.setEnabled(true);
			btn_demo_increase.setEnabled(false);
			btn_demo_pause.setEnabled(true);
			//停止减少(移除未处理的减少的消息)
			handler.removeMessages(WHAT_DECREASE);
			// 发消息
			handler.sendEmptyMessage(WHAT_INCREASE);
		} else if (v == btn_demo_decrease) {// 自动减少 what=2
			//限制button可操作性
			btn_demo_decrease.setEnabled(false);
			btn_demo_increase.setEnabled(true);
			btn_demo_pause.setEnabled(true);
			//停止增加(移除未处理的增加的消息)
			handler.removeMessages(WHAT_INCREASE);
			// 发消息
			handler.sendEmptyMessage(WHAT_DECREASE);
		} else if (v == btn_demo_pause) {// 暂停
			//限制button可操作性
			btn_demo_decrease.setEnabled(true);
			btn_demo_increase.setEnabled(true);
			btn_demo_pause.setEnabled(false);
			//停止增加/减少(移除未处理的减少/增加的消息)
			handler.removeMessages(WHAT_DECREASE);
			handler.removeMessages(WHAT_INCREASE);
		}
	}
}

三.测试AsyncTask的使用

1.AsyncTask的理解

在没有AsyncTask之前, 我们用Handler+Thread就可以实现异步任务的功能需求

AsyncTask是对Handler和Thread的封装, 使用它更编码更简洁,更高效

AsyncTask封装了ThreadPool, 比直接使用Thread效率要高

2.相关API

AsyncTask: 简化Handler处理多线程通信的问题

AsyncTask<Params, Progress, Result>

Params 启动任务执行的输入参数,比如HTTP请求的URL。

Progress 后台任务执行的百分比。

Result 后台执行任务最终返回的结果,比如String。

execute(Params... params) 

启动任务, 开始任务的执行流程

void onPreExecute() 

在分线程工作开始之前在UIThread中执行,一般用来显示提示视图

Result doInBackground(Params... params) 

在workerThread中执行, 完成任务的主要工作,通常需要较长的时间

void onPostExecute(Result result)   

在doInBackground()执行完后在UIThread中执行,一般用来更新界面 

publishProgress(Progress... values) : 在分线程中, 发布当前进度
void onProgressUpdate(Progress... values) : 在主线程中更新进度

3.过程分析图


4.代码实现

package com.example.atguigu_05;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.SystemClock;
import android.view.View;

public class AsyncTastTestActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_async_tast_test);
	}
	
	private File apkFile;
	private ProgressDialog dialog;
	public void downloadApk(View v){
		//启动异步任务处理
		new AsyncTask<Void, Integer, Void>() {

			//1.主线程,显示提示视图
			protected void onPreExecute() {
				dialog = new ProgressDialog(AsyncTastTestActivity.this);
				dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
				dialog.show();
				
				//准备用于保存APK文件的File对象:/storage/sdcard/Android/package_name/files/xxx.apk
				apkFile = new File(getExternalFilesDir(null),"update.apk");
			};
			
			//2.分线程,联网请求
			@Override
			protected Void doInBackground(Void... params) {
				try {
					// 1).得到连接对象
					String path = "http://192.168.51.65:8080/web/ActivityDemo.apk";
					URL url = new URL(path);
					HttpURLConnection connection = (HttpURLConnection) url.openConnection();
					// 2).设置
					//connection.setRequestMethod("GET");默认
					connection.setConnectTimeout(5000);
					connection.setReadTimeout(1000);
					// 3).连接
					connection.connect();
					// 4).请求并得到响应码200
					int responseCode = connection.getResponseCode();
					if(responseCode==200){
						//设置dialog的最大进度
						dialog.setMax(connection.getContentLength());
						// 5).得到包含APK文件数据的InputStream
						InputStream is = connection.getInputStream();
						// 6).创建指向apkFile的FileOutputStream
						FileOutputStream fos = new FileOutputStream(apkFile);
						// 7).边读边写
						byte[] buffer = new byte[1024];
						int len = -1;
						while((len=is.read(buffer))!=-1){
							fos.write(buffer,0,len);
							// 8).显示下载进度
							//dialog.incrementProgressBy(len);
							//在分线程中发布当前进度
							publishProgress(len);
							//休息一会(模拟网速慢 时)
							//Thread.sleep(50);
							SystemClock.sleep(50);
						}
						fos.close();
						is.close();
					}
					// 9).下载完成,关闭,进入3.
					connection.disconnect();
				}catch(Exception e){
					e.printStackTrace();
				}
				return null;
			}
			
			//3.主线程,更新界面(在publishProgress()后执行)
			protected void onPostExecute(Void result) {
				dialog.dismiss();
				installAPK();
			};
			
			//在主线程中更新进度
			protected void onProgressUpdate(Integer[] values) {
				dialog.incrementProgressBy(values[0]);
			};
		}.execute();
	}
	/**
	 * 启动安装APK
	 */
	private void installAPK(){
		Intent intent = new Intent("android.intent.action.INSTALL_PACKAGE");
		intent.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive");
		startActivity(intent);
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值