android消息机制及实例演示

一、消息机制主要元素

1.Message:用来携带子线程中的数据。

2.MessageQueue:用来存放所有子线程发来的Message.

3.Handler:用来在子线程中发送Message,在主线程中接受Message,处理结果

4.Looper:是一个消息循环器,一直循环遍历MessageQueue,从MessageQueue中取一个Message,派发给Handler处理。

二、消息机制写法

使用Handler的步骤:

1.主线程中创建一个Handler

private Handler handler = new Handler(){

public void handleMessage(android.os.Message msg) {

};

};

2.重写handler的handlermessage方法

3.子线程中创建一个Message对象,将获取的数据绑定给msg

Message msg = new Message();

//另一种方式:Message msg = Messge.obtain;

msg.obj = result;

4.主线程中的handler对象在子线程中将message发送给主线程

handler.sendMessage(msg);

5.主线程中handlermessage方法接受子线程发来的数据,就可以做更新UI的操作。

三、实例演示消息机机制——网页请求源码查看器

项目目录截图

layout界面

layout界面代码

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    tools:context="com.zgs.sourcelook.MainActivity" >

    <EditText
        android:id="@+id/et_url"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="https://www.baidu.com" />

    <Button
        android:id="@+id/bt_looksource"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="查看源码" />

    <ScrollView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" >

        <TextView
            android:id="@+id/tv_source"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    </ScrollView>

</LinearLayout>
StreamUtils类代码
package com.zgs.sourcelook;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;

public class StreamUtils {

	public static String streamToString(InputStream  in){
		String result ="";

		try{
			//创建一个字节数组写入流
			ByteArrayOutputStream out = new ByteArrayOutputStream();
			
			byte[] buffer = new byte[1024];
			int length = 0;
			while ((length = in.read(buffer)) !=-1) {
				out.write(buffer, 0, length);
				out.flush();
			}
			
			result = out.toString();//将字节流转换成string
			
			out.close();
		}catch (Exception e) {
			e.printStackTrace();
		}

		return result;
	}
	
}
MainActivity类代码

package com.zgs.sourcelook;

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

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity implements OnClickListener {

	private Context mContext;
	private EditText et_url;
	private TextView tv_source;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		mContext =this;

		//一、获取控件
		et_url = (EditText) findViewById(R.id.et_url);
		Button bt_looksource = (Button) findViewById(R.id.bt_looksource);
		tv_source = (TextView) findViewById(R.id.tv_source);

		//二、设置点击事件
		bt_looksource.setOnClickListener(this);

		System.out.println("oncreate方法线程:"+Thread.currentThread().getName());

	}

	//☆☆☆1.在主线程中创建一个Handler对象
	private Handler handler = new Handler(){
		//☆☆☆2.重写handler的handlermessage方法,用来接收子线程中发来的消息
		public void handleMessage(android.os.Message msg) {
			//☆☆☆5.接收子线程发送的数据,处理数据。
			String result  = (String) msg.obj;
			//☆☆☆6.当前方法属于主线程可以做UI的更新
			//五.获取服务器返回的内容,显示到textview上
			tv_source.setText(result);
		};
	};

	@Override
	public void onClick(View v) {

		try{
			//三.oclick方法中获取用户输入的url地址
			final String url_str = et_url.getText().toString().trim();
			if(TextUtils.isEmpty(url_str)){
				Toast.makeText(mContext, "url不能为空", 0).show();
				return ;
			}

			System.out.println("oclick方法线程:"+Thread.currentThread().getName());

			//创建一个子线程做网络请求
			new Thread(new Runnable() {

				@Override
				public void run() {
					try{
						System.out.println("oclick方法runnable线程:"+Thread.currentThread().getName());

						//四.请求url地址
						//1.创建一个Url对象
						URL url = new URL(url_str);
						//2.获取一个UrlConnection对象
						HttpURLConnection connection = (HttpURLConnection)url.openConnection();
						//3.为UrlConnection对象设置一些请求的参数,请求方式,连接的超时时间 
						connection.setRequestMethod("GET");//设置请求方式
						connection.setConnectTimeout(1000*10);//设置超时时间

						//4.在获取url请求的数据前需要判断响应码,200 :成功,206:访问部分数据成功   300:跳转或重定向  400:错误 500:服务器异常
						int code = connection.getResponseCode();
						if(code == 200){
							//5.获取有效数据,并将获取的流数据解析成String
							InputStream inputStream = connection.getInputStream();
							String result = StreamUtils.streamToString(inputStream);

							//☆☆☆3.子线中创建一个Message对象,为了携带子线程中获取的数据给主线程。
							Message msg = new Message();
							msg.obj = result;//将获取的数据封装到msg中。
							//☆☆☆4.使用handler对象将message发送到主线程。
							handler.sendMessage(msg);
						}

					}catch (Exception e) {
						e.printStackTrace();
					}

				}
			}).start();

		}catch (Exception e) {
			e.printStackTrace();
		}
	}
	
}

添加网络访问权限

运行效果截图


异常及处理

1. ANR:application not response 应用无响应; androoid中耗时的操作(请求网络,大文件的拷贝,数据库的操作)需要在子线程中做。

09-02 01:52:40.711: E/ActivityManager(857): ANR in com.itheima.sourcelook

(com.itheima.sourcelook/.MainActivity)

2. 4.0后网络操作强制在子线程中进行。因为网络访问是耗时的操作,可能会导致ANR

09-02 01:57:32.879: W/System.err(1789): android.os.NetworkOnMainThreadException

3.错误线程调用异常,子线程不能够更新UI(控件的内容)

09-02 02:02:08.873: W/System.err(1858): android.view.ViewRootImpl$CalledFromWrongThreadException:

Only the original thread that created a view hierarchy can touch its views.

主线程不能够做耗时的操作,网络请求就是耗时的操作需要放到子线程做。子线程不能更新控件的内容(更新Ui)。所以产生了矛盾,解决办法就是使用Handler.

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值