现在的位置: 首页 > 综合 > 正文

一个简单的,基本功能完善的移动通信架构

2018年04月19日 ⁄ 综合 ⁄ 共 9961字 ⁄ 字号 评论关闭

          设计一个简单的,易用的通信框架应该包含三个部分:监听器(耦合UI线程和通信线程),计时器(在通信超时的情况下,通知UI线程),通信体(维护通信)。

 

下面给出一个设计完好的例子:

 

      UI代码:

package app.midlet;

import javax.microedition.io.HttpConnection;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.TextBox;
import javax.microedition.midlet.MIDlet;

import app.http.HttpConst;
import app.http.Request;
import app.http.Response;
import app.http.UI_HTTP;

public class eastmoney extends MIDlet implements CommandListener {
	private Command exitCommand = null;
	private Display display = null;
	private TextBox t = null;
	private UI_HTTP http;

	public eastmoney() {
		init();
		send();
		exitCommand = new Command("Exit", Command.EXIT, 2);
		t = new TextBox("welcome ", "", 256, 0);
		t.addCommand(exitCommand);
		t.setCommandListener(this);

	}

	private void init() {
		http = new UI_HTTP();
	}

	public void startApp() {
		display = Display.getDisplay(this);
		display.setCurrent(t);

	}

	public void pauseApp() {

	}

	public void destroyApp(boolean unconditional) {

	}

	public void commandAction(Command arg0, Displayable arg1) {
		if (arg0 == exitCommand) {
			destroyApp(false);
			notifyDestroyed();
		}

	}

	private void send() {
		Request request = new Request("cftpopup.eastmoney.com/mobile_toolbar_utf8.txt", null, null, HttpConst.COMM_AD);
		request.method = HttpConnection.GET;
		sendRequest(request);
	}

	public void sendRequest(Request request) {
		http.sendRequest(request, this);
	}

	public void httpCompleted(Response resp) {
		t.setString((String) resp.result);

	}

	public void httpException(Exception e) {
		System.out.println(e);
	}
}

       请求的封装类:

package app.http;

import java.util.Hashtable;

import javax.microedition.io.HttpConnection;

/**
 * 请求的封装类
 * 
 * @author 冯小卫2011-12-9
 */
public class Request {
	public String url;
	public Hashtable properties;
	public byte[] content;
	public int commId;
	// public int screenId;
	public String method = HttpConnection.POST;

	public Request() {

	}

	/**
	 * 适合普通POST请求
	 * 
	 * @param url
	 * @param properties
	 * @param content
	 * @param commId
	 */
	public Request(String url, Hashtable properties, String content, int commId) {
		this.url = url;
		this.properties = properties;
		if (content != null) {
			this.content = content.getBytes();
		}
		this.commId = commId;
		// this.screenId = screenId;
	}

	/**
	 * 适合普通GET请求
	 * 
	 * @param url
	 * @param commId
	 * @param method
	 */
	public Request(String url, int commId, String method) {
		this.url = url;
		this.commId = commId;
		// this.screenId = screenId;
		this.method = method;
	}

}

       响应的封装类:

package app.http;

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

import javax.microedition.io.HttpConnection;

/**
 * 响应:包含响应结果
 * 
 * @author 冯小卫2011-12-12
 */
public class Response {
	public Object result;
	public int commId;

	// public int screenId;

	/**
	 * 把响应数据填充到result中
	 * 
	 * @param conn
	 * @param inputStream
	 * @param request
	 * @throws IOException
	 */
	public void setData(HttpConnection conn, InputStream inputStream, Request request) throws IOException {
		byte[] buffer = new byte[HttpConst.BUFFER_SIZE];
		int count;
		ByteArrayOutputStream tmp = new ByteArrayOutputStream();
		while ((count = inputStream.read(buffer)) != -1) {
			tmp.write(buffer, 0, count);
		}
		result = new String(tmp.toByteArray(), "UTF-8");
		commId = request.commId;
	}

}

        监听器极其实现类:

package app.http;

import app.http.Response;

public interface HttpListener {
	public void completed(Response resp);

	public void exception(Exception e);
}

 

package app.http;

import javax.microedition.midlet.MIDlet;

import app.midlet.eastmoney;

/**
 * UI线程和HTTP通信线程交互的类
 * 
 * @author 冯小卫2011-12-9
 */
public class UI_HTTP implements HttpListener {
	private HttpHandler httpHandler = null;
	// private int[] requestInfo = null;
	private MIDlet midlet;

	public UI_HTTP() {
		httpHandler = new HttpHandler(this);
	}

