Android学习10-----Android组件通信 (4) 消息机制

阅读更多

Android 操作系统中存在着消息队列的操作,用消息队列可以完成主线程和子线程之间的消息传递,要想完成这些线程的消息操作,则需要使用 Looper Message Handler 类,其关系如下:

Android学习10-----Android组件通信 (4) 消息机制_第1张图片

 

 

所以,我们可以发现, Looper 本身提供的是一个消息队列的集合,而每个消息都可以通过 Handler 增加和取出,而操作 Handler 的对象就是主线程( UI Thread )和子线程(利用 Runable 实现的线程操作类)。

说明:

         如果把 Looper 比喻成一个正在排队卖票的队伍,那么每个排队的人就是一个 Message ,而一个维护队伍的管理员就相当于是一个 Handler ,管理员负责通知对外的人进到队列之中等待,也负责通知队列中的人离开队伍。

 

1 Android.os.Message 的主要功能是进行消息的封装,同事可以指定消息的操作形式。

No.

变量或方法

类型

描述

1

Public int what

变量

用于定义此 Message 属性何种操作

2

Public Object obj

变量

用于定义此 Message 传递的信息数据

3

Public int arg1

变量

传递一些整型数据时使用,一般很少用

4

Public int arg2

变量

传递一些整型数据时使用,一般很少用

5

Public Handler getTarget()

普通

取得操作此消息的 Handler 对象

Message 类中,使用最多的是 what obj 两个变量,通过 what 变量指明一个 Message 所携带的是何种信息,而通过 obj 传递信息

 

2 Message 对象封装了所有的消息,而这些消息的操作需要 android.os.Handler 类完成

No.

方法

类型

描述

1

Public Handler()

构造

创建一个新的 Handler 实例

2

Public Handler(Looper looper)

构造

使用指定的队列创建一个新的 Handler 实例

3

Public final Message obtainMessage(int what,Object obj)

普通

获得一个 Messge 对象

4

Public final Message obtainMessage(int what,Int arg1,

int arg2,Object obj)

普通

获得一个 Messge 对象

5

Public void handleMessage(Message msg)

普通

处理消息的方法,子类要覆写此方法

6

Public final Boolean   hasMessages(int what)

普通

判断是否有指定的 Message

7

Public final boolwan hasMessages(int what,Object obj)

普通

判断是否有指定的 Message

8

Public final void removeMessages(int what)

普通

删除指定的 Message

9

Public final void removeMessages(int what,Object obj)

普通

删除指定的 Message

10

Public final Boolean sendEmptyMessage(int what)

普通

发送一个空消息

11

Public final Boolean sendEmptyAtTime(Int what,

long uptimeMills)

普通

在指定的日期时间发送消息

12

Public final boolean senEmptyMessageDelayed(int what,

long delayMills)

普通

等待指定的时间之后发送消息

13

Public final boolean sendMessage(Message msg)

普通

发送消息

可以发现 Handler 所有的相关操作都是在操作 Message 的,可以向队列中添加 Message ,也可以从队列中删除指定的 Message

 

下面我们来通过一个定时更新文本来做一个范例:

Message01_Activity.java

package com.iflytek.demo;

import java.util.Timer;
import java.util.TimerTask;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.widget.TextView;

public class Message01_Activity extends Activity {
	private TextView info = null;
	private static int count = 0; // 表示更新后的记录
	private static final int SET = 1; // 操作的what状态

	private Handler myHandler = new Handler() {
		@Override
		public void handleMessage(Message msg) {
			switch (msg.what) { // 判断操作的消息类型
			case SET: // 更新组件
				Message01_Activity.this.info.setText("XDWANG - " + count++);
			}
		}
	};

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		super.setContentView(R.layout.main);
		this.info = (TextView) super.findViewById(R.id.info); // 取得组件

