您的位置:首页 > 产品设计 > UI/UE

Android UDP通信之Handler、Activity、UI更新

2011-12-15 15:43 351 查看
碰到了一些问题,列出几个说说

1.ERROR/JavaBinder(1726): android.util.AndroidRuntimeException: { what=102 when=330076886 obj=android.os.BinderProxy@325fb830 } This message is already in use.

2.ERROR/global(29212): java.lang.UnsupportedOperationException

ERROR/global(29212): at java.lang.VMThread.suspend(VMThread.java:61)

ERROR/global(29212): at java.lang.Thread.suspend(Thread.java:1403)

3.ERROR/DEBUG_TAG(31012): java.net.SocketException: Interrupted system call

可能文章题目有些不合适,但不管了,先贴代码,其中用到的Activity生命周期、Handler使用参看参考文章

UDPSender:向指定IP发送消息“Hello+i(动态自增值)”,

package com.udp.androidStudy.lx;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;

public class udpSender {
	public static void main(String[] args) {
		try {
			//定义要发送的字符串并转为byte数组
			byte[] buffer = "Hello".getBytes();
			int messageCount=0;
			//目标ip地址
			InetAddress wiFiDestIP = InetAddress.getByName("192.168.43.1");
			//定义UDP数据包,需要指定目标地址及端口号
			DatagramPacket packet = new DatagramPacket(buffer,buffer.length,wiFiDestIP,54321);
			//发送数据
			DatagramSocket sendSocket = new DatagramSocket();
			StringBuffer dataString =new StringBuffer();
			while(true){
				sendSocket.send(packet);
				System.out.println("Send Data:" +  new String(packet.getData()));
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				messageCount++;
				buffer = ("Hello" + messageCount).getBytes();
				packet.setData(buffer,0,buffer.length);
			}
		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (SocketException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}


UDPRecever:接收UDP消息,并在一个TextView中显示

package com.udp.androidStuy.lx;

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

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.SocketOptions;
import java.net.UnknownHostException;

public class UDPRecever extends Activity {
	/** Called when the activity is first created. */
	TextView mainTextView;
	Thread mReceiveThread;
	DatagramSocket server;
	int mMessageCountInt = 0;
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		setContentView(R.layout.main);
		mainTextView = (TextView) findViewById(R.id.mainTextView);
		// 定义UDP监听
		try {
			server = new DatagramSocket(54321);
			//server.setReuseAddress(true);
		} catch (SocketException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		Log.e("myLog","activity run");
		mReceiveThread= new Thread(updateThread);
		mReceiveThread.start();
		mainTextView.append("开始接收数据:\n");

	}
	
	@Override
    protected void onResume() {
		super.onResume();
		if(!mReceiveThread.isAlive()){
			if(server.isClosed()){
				Log.e("myLog","Resume thread");
				// 定义UDP监听
				try {
					server = new DatagramSocket(54321);
					//server.setReuseAddress(true);
				} catch (SocketException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			mReceiveThread= new Thread(updateThread);
			mReceiveThread.start();
			//mReceiveThread.run();
		}
		/*if(!mReceiveThread.isAlive()){
			mReceiveThread.resume();
			
		}*/
	}
	
	@Override
    protected void onPause() {
		super.onPause();
		/*if(mReceiveThread.isAlive()){
			mReceiveThread.suspend();
		}*/
		server.close();
	}
	

	
	// 使用匿名内部类来复写Handler当中的handlerMessage()方法
	final Handler updateBarHandler = new Handler() {
		@Override
		public void handleMessage(Message msg) {
			Log.e("myLog","handleMessage");
			//每次只保存显示30个
			if(mMessageCountInt++ >= 30){
				//mainTextView.computeScroll();
				//mainTextView.scrollBy(0, mMessageCountInt + 10);
				mainTextView.setText("");
				mMessageCountInt = 0;
			}

			mainTextView.append((msg.getData()).getString("data"));
		}
	};

	// 线程类,该类使用匿名内部类的方式进行声明
	Runnable updateThread = new Runnable() {

		public void run() {
			// TODO Auto-generated method stub
			 Log.e("myLog","执行run");

			// 得到一个消息对象,Message类是android系统提供的
			Message msg = new Message();
			Bundle b = new Bundle();

				try {
					// 定义缓冲区
					byte[] buffer = new byte[1024];
					// 定义接收数据包
					DatagramPacket packet = new DatagramPacket(buffer,
							buffer.length);
					while (true) {
						msg = updateBarHandler.obtainMessage();
						// 接收数据
						server.receive(packet);
						// 判断是否收到数据,然后输出字符串
						if (packet.getLength() > 0) {
							String str = new String(buffer, 0, packet
									.getLength());
							b.putString("data", str + "\n");
							msg.setData(b);
							// 将Message对象加入到消息队列当中
							updateBarHandler.sendMessage(msg);
							Log.e("myLog", "sendMessage");
						}
					}
				} catch (SocketException e) {
					Log.e("DEBUG_TAG", e.toString());// e.printStackTrace();原来还想外围加个while用label跳转,试试而已
				} catch (IOException e) {
					Log.e("DEBUG_TAG", e.toString());// e.printStackTrace();
				}
				// Log.e("myLog","Exception");

		}
	};

}
很多注释还留着,可以看看试了哪些东西。

layout中的main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
	android:orientation="vertical" android:layout_width="fill_parent"
	android:layout_height="fill_parent">
	<ScrollView android:layout_width="fill_parent"
		android:layout_height="fill_parent">
		<TextView android:id="@+id/mainTextView"
			android:layout_width="fill_parent" android:layout_height="fill_parent"
			 >
		</TextView>
	</ScrollView>
</LinearLayout>
首先说说Activity,其生命周期不知多少人说了又说,我这里只说这个程序的情况,在按下返回键时,相当于退出程序,重新进入时,执行Activity的onCreate();按下电源键锁屏时,重新进入Activity,没有执行onCreate(),但是由于有些原因另启的线程死了,抛出异常(问题3)的情况,线程死原因在后面,算是执行完毕了。

对问题1,需要注意每次的消息需要updateBarHandler.obtainMessage()获取一下,在Activity一直在可见状态(运行)时,如果没有这句,上面的程序不会有问题,但是当使用回退或者锁屏后恢复,会发现问题1(还有个前提是要有收到UDP消息)。具体原因还是不清,因为程序在回退键后重新进入时是重新执行了线程的run的,猜测是不是重新分配时仍沿用了老的对象空间(原来的server也是在线程里,也会抛出地址被使用的异常)。

对问题2,是在onPause()和onResume()时,想把线程挂起和唤醒,但每次好像不按照自己想的来,还抛出异常,可能是内部不支持?该方法帮助提示是deprecated的了。

对问题3,每次按返回键,主菜单,电源键(锁屏)了,返回后都会抛出,看上面的代码,能知道是线程里跳出while循环了,相当于是线程死了,至于什么原因导致while中的socket抛出异常,还是不知道,猜测是socket阻塞获取消息被系统打断,抛出异常。

问题原因还是不清晰,希望有解决的告知(通常没有人会告知,懂的人看不到这文章,看到的又不会,O(∩_∩)O~ %>_<% )。

转载注明出处:/article/2707871.html

邮箱:w.7849516230@163.com

参看文章:

1.Activity生命周期 http://www.2cto.com/kf/201110/108421.html
2.Handler的使用 http://www.eoeandroid.com/thread-72298-1-1.html
3.android的Handler http://www.cnblogs.com/keyindex/articles/1822463.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