	/**
	 * 数据解析完成的时候,应该让界面刷新(没有处理)
	 */
	public void completed(Response resp) {

		try {
			// if (requestInfo != null) {
			// BaseScreen requestScreen = findRequestScreen();
			// if (requestScreen != null) {
			// requestScreen.httpCompleted(resp);
			// }
			// }
			((eastmoney) midlet).httpCompleted(resp);
		} catch (Exception e) {
			e.printStackTrace();
		}
		// @完成Http通讯后刷新normal controls
		// this.setNeedPaint();

	}

	public void exception(Exception e) {
		((eastmoney) midlet).httpException(e);

	}

	public void timeOut() {
		((eastmoney) midlet).httpException(new Exception("timeOut"));

	}

	public void sendRequest(Request request) {
		// requestInfo = new int[] { request.screenId, request.commId };
		httpHandler.sendRequest(request);
	}

	/**
	 * @param request
	 */
	public void sendRequest(Request request, MIDlet midlet) {
		// requestInfo = new int[] { request.screenId, request.commId };
		this.midlet = midlet;
		httpHandler.sendRequest(request);
	}

	/**
	 * 停止HTTP请求
	 */
	public void stop() {
		httpHandler.stop();
	}

}

     计时器:

package app.http;

public class HttpMonitor implements Runnable {
	// 超时时间(毫秒)
	long timeout;
	long startTime;
	boolean active = false;
	boolean time = false;
	HttpHandler handler;

	public HttpMonitor(HttpHandler handler) {
		this.handler = handler;
		active = true;
		timeout = 10 * 1000;// 10秒认为超时
	}

	public void run() {
		while (active) {
			if (time) {
				long tmp = System.currentTimeMillis() - startTime;
				if (tmp > timeout) {
					handler.timeout();
					stopTimer();
				} else {
					try {
						Thread.sleep(100);
					} catch (InterruptedException ie) {
						active = false;
					}
				}

			}
			try {
				Thread.sleep(100);
			} catch (Exception e) {
				e.printStackTrace();
				active = false;
			}

		}

	}

	public void startTimer() {
		if (!time) {
			startTime = System.currentTimeMillis();
			time = true;
		}
	}

	/**
	 * 停止本次计时,但是计时线程依然运行
	 */
	public void stopTimer() {
		time = false;
	}

	/**
	 * 终止计时线程
	 */
	public void cleanup() {
		time = false;
		active = false;
	}

}

    通信体:

 

package app.http;

import java.util.Vector;

public class HttpHandler implements Runnable {
	private HttpMonitor httpMonitor;

	private boolean isRunning = false;
	// Http client
	private HttpClient httpClient = null;
	// HttpListener
	private HttpListener httpListener = null;
	// 等待发送的缓冲请求信息
	private Vector vctRequests = new Vector();

	public HttpHandler(HttpListener httpListener) {
		this.httpListener = httpListener;
		httpClient = new HttpClient();
		isRunning = true;
		new Thread(this).start();// 启动发送线程
	}

	public void run() {
		while (isRunning) {
			try {
				if (vctRequests.size() > 0) {
					// 得到Request
					Request request = null;
					synchronized (vctRequests) {
						if (vctRequests.size() > 0) {
							request = (Request) vctRequests.elementAt(0);
							vctRequests.removeElementAt(0);
						}
					}
					// 通过网络请求得到数据
					Response resp = getResponse(request);

					// 数据到达以后,送给界面解析
					if (resp != null) {
						if (httpListener != null) {
							httpListener.completed(resp);
						}
						resp = null;
					}
				}
				Thread.sleep(200);
			} catch (Exception e) {

			}
		}

	}

	private void handleException(Exception e) {
		if (httpListener != null) {
			httpListener.exception(e);
		}
	}

	public void sendRequest(Request request) {
		if (request == null) {
			return;
		}
		synchronized (vctRequests) {
			vctRequests.addElement(request);
		}
	}

	public Response getResponse(Request request) {
		Response resp = null;

		try {
			// 处理数据过程可能比较长 不建议放在synchronized域中
			startTimer();
			resp = httpClient.getResponse(request);
			stopTimer();
		} catch (Exception e) {
			stopTimer();
			handleException(e);
		}

		return resp;
	}

	private void startTimer() {
		httpMonitor = getRequestTimer();
		httpMonitor.startTimer();
	}

	private HttpMonitor getRequestTimer() {
		if (httpMonitor == null) {
			httpMonitor = new HttpMonitor(this);
			new Thread(httpMonitor).start();
		}
		return httpMonitor;
	}

	private void stopTimer() {
		if (httpMonitor != null) {
			httpMonitor.stopTimer();
		}
	}