		// 通过任务管理器进行任务调度
		Timer timer = new Timer();
		//每一秒调度一次
		timer.schedule(new MyTask(), 0, 1000);

	}

	/**
	 * 
	 * @author xdwang
	 * 
	 * @create 2012-10-27下午08:11:25
	 * 
	 * @email:[email protected]
	 * 
	 * @description 定时调度类
	 * 
	 */
	private class MyTask extends TimerTask {

		@Override
		public void run() {
			Message msg = new Message(); // 设置更新
			msg.what = SET; // 操作的标记
			Message01_Activity.this.myHandler.sendMessage(msg); // 发送消息
		}

	}
}

 

从上面代码我们可以发现是在 Handler 中处理组件内容的,那么为什么不在任务调度器里完成呢?因为子线程不能更新主线程中各个组件的状态。即子线程无法更新组件,那么现在只能采用与之前一样的方式,在子线程之中返回要要操作的消息,而后在主线程之中利用 Handler 处理这些消息,从而实现线程的操作

 

3 、在使用 Handler 处理 Message 时,都需要依靠一个 Looper 通道完成,当用户取得一个 Handler 对象时,实际上都是通过 Looper 完成的,在一个 Activity 类中,会自动帮助用户启动 Looper 对象,而若是在一个用户自定义的类中,则需要手动调用 Looper 类的若干方法,之后才可以正常的启动 Looper 对象,其方法如下:

No.

方法名称

描述

1

Public static final synchronized Looper getMainLooper()

取得主线程

2

Public static final myLooper()

返回当前的线程

3

Public static final void prepare()

初始化 Looper 对象

4

Public static final void prepareMainLooper()

初始化主线程 Looper 对象

5

Public void quit()

消息队列结束时调用

6

Public static final void loop()

启动消息队列

 

下面我们来利用 Looper 做一个范例

Message02_Activity.java:

package com.iflytek.demo;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class Message02_Activity extends Activity {
	private TextView info = null;
	private static final int SET = 1; // 操作的what状态
	private Button but = null; // 操作按钮

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		super.setContentView(R.layout.main);
		this.info = (TextView) super.findViewById(R.id.info); // 取得组件
		this.but = (Button) super.findViewById(R.id.but); // 取得组件
		this.but.setOnClickListener(new OnClickListenerImpl()); // 单击事件
	}

	private class OnClickListenerImpl implements OnClickListener {
		@Override
		public void onClick(View v) {
			Looper looper = Looper.myLooper();
			MyHandler myHandler = new MyHandler(looper);
			myHandler.removeMessages(0); // 表示清空所有的消息
			String data = "xdwangiflytek.iteye.com"; // 要传递的消息
			Message msg = myHandler.obtainMessage(SET, 1, 1, data); // 创建消息
			myHandler.sendMessage(msg); // 发送消息
		}

	}

	private class MyHandler extends Handler {
		public MyHandler(Looper looper) {
			super(looper);
		}

		@Override
		public void handleMessage(Message msg) {
			switch (msg.what) { // 判断操作的消息类型
			case SET: // 更新组件
				Message02_Activity.this.info.setText(msg.obj.toString()); // 设置文本组件
			}
		}
	}
}
 

这里如果我们不设置Looper,如下:

private class OnClickListenerImpl implements OnClickListener {
		@Override
		public void onClick(View v) {
			MyHandler myHandler = new MyHandler();
			myHandler.removeMessages(0); // 表示清空所有的消息
			String data = "xdwangiflytek.iteye.com"; // 要传递的消息
			Message msg = myHandler.obtainMessage(SET, 1, 1, data); // 创建消息
			myHandler.sendMessage(msg); // 发送消息
		}

	}

	private class MyHandler extends Handler {
		@Override
		public void handleMessage(Message msg) {
			switch (msg.what) { // 判断操作的消息类型
			case SET: // 更新组件
				Message03_Activity.this.info.setText(msg.obj.toString()); // 设置文本组件
			}
		}
	}

 

其效果是一样的。

 

下面我们来完成一个主线程与子线程之间的数据交换

主线程向子线程发送数据,然后子线程再向主线程发送数据:

Thread01_Activity.java

package com.iflytek.demo;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class Thread02_Activity extends Activity {

	public static final int SETMAIN = 1; // 设置一个what标记
	public static final int SETCHILD = 2; // 设置what的标记]
	private Handler mainHandler, childHandler;
	private TextView msg = null;
	private Button but;

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		super.setContentView(R.layout.main);
		this.msg = (TextView) super.findViewById(R.id.msg);
		this.but = (Button) super.findViewById(R.id.but);
		this.mainHandler = new Handler() {

			@Override
			public void handleMessage(Message msg) {
				switch (msg.what) {
				case SETMAIN:
					Thread02_Activity.this.msg.setText("主线程接收数据:"
							+ msg.obj.toString());
					break;
				}
			}

		};
		new Thread(new ChildThread(), "Child Thread").start();
		this.but.setOnClickListener(new OnClickListenerImpl());
	}

	private class OnClickListenerImpl implements OnClickListener {

		@Override
		public void onClick(View v) { // 是将信息发送到子线程之中
			//因为线程的状态不固定,所以这里需要一个判断
			if (Thread02_Activity.this.childHandler != null) {
				Message childMsg = Thread02_Activity.this.childHandler
						.obtainMessage(); // 创建消息
				childMsg.obj = Thread02_Activity.this.mainHandler.getLooper()
						.getThread().getName()
						+ " --> Hello XDWANG .";
				childMsg.what = SETCHILD;
				Thread02_Activity.this.childHandler.sendMessage(childMsg);
			}
		}

	}

	/**
	 * 
	 * @author xdwang 
	 *
	 * @create 2012-10-27下午08:31:25
	 * 
	 * @email:[email protected]
	 * 
	 * @description 子线程的线程类
	 *
	 */
	class ChildThread implements Runnable {

		@Override
		public void run() {
			Looper.prepare();//准备好一个Looper对象
			Thread02_Activity.this.childHandler = new Handler() {

				@Override
				public void handleMessage(Message msg) {
					switch (msg.what) {
					case SETCHILD: // 子线程接收主线程发送来的消息
						System.out.println("*** Main Child Message : "
								+ msg.obj); // 输出数据
						Message toMain = Thread02_Activity.this.mainHandler
								.obtainMessage();
						toMain.obj = "\n\n[B]这是子线程发送给主线程的信息:"
								+ super.getLooper().getThread().getName();
						toMain.what = SETMAIN;
						Thread02_Activity.this.mainHandler.sendMessage(toMain);
						break;
					}
				}

			};
			Looper.loop(); // 创建消息队列
		}

	}

	@Override
	protected void onDestroy() {
		super.onDestroy();
		//结束子线程的操作队列
		Thread02_Activity.this.childHandler.getLooper().quit();
	}

}
 

打印:

10-27 21:04:07.165: I/System.out(4449): *** Main Child Message : main --> Hello XDWANG .
 

下面我们再以一个时钟显示来看看
前面我们说过时钟的组件,但是当时没有时间的说明,下面我们来写一个这样的时钟
main.xml



	
	


 AnalogClockThread_Activity.java

package com.iflytek.demo;

import java.text.SimpleDateFormat;
import java.util.Date;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.widget.TextView;

public class AnalogClockThread_Activity extends Activity {
	private TextView info = null;
	private static final int SET = 1;
	private Handler handler = new Handler() {

		@Override
		public void handleMessage(Message msg) {
			switch (msg.what) {
			case SET:
				AnalogClockThread_Activity.this.info.setText("当前时间为:"
						+ msg.obj.toString());
				break;
			}
		}
	};

	private class ClockThread implements Runnable {

		@Override
		public void run() {
			while (true) { // 一直更新
				Message msg = AnalogClockThread_Activity.this.handler
						.obtainMessage(AnalogClockThread_Activity.SET,
								new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
										.format(new Date()));
				AnalogClockThread_Activity.this.handler.sendMessage(msg);
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
				}
			}
		}

	}

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		super.setContentView(R.layout.main);
		this.info = (TextView) super.findViewById(R.id.info);
		new Thread(new ClockThread()).start();
	}
}
 

