我想读这篇文章的朋友应该是被标题所吸引的, 毕竟手机已经成为我们日常生活中不可缺少的一部分, 除了很小的孩子和老人外, 基本上是每个人必备的装备^_^。 我们每天与自己的手机形影不离, 如果能通过手机来了解出行信息, 那将极大的方便我们的生活。 没错, 通过手机是可以得到实时的路况信息的。 下面我来详细说明一下。
上周我无意间发现北京公安交通管理局的网站提供了实时的路况信息。
http://210.73.74.215/realroad/
而且实时更新, 所以马上就产生了一个灵感, 能不能把这个通过手机来访问呢。 (其实这个网站是完全可以通过手机内置的浏览器访问的), 于是我准备通过手机上的JAVA程序来实现这个功能。
思路很简单, 这个网站的所有路况信息都是以图片的形式展现的。 我首先的出发点是不通过任何的代理服务器来处理, 也就是说直接用手机来访问URL实现。 不过我发现网站默认的图片格式都是JPG的, 好在现在的大部分手机还是支持这个格式的。 好, 我们现在创建一个工程。
项目名就叫trafficinfo吧, 包含两个类和一个接口。
Main: 继承自MIDlet, 程序的入口点与界面实现。
Network: 负责网络连接
NetworkListener: 一个联网过程的反馈接口。 我稍后解释它。
- import javax.microedition.lcdui.Command;
- import javax.microedition.lcdui.CommandListener;
- import javax.microedition.lcdui.Display;
- import javax.microedition.lcdui.Displayable;
- import javax.microedition.lcdui.Form;
- import javax.microedition.lcdui.Gauge;
- import javax.microedition.lcdui.Image;
- import javax.microedition.lcdui.List;
- import javax.microedition.midlet.MIDlet;
- import javax.microedition.midlet.MIDletStateChangeException;
- public class Main extends MIDlet implements CommandListener, NetworkListener {
- private String[] locations =
- {"西直门", "雍和宫", "东直门",
- "朝阳门", "建国门", "左安门",
- "永定门", "广安门", "菜户营",
- "六里桥", "莲花桥", "蓟门桥",
- "马甸桥", "洋桥", "航天桥",
- "紫竹桥", "长虹桥", "三元桥",
- "玉泉营桥", "分钟寺桥", "双井桥",
- "定慧桥", "五棵松", "学院桥"};
- public static final String imgSuffix = ".jpg";
- private List list;
- private Form form;
- private Gauge process;
- private Command view = new Command("查看", Command.OK, 1);
- private Command exit = new Command("退出", Command.EXIT, 1);
- public Command back = new Command("菜单", Command.OK, 1);
- public Command backForm = new Command("地图", Command.OK, 1);
- private Command log = new Command("信息", Command.OK, 1);
- private static Main mainInstance;
- public Main() {
- list = new List("选择区域", List.IMPLICIT, locations, null);
- list.addCommand(view);
- list.addCommand(exit);
- list.addCommand(log);
- list.setCommandListener(this);
- form = new Form("");
- form.addCommand(back);
- form.addCommand(log);
- form.setCommandListener(this);
- process = new Gauge("下载中...", false, 100, 1);
- mainInstance = this;
- Display.getDisplay(this).setCurrent(list);
- }
- static Main getInstance() {
- return mainInstance;
- }
- protected void destroyApp(boolean arg0) throws MIDletStateChangeException {
- // TODO Auto-generated method stub
- }
- protected void pauseApp() {
- // TODO Auto-generated method stub
- }
- private void exitApp() {
- try {
- destroyApp(false);
- notifyDestroyed();
- } catch (Exception e) {e.printStackTrace();}
- }
- protected void startApp() throws MIDletStateChangeException {
- // TODO Auto-generated method stub
- }
- public void commandAction(Command cmd, Displayable d) {
- // TODO Auto-generated method stub
- if (cmd == view) {
- int index = list.getSelectedIndex();
- Network net = new Network(index + 1, mainInstance);
- net.start();
- form.setTitle(locations[index]);
- form.deleteAll();
- process.setValue(1);
- form.append(process);
- Display.getDisplay(mainInstance).setCurrent(form);
- }
- if (cmd == exit) {
- exitApp();
- }
- if (cmd == back) {
- Display.getDisplay(mainInstance).setCurrent(list);
- }
- if (cmd == log) {
- Display.getDisplay(mainInstance).setCurrent(Logger.getInstance().getForm());
- }
- if (cmd == backForm) {
- Display.getDisplay(mainInstance).setCurrent(form);
- }
- }
- public void connectProcess(int i, boolean b) {
- // TODO Auto-generated method stub
- if (b) {
- Display.getDisplay(mainInstance).setCurrent(form);
- } else {
- process.setValue(i);
- }
- }
- public void inputImage(Image img) {
- // TODO Auto-generated method stub
- if (img != null) {
- form.deleteAll();
- form.append(img);
- } else {
- System.out.println(" get img is null");
- }
- }
- public void errorInfo(String str) {
- // TODO Auto-generated method stub
- }
- }
Main.java
- import java.io.InputStream;
- import javax.microedition.io.Connector;
- import javax.microedition.io.HttpConnection;
- import javax.microedition.lcdui.Image;
- public class Network/* implements Runnable*/ {
- private int imgIndex;
- private NetworkListener listener;
- private boolean done;
- private HttpConnection hc;
- private HttpConnection urlConn;
- private HttpConnection mobileConn;
- private String urlKey;
- private boolean getKeywordDone;
- private boolean getMobileInfoDone;
- private static final String mainurl = "http://210.73.74.215/realroad/submap.jsp";
- private String parsedURL;
- private static final String commiturl = "http://210.73.74.215/realroad/getimages.jsp?fileName=";
- Logger logger = Logger.getInstance();
- public Network(int index, NetworkListener nk) {
- imgIndex = index;
- listener = nk;
- }
- public void start() {
- Thread getUrl = new Thread(new Runnable(){
- public void run() {
- while (!getMobileInfoDone) {
- }
- logger.put("Thread 1 continue");
- try {
- if (parsedURL == null) {
- urlConn = (HttpConnection) Connector.open(mainurl, Connector.READ_WRITE);
- } else {
- urlConn = (HttpConnection) Connector.open(parsedURL, Connector.READ_WRITE);
- }
- if (urlConn.getResponseCode() == 200) {
- logger.put("200 ok");
- InputStream is = urlConn.openInputStream();
- if (is != null) {
- StringBuffer sb = new StringBuffer();
- String temp = null;
- int ch = 0;
- int times = 0;
- while ((ch = is.read()) != -1) {
- times++;
- sb.append((char)ch);
- temp = sb.toString();
- if (temp.endsWith(".jpg")) {
- logger.put("find key");
- String keyStr = temp.substring(temp.length() - 50, temp.length() - 4);
- int qa = keyStr.lastIndexOf('=');
- urlKey = keyStr.substring(qa + 1, keyStr.length() - 1);
- break;
- }
- }
- }
- }
- } catch (Exception e) {
- logger.put("Thread 1 #! " + e.getMessage());
- e.printStackTrace();
- } finally {
- try {
- logger.put("to close thread 1");
- urlConn.close();
- getKeywordDone = true;
- if (urlKey != null) {
- logger.put("URL Connection colosed! " + urlKey);
- } else {
- logger.put("urlKey is null");
- }
- } catch (Exception e) {
- logger.put("Thread 1 ##! " + e.getMessage());
- e.printStackTrace(); }
- }
- }
- });
- Thread getImage = new Thread(new Runnable(){
- public void run() {
- // TODO Auto-generated method stub
- while (!getKeywordDone) {
- }
- logger.put("Thread 2 continue");
- try {
- logger.put("URL :: " + commiturl + urlKey + imgIndex + Main.imgSuffix);
- hc = (HttpConnection)Connector.open(commiturl + urlKey + imgIndex + Main.imgSuffix, Connector.READ_WRITE);
- int rs = hc.getResponseCode();
- if (rs == 200) {
- logger.put("Thread 2 200 ok");
- Thread download = new Thread(new Runnable(){
- public void run() {
- try {
- InputStream is = hc.openInputStream();
- if (is != null) {
- logger.put("Thread 2 inputstream not null");
- Image img = Image.createImage(is);
- listener.inputImage(img);
- done = true;
- logger.put("Thread 2 image done");
- }
- } catch (Exception e) {
- logger.put("Thread 2 :" + e.getMessage());
- e.printStackTrace();
- }
- }
- });
- download.start();
- int p = 1;
- while (!done) {
- try {
- Thread.sleep(500L);
- listener.connectProcess(p, false);
- } catch (Exception e) { e.printStackTrace(); };
- p++;
- }
- if (done) {
- listener.connectProcess(p, true);
- }
- } else {
- logger.put("response code " + rs);
- }
- } catch (Exception e) {
- logger.put("Thread 2 # :" + e.getMessage());
- e.printStackTrace();
- } finally {
- try {
- hc.close();
- logger.put("Thread 2 closed");
- } catch (Exception e) { e.printStackTrace(); }
- }
- }
- });
- getUrl.start();
- getImage.start();
- }
- }
Network.java
- import javax.microedition.lcdui.Image;
- public interface NetworkListener {
- void connectProcess(int i, boolean b);
- void inputImage(Image img);
- void errorInfo(String str);
- }
NetworkListener.java
以上是每个类的具体代码, 其实我还写了一个Log类, 负责在真机查看调试信息。 在真机上联网时,还是比较有帮助的。
核心的思路就是, 从List上选择一个地名后, 会传入相应的URL, 交给Network去联网。 然后建立连接后, 返回一张图片的数据, 通过OpenInputStream 来创建一副图片。 当连接建立后, NetworkListener接口就该发挥作用了, Network类可以通过这个就接口来传递联网的进度和状态。 也就会反应在界面上了。 等图片被创建后, 这样就可以看到跟网站上的图片一样的效果了。
这里有一点需要解释一下, 大家可以仔细看一下那个网站, 当每2分钟刷新一次的时候, 每幅图片的URL就变化了, 也就是说图片名字是自动生成的。 这个问题我是如何处理的呢? 我打开那个网页的源代码,仔细的研究了一下, 没发现什么好办法。 后来我想了一条比较笨的方法, 也就是当每次查询前, 我首先请求一下那个页面, 它会返回一个标准的HTML格式页面, 里面包含所有的图片的URL, 其实每张图片名字只有最后一位不同。 这样我就想了一个折中的办法, 我把返回的这个HTML页面的字符遍历一遍, 当第一次遇到.jpg结尾的字符后, 我就跳出来, 然后把签名的数字名称解析出来, 留做备用, 这样我通过从界面上传来的List的index, 就可以知道程序想要请求哪幅图, 只要把这串数字后加上这个index, 再加上.jpg的后缀, 前面加上完整的服务器请求地址,就是实际的图片路径了。
以下是在模拟器上的截图:

(主界面)

(下载界面)

(区域地图)
我记得以前郑钧的BLOG上有关于手机查看路况信息的文章, 是视频的。 所以这个相比于流媒体来说没有什么技术含量了。 呵呵。 路况图片上不同颜色表示不同的道路状况, 绿色表示畅通,黄色表示缓慢,红色表示拥堵,灰色则表示暂时无数据。
下面是打包的程序包的下载地址:
http://121.198.86.108/ebooks/trafficinfo.jar
http://121.198.86.108/ebooks/trafficinfo.jad
本程序在Nokia 6120上测试通过, 目前仅支持240 x 320 屏幕的真机。 仅仅是个测试版本, 如果真的想通过这条途径来查看路况, 我觉得还是需要一个代理服务器去中转的, 毕竟不是所有的手机都支持JPG格式的图片。
1万+



被折叠的 条评论
为什么被折叠?