	/**
	 * 停止HTTP请求
	 */
	public void stop() {
		httpMonitor.cleanup();
		// 请空缓存请求数据
		synchronized (vctRequests) {
			vctRequests.removeAllElements();
		}

		httpListener = null;
		// 中断数据接收监听
		isRunning = false;
		httpClient = null;

	}

	// 这里通信超时的处理时停止计时器,然后通知UI线程
	public void timeout() { // 数据接收超时
		httpMonitor.stopTimer();
		httpListener.exception(new Exception("timeOut"));
	}
}

 

package app.http;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Enumeration;
import java.util.Hashtable;

import javax.microedition.io.Connector;
import javax.microedition.io.HttpConnection;

import app.utils.Functions;

public class HttpClient {
	private HttpConnection conn = null;

	private InputStream inputStream = null;

	private OutputStream outputStream = null;

	private Request request = null;

	/**
	 * 应该在这里处理资费页面的,但是还没有处理
	 * 
	 * @param request
	 * @param httpHandler
	 * @return
	 * @throws Exception
	 */
	public Response getResponse(Request request) throws Exception {
		if (request == null) {
			return null;
		}
		try {
			this.request = request;
			Response resp = new Response();
			makeConnection(request.url);
			setProperty();
			setContent();
			if (conn.getResponseCode() != HttpConnection.HTTP_OK) {
				resp.result = "BAD" + "-" + conn.getResponseCode();
				return resp;
			} else {
				makeInputStream();
				resp.setData(conn, inputStream, request);
			}
			return resp;
		} catch (Exception e) {
			e.printStackTrace();
			throw e;
		} finally {
			this.request = null;
			cleanup();
		}
	}

	private void cleanup() {
		try {
			if (inputStream != null) {
				inputStream.close();
				inputStream = null;
			}
			if (outputStream != null) {
				outputStream.close();
				outputStream = null;
			}
			if (conn != null) {
				conn.close();
				conn = null;
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private void makeInputStream() throws Exception {
		inputStream = conn.openInputStream();
	}

	private void setContent() throws IOException {
		if (request.content != null) {// post
			if (conn.getRequestProperty("Content-Type") == null) {
				conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
			}
			conn.setRequestProperty("Content-Length", String.valueOf(request.content.length));
			makeOutputStream();
			outputStream.write(request.content);
			// outputStream.flush();//不要使用,会导致编码变成 chunked
		} else {// get
			makeOutputStream();
		}

	}

	private void makeOutputStream() throws IOException {
		outputStream = conn.openOutputStream();
	}

	/**
	 * 设置请求方式和参数信息
	 * 
	 * @throws IOException
	 */
	private void setProperty() throws IOException {
		conn.setRequestMethod(request.method);
		Hashtable table = request.properties;
		if (table != null) {
			Enumeration keys = table.keys();
			while (keys.hasMoreElements()) {
				String key = (String) keys.nextElement();
				String value = (String) table.get(key);
				conn.setRequestProperty(key, value);
			}
		}
	}

	/**
	 * 打开连接,可能发生IOException
	 * 
	 * @param url
	 * @throws IOException
	 */
	private void makeConnection(String url) throws IOException {
		if (HttpConst.IS_NET) {
			conn = (HttpConnection) Connector.open("http://" + url);
		} else {
			conn = (HttpConnection) Connector.open("http://" + HttpConst.HTTP_CMWAP + Functions.getNoHost(url));
			conn.setRequestProperty("X-Online-Host", Functions.getHost(url));
		}

	}

}

    用到的工具方法和常量:

 

package app.utils;

public class Functions {
	/**
	 * 获取一个url的host(url指除去http://后剩下的部分)
	 * 
	 * @param url
	 * @return
	 */
	public static String getHost(String url) {
		if (url == null) {
			return null;
		}
		if (url.indexOf("/") > 0) {
			return url.substring(0, url.indexOf("/"));
		}
		return url;
	}

	/**
	 * 获取一个url除去host的部分(url指除去http://后剩下的部分)
	 * 
	 * @param url
	 * @return
	 */
	public static String getNoHost(String url) {
		if (url == null) {
			return null;
		}
		if (url.indexOf("/") > 0) {
			return url.substring(url.indexOf("/") + 1);
		}
		return "index.html";

	}

}

 

package app.http;

public interface HttpConst {
	/**
	 * 默认缓冲区大小
	 */
	int BUFFER_SIZE = 1024;
	/**
	 * 联网方式(默认cmnet)
	 */
	boolean IS_NET = true;
	/**
	 * 默认的代理服务器
	 */
	String HTTP_CMWAP = "10.0.0.172:80/";

	// commId
	int COMM_AD = 1;

}

 

抱歉!评论已关闭.