进度条组件:ProgressBar
main.xml



	
	
	
	
	
	

 属性说明:

android:visibility="gone":隐藏进度条
android:max="120":设置最大进度
android:progress="50":设置当前进度
android:secondaryProgress="70":设置第二进度条当前值
 

ProgressBar_Activity.java:

package com.iflytek.demo;

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

public class ProgressBar_Activity extends Activity {
	private static final int STOP = 1;
	private static final int CONTINUE = 2;
	private ProgressBar myprobarA, myprobarB, myprobarC, myprobarD, myprobarE;
	private Button mybut;

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		super.setContentView(R.layout.main);
		this.myprobarA = (ProgressBar) super.findViewById(R.id.myprobarA);
		this.myprobarB = (ProgressBar) super.findViewById(R.id.myprobarB);
		this.myprobarC = (ProgressBar) super.findViewById(R.id.myprobarC);
		this.myprobarD = (ProgressBar) super.findViewById(R.id.myprobarD);
		this.myprobarE = (ProgressBar) super.findViewById(R.id.myprobarE);
		this.mybut = (Button) super.findViewById(R.id.mybut);
		this.myprobarA.setIndeterminate(false); // 不确定模式
		this.myprobarB.setIndeterminate(false); // 不确定模式
		this.myprobarC.setIndeterminate(true); // 确定模式
		this.myprobarD.setIndeterminate(false); // 不确定模式
		this.myprobarE.setIndeterminate(false); // 不确定模式
		this.mybut.setOnClickListener(new OnClickListenerImpl()); // 单击事件
	}

	private class OnClickListenerImpl implements OnClickListener {

		@Override
		public void onClick(View v) {
			ProgressBar_Activity.this.myprobarB.setSecondaryProgress(50);
			ProgressBar_Activity.this.myprobarA.setVisibility(View.VISIBLE);
			ProgressBar_Activity.this.myprobarB.setVisibility(View.VISIBLE);
			ProgressBar_Activity.this.myprobarC.setVisibility(View.VISIBLE);
			ProgressBar_Activity.this.myprobarD.setVisibility(View.VISIBLE);
			ProgressBar_Activity.this.myprobarE.setVisibility(View.VISIBLE);

			ProgressBar_Activity.this.myprobarA.setMax(120);
			ProgressBar_Activity.this.myprobarB.setMax(120);
			ProgressBar_Activity.this.myprobarA.setProgress(0);
			ProgressBar_Activity.this.myprobarB.setProgress(0);

			new Thread(new Runnable() {
				@Override
				public void run() {
					int count = 0; // 保存当前进度的值
					for (int i = 0; i < 10; i++) {
						count = (i + 1) * 20; // 进度的增长快一些
						try {// 每次操作延迟500MS
							Thread.sleep(500);
						} catch (InterruptedException e) {
						}
						if (i == 6) { // 正好增长到120
							Message m = new Message();
							m.what = ProgressBar_Activity.STOP; // 停止
							ProgressBar_Activity.this.myMessageHandler
									.sendMessage(m);// 停止
						} else {
							Message m = new Message();
							m.what = ProgressBar_Activity.CONTINUE;
							m.arg1 = count;
							ProgressBar_Activity.this.myMessageHandler
									.sendMessage(m);
						}
					}
				}
			}).start();
		}

	}

	private Handler myMessageHandler = new Handler() {

		@Override
		public void handleMessage(Message msg) {
			switch (msg.what) {
			case ProgressBar_Activity.STOP:
				ProgressBar_Activity.this.myprobarA.setVisibility(View.GONE);
				ProgressBar_Activity.this.myprobarB.setVisibility(View.GONE);
				ProgressBar_Activity.this.myprobarC.setVisibility(View.GONE);
				ProgressBar_Activity.this.myprobarD.setVisibility(View.GONE);
				ProgressBar_Activity.this.myprobarE.setVisibility(View.GONE);
				Thread.currentThread().interrupt();
				break;
			case ProgressBar_Activity.CONTINUE:
				if (!Thread.currentThread().isInterrupted()) { // 线程没有中断
					ProgressBar_Activity.this.myprobarA.setProgress(msg.arg1);
					ProgressBar_Activity.this.myprobarB.setProgress(msg.arg1);
					ProgressBar_Activity.this.myprobarC.setProgress(msg.arg1);
					ProgressBar_Activity.this.myprobarD.setProgress(msg.arg1);
					ProgressBar_Activity.this.myprobarE.setProgress(msg.arg1);
				}
				break;
			}
		}
	};
}
 

 

效果图:

Android学习10-----Android组件通信 (4) 消息机制_第2张图片

 

 

异步处理工具类: AsyncTask

上面我们了解了主线程与子线程之间的通信主要依靠 Handler 完成,但子线程无法直接对主线程的组件进行更新,而如果所有的开发都分别定义若干个子线程的操作对象,则这多个对象同时对主线程操作就会非常满分,为了解决这个问题,在 Android1.5 之后专门提供了一个 andorid.os.AsyncTask (非同步任务)类,可以通过此类完成非阻塞的操作类,该类的功能与 Handler 类似,可以在后台进行操作之后更新主线程的 UI ,但其使用比 Handler 要容易的多。

通过此类的定义可以发现,在 AsyncTask 类中要通过泛型指定 3 个参数,作用分别是:

         Params :启动时需要的参数类型,如每次操作的休眠时间为 Integer

         Progress :后台执行任务的百分比,如进度条需要传递的是 Integer

         Result :后台执行完毕之后返回的信息,如完成数据信息显示传递的是 String

常用方法:

No.

方法

描述

1

Public final Boolean cancel(Boolean

mayInterruptIfRunning))

指定是否取消当前线程操作

2

Public final AsyncTask

execute(Params… params)

执行 AsyncTask 操作

3

Public final Boolean isCancelled()

判断子线程是否被取消

4

Protected final void publishProgress(

Progress… values)

更新线程进度

5

Protected abstract Result doInBackground(

Params… params)

在后台完成任务执行,可以调用

publishProgress() 方法更新线程进度

6

Protectes void onProgressUpdate(

Progress… values)

在主线程中执行,用于显示任务的进度

7

Protectes void onPreExecute()

在主线程中执行,在 doInBackground() 之前执行

8

Protectes void onPostExecute(Result result)

在主线程中执行,方法参数为任务执行结果

9

Protectes void onCancelled()

主线程中执行,在 cancel() 方法之后执行

 

下面我们通过 AsyncTask 来实现进度条

main.xml



	
	


 
AsyncTask_Activity.java

package com.iflytek.demo;

import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.widget.ProgressBar;
import android.widget.TextView;

public class AsyncTask_Activity extends Activity {
	private ProgressBar progressBar = null;
	private TextView info = null;

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		super.setContentView(R.layout.main);
		this.progressBar = (ProgressBar) super.findViewById(R.id.bar);
		this.info = (TextView) super.findViewById(R.id.info);
		ChildUpdate child = new ChildUpdate();
		//每次休眠100毫秒
		child.execute(100);
	}

	// 每次处理后台进度的类型是Integer、更新之后的数值Integer,最后的结果返回的是字符串
	private class ChildUpdate extends AsyncTask {

		@Override
		protected void onPostExecute(String result) {
			AsyncTask_Activity.this.info.setText(result);
		}

		@Override
		protected void onProgressUpdate(Integer... values) { // 每次更新之后的内容
			AsyncTask_Activity.this.info.setText("当前的进度值是:"
					+ String.valueOf(values[0]));
		}

		@Override
		protected String doInBackground(Integer... params) { // 每次的进度处理,可以更新UI组件
			for (int x = 0; x < 100; x++) {
				AsyncTask_Activity.this.progressBar.setProgress(x); // 设置进度
				this.publishProgress(x); // 更新,调用更新操作
				try {// 延迟的操作由外部决定
					Thread.sleep(params[0]);
				} catch (InterruptedException e) {
				}
			}
			return "执行完毕";
		}

	}
}
 

从上我们可以发现这个组件完全融合了Handler和Message的功能所完成。

下面我们再做一个简单的文件管理器
main.xml:



	


 

file_list.xml:



	
		
		
	


 

AsyncTaskListFile_Activity.java

package com.iflytek.demo;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import android.widget.SimpleAdapter;

public class AsyncTaskListFile_Activity extends Activity {

	private List> allFileItems = new ArrayList>();
	private SimpleAdapter simpleAdapter = null;
	private ListView listView = null;
	private ListFileThread listFileThread = null;

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		super.setContentView(R.layout.main);
		this.listView = (ListView) super.findViewById(R.id.list);
		File filePath = new File(java.io.File.separator); // 从根目录下开始列出
		this.listView.setOnItemClickListener(new OnItemClickListenerImpl());
		this.listFileThread = new ListFileThread();
		this.listFileThread.execute(filePath);
	}

	private class OnItemClickListenerImpl implements OnItemClickListener {

		@Override
		public void onItemClick(AdapterView parent, View view, int position,
				long id) {
			File currFile = (File) AsyncTaskListFile_Activity.this.allFileItems
					.get(position).get("name");
			if (currFile.isDirectory()) { // 当前是一个目录
				AsyncTaskListFile_Activity.this.allFileItems = new ArrayList>();
				AsyncTaskListFile_Activity.this.listFileThread = new ListFileThread();
				AsyncTaskListFile_Activity.this.listFileThread.execute(currFile);
			}
		}

	}

	private class ListFileThread extends AsyncTask {

		@Override
		protected void onProgressUpdate(File... values) {
			Map fileItem = new HashMap(); // 表示可以返回
			if (values[0].isDirectory()) {
				fileItem.put("img", R.drawable.folder_close); // 文件夹
			} else { // 是文件
				fileItem.put("img", R.drawable.file);
			}
			fileItem.put("name", values[0]);
			AsyncTaskListFile_Activity.this.allFileItems.add(fileItem);
			AsyncTaskListFile_Activity.this.simpleAdapter = new SimpleAdapter(
					AsyncTaskListFile_Activity.this,
					AsyncTaskListFile_Activity.this.allFileItems,
					R.layout.file_list, new String[] { "img", "name" },
					new int[] { R.id.img, R.id.name });
			AsyncTaskListFile_Activity.this.listView
					.setAdapter(AsyncTaskListFile_Activity.this.simpleAdapter);
		}

		@Override
		protected String doInBackground(File... params) {
			if (!params[0].getPath().equals(java.io.File.separator)) { // 不是根目录
				Map fileItem = new HashMap(); // 表示可以返回
				fileItem.put("img", R.drawable.folder_open); // 可以返回
				fileItem.put("name", params[0].getParentFile());
				AsyncTaskListFile_Activity.this.allFileItems.add(fileItem);
			}
			if (params[0].isDirectory()) { // 是文件夹
				File tempFile[] = params[0].listFiles();
				if (tempFile != null) {
					for (int x = 0; x < tempFile.length; x++) {
						this.publishProgress(tempFile[x]);
					}
				}
			}
			return "文件已列出";
		}
	}
}
 

效果图:

Android学习10-----Android组件通信 (4) 消息机制_第3张图片

 

 

 

  • Android学习10-----Android组件通信 (4) 消息机制_第4张图片
  • 大小: 15.6 KB
  • Android学习10-----Android组件通信 (4) 消息机制_第5张图片
  • 大小: 13.9 KB
  • Android学习10-----Android组件通信 (4) 消息机制_第6张图片
  • 大小: 18.9 KB
  • 查看图片附件

你可能感兴趣的:(Looper,Handler,Message,progressBar,AsyncTask)