如何使用 LumaQQ 核心 API

第2部分:处理QQ事件

摘要
在第1部分中,我向你演示了一个最简单的QQ程序,在那个程序里,我使用了Thread.sleep()这样的方式来等待操作的完成,显然这种方式只能拿来做演示,在本部分中,我会更进一步,为你介绍LumaQQ中的事件处理方法,并且会实现一个LumaQQ Applet,于是你在网页里面也可以使用LumaQQ了。

Luma,清华大学
更新时间:2005/03/13

由于QQ的操作需要一定的时间,因为我们不能再继续用Thread.sleep()去傻等了,LumaQQ自身的异步事件机制可以让你获知一个操作何时成功,何时失败,然后再做出相应的处理。通过学习本部分,你基本上就可以用LumaQQ核心API去实现你自己的QQ程序了,你可以在你能想到的情况下使用它们,比如Applet,那么我们今天的Demo就给你奉献一个LumaQQ Applet,以便你加深了解。Demo的代码可以通过CVS获得,其位于edu.tsinghua.lumaqq.demo.demo2包中。

概述

LumaQQ定义了很多QQ的事件常量,它们都包含在QQEvent类中,为了监听QQ事件,你必须实现IQQListener接口,QQClient类有一个addIQQListener()方法,可以让你添加自己的IQQListener。而IQQListener只包含了一个方法qqEvent(),所以你需要使用条件判断来筛选出自己想处理的事件。对于这些概念,实在是相当简单,无需多言,就让我们开始一步步实现一个Applet吧。

第1步:创建Applet子类

关于Applet的概念,如果你不了解,可以先找些资料看看,我不会在此多废话。下面是我们的类声明:
public class Demo2 extends JApplet implements IQQListener {  ...
}
我们继承了JApplet,更重要的是,我们声明自己的Applet会实现IQQListener接口。对于Applet的界面代码,我就不详细列出了,运行起来之后,这个Applet有如下的界面:

图1. Applet界面

为了发送一条消息,你必须提供你的QQ号,你的密码,和消息接收者的QQ号。消息可以在第四个文本框中输入,要发送时,点击Send按钮即可。在最底部,还有一个提示标签,在某个事件发生后,将会设置提示信息,这是为了向你更好的演示事件处理的功能。

第2步:为按钮加上监听器

很显然,我们需要给Send按钮加上一个监听器,如下:
btnSend.addActionListener(new ActionListener() {public void actionPerformed(ActionEvent e) {send();}
});
那么我们看到,按钮按下时,我们调用了send()方法,这个方法的代码如下:
protected void send() {// 得到所有参数int yourQQ = 0;try {yourQQ = Integer.parseInt(textQQ.getText());friendQQ = Integer.parseInt(textFriendQQ.getText());} catch (NumberFormatException e) {lblHint.setText("The format of QQ number is invalid.");return;}        String yourPassword = textPassword.getText();// 开始创建各种对象,登录,然后发送消息,登出,注意我们不再使用sleep来等待操作完成// 创建QQClient和QQUserclient = new QQClient();QQUser user = new QQUser(yourQQ, yourPassword);// 把自己添加成为IQQListenerclient.addIQQListener(this);// 设置参数user.setUdp(true);client.setUser(user);client.setLoginServer("sz.tencent.com");client.setAutoGetFriend(false);try {// 登录lblHint.setText("Logining...");client.login();} catch (Exception e1) {e1.printStackTrace();}
}
send()方法的一开始,我们先把参数得到,这没有什么可说的。得到参数后,我们开始创建各种对象,然后登录,这里和第1部分的Demo有两处不同,首先,我把Applet做为一个IQQListener添加到了QQClient中,其次,send()方法只运行到login()为止,而且没有包含任何Thread.sleep()。很显然,在登录成功之前,我们无法做任何事,所以send()只能到这里为止,由于我们已经注册了IQQListener,现在我们就可以来实现事件处理的代码了。

第3步:实现IQQListener

理所当然的,我们首先想到的就是处理登录成功事件,所以,我们可以这样来实现qqEvent方法:
public void qqEvent(QQEvent e) {switch(e.type) {case QQEvent.QQ_LOGIN_SUCCESS:processLoginSuccess();break;}
}
登录成功事件对应的常量为QQ_LOGIN_SUCCESS,如果你想看看都有哪些事件可以用,可以看看QQEvent的代码,里面的常量名意义都是明显的,我想你应该会明白。QQEvent类有一个type字段说明了事件的类型,我们判断type的值就可以了,这应该是非常的简单明了吧。在这里,我们声明了processLoginSuccess()方法来处理登录成功事件,出于演示的目的,这些事件处理函数都是非常的简单,一般只是设置一下提示信息:
private void processLoginSuccess() {if(!client.getUser().isLoggedIn()) {lblHint.setText("Login successful, wait for status changed...");          }
}
应该很好理解,我判断现在的状态是否是已登录,然后显示一条提示信息,如果登录成功的话,界面就是这样子:

图2. 登录成功后的提示信息

不过你可能会奇怪,为什么没有开始发送消息,而是说等待什么状态改变,这是因为QQ并不是登录了之后就可以发消息,而是要把自己的上线状态设置了之后才能发送消息。所以,我们这里还要等待状态设置完成,这个你不用担心,设置状态是LumaQQ核心层自动完成的,你只需要监听状态完成的事件就可以了。于是我们要加一个事件:
public void qqEvent(QQEvent e) {switch(e.type) {case QQEvent.QQ_LOGIN_SUCCESS:processLoginSuccess();break;case QQEvent.QQ_CHANGE_STATUS_SUCCESS:processChangeStatusSuccess();break;}
}
我们添加了QQ_CHANGE_STATUS_SUCCESS事件,它的处理方法如下:
private void processChangeStatusSuccess() {lblHint.setText("Status changes successful, begin sending message...");client.sendMessage(textMessage.getText(), friendQQ, "宋体");
}
由于在状态设置成功之后我们才能发消息,所以发送消息的代码被放到了这个方法里,很简单吧?我实在是想不出有什么可解释的,这还看不明白就惨了。接下来,我们要在消息发送成功之后登出。所以,我们再加一个事件:
public void qqEvent(QQEvent e) {switch(e.type) {case QQEvent.QQ_LOGIN_SUCCESS:processLoginSuccess();break;case QQEvent.QQ_SEND_IM_SUCCESS:processSendIMSuccess();break;case QQEvent.QQ_CHANGE_STATUS_SUCCESS:processChangeStatusSuccess();break;}
}
processSendIMSuccess()的代码如下:
private void processSendIMSuccess() {lblHint.setText("Message is sent successfully, client now logout.");client.logout();
}
如此,我们在发送成功之后,就退出登录了,于是系统又回到了起点,你可以继续发送其他消息了。

第4步:差错处理

做完了前三步其实也够了,但是你如果要把你的软件拿给别人用,那就还远远不够,差错处理对于产品来说是非常重要的,LumaQQ不仅定义了成功的事件,也照样定义了失败的事件,所以,我们需要加上对登录失败的处理,加上对状态设置失败的处理,加上发送消息失败的处理,尤其是登录失败的处理,其又有很多情况,呵呵,所以,我们最终的qqEvent()方法是这样的:
public void qqEvent(QQEvent e) {switch(e.type) {case QQEvent.QQ_LOGIN_SUCCESS:processLoginSuccess();break;case QQEvent.QQ_LOGIN_PASSWROD_ERROR:processLoginPasswordError();break;case QQEvent.QQ_LOGIN_UNKNOWN_ERROR:processLoginUnknownError();break;case QQEvent.QQ_SEND_IM_SUCCESS:processSendIMSuccess();break;case QQEvent.QQ_CHANGE_STATUS_SUCCESS:processChangeStatusSuccess();break;case QQEvent.QQ_CHANGE_STATUS_FAIL:processChangeStatusFail();break;case QQEvent.QQ_OPERATION_TIMEOUT:if(e.operation == QQ.QQ_CMD_SEND_IM)processSendIMFail();break;}
}
我们又添加了4个事件(黑体部分)来处理错误,当然,我们这里的错误处理都很简单,就是打印一条消息而已:
private void processLoginPasswordError() {lblHint.setText("Password error, login failed!");
}
private void processLoginUnknownError() {lblHint.setText("Unknown error, login failed!");
}
private void processChangeStatusFail() {lblHint.setText("Failed to change status, message can't be sent, client is logout");client.logout();
}
private void processSendIMFail() {lblHint.setText("Failed to send message, client now logout.");client.logout();
}
只是在后面两个方法中,我们还要调用一下logout(),前面两个是处理登录错误的,我们不需要调用logout(),因为那个时候肯定没有登录成功。这些方法都简单易懂,不过对于发送消息失败的处理稍微有点不一样,我们并没有添加什么QQ_SEND_IM_FAIL事件,事实上,这个事件也不存在,我们添加的是QQ_OPERATION_TIMEOUT事件,然后再去判断到底是什么操作超时了。为什么呢? 因为服务器并不会为发送消息返回一个什么应答码来告诉你发送失败了(至少在目前已知的协议中是不会的),所以,消息只有可能发不出去,也就是超时。当然,有些操作即可能超时,也可能是失败,那你就要处理两个情况了。

总结

如此如此,是不是还是很简单呢?当然了,实际的事件数非常之多,我这个Demo才处理了7个而已,如果你真要实现一个很完善的客户端,那确实是非常繁琐的。今天我们就说到这里,如果我想起还有什么要告诉你的,就写第三部分吧。

如何使用 LumaQQ 核心 API相关推荐

  1. hibernate教程--常用配置和核心API详解

    一.Hibernate的常用的配置及核心API. 1.1 Hibernate的常见配置: 1.1.1.核心配置: 核心配置有两种方式进行配置:  1)属性文件的配置: * hibernate.prop ...

  2. hibernate教程--常用配置和核心API

    一.Hibernate的常用的配置及核心API. 1.1Hibernate的常见配置: 1.1.1.核心配置: 核心配置有两种方式进行配置: 1)属性文件的配置: * hibernate.proper ...

  3. hibernate框架学习第二天:核心API、工具类、事务、查询、方言、主键生成策略等...

    核心API Configuration 描述的是一个封装所有配置信息的对象 1.加载hibernate.properties(非主流,早期) Configuration conf = new Conf ...

  4. EXT核心API详解(二)-Array/Date/Function/Number/String

    EXT核心API详解(二)-Array/Date/Function/Number/String Array类 indexOf( Object o )  Number object是否在数组中,找不到返 ...

  5. 核心API最佳实践——JDK日志分级

    核心API最佳实践--JDK日志分级 时间:2005-10-29 08:00 来源:网管之家bitsCN.com 字体:[大 中 小] 日志(Log)是什么?字典对其的解释是"对某种机器工作 ...

  6. Java核心API需要掌握的程度

    Java的核心API是非常庞大的,这给开发者来说带来了很大的方便,经常人有评论,java让程序员变傻. 但是一些内容我认为是必须掌握的,否则不可以熟练运用java,也不会使用就很难办了. 1.java ...

  7. JavaEE基础(02):Servlet核心API用法详解

    本文源码:GitHub·点这里 || GitEE·点这里 一.核心API简介 1.Servlet执行流程 Servlet是JavaWeb的三大组件之一(Servlet.Filter.Listener) ...

  8. Spring Security系列教程11--Spring Security核心API讲解

    前言 经过前面几个章节的学习,一一哥 带大家实现了基于内存和数据库模型的认证与授权,尤其是基于自定义的数据库模型更是可以帮助我们进行灵活开发.但是前面章节的内容,属于让我们达到了 "会用&q ...

  9. Spring Security系列教程-Spring Security核心API讲解

    前言 经过前面几个章节的学习,一一哥 带大家实现了基于内存和数据库模型的认证与授权,尤其是基于自定义的数据库模型更是可以帮助我们进行灵活开发.但是前面章节的内容,属于让我们达到了 "会用&q ...

  10. Activiti6.0 (三)核心API

    核心API RepositoryService: 负责对流程定义文件的管理,操作一些静态文件(流程xml.流程图片),获取部署对象和资源对象 RunTimeService: 对流程进行控制,可用于启动 ...

最新文章

  1. 【数论基础】模运算详解及其应用
  2. Linux内存管理 (26)内存相关工具
  3. 【编译原理】递归下降的预测分析(真の能看懂~!)
  4. zuul过滤器执行生命周期
  5. ipv6转换成ipv4_IPv6协议及其安全浅析
  6. python的pow(-2,3,5)=?
  7. Ubuntu12.04 配置JDK7
  8. Jenkins+CCNET的另类部署图
  9. vim复制,粘贴,删除,撤销,替换,光标移动等用法
  10. 初识STM32之选型
  11. 【小工具】仿站小工具的使用及下载
  12. iPhone 快捷指令 文本朗读
  13. 解决阿里云oss 图片跨域问题
  14. Windows server 2008 r2 基于LLS的Web和FTP服务搭建(基本)
  15. 车载导航蓝牙知识介绍
  16. 数据在云服务器中的安全性不会降低的原因
  17. Kubernetes(k8s)四、Pod生命周期(初始化容器的应用,探针liveness、readliness应用,)
  18. 如何识别手写汉字?跟着步骤就能完成
  19. 英伟达RTX 4070 Ti显卡正式发布!你会买吗?
  20. Golang interface 接口详细原理和使用技巧

热门文章

  1. Windows系统文件浏览标签窗口工具
  2. java 手机号码归属地_Java获取手机号码归属地
  3. houdini 常用
  4. 邮件服务器pop110什么意思,pop pop3区别_25和110端口_imap和pop怎么设置
  5. 【比特率和波特率】bit rate VS baud rate
  6. 分类网络 resnet
  7. 使用MASM 5编译程序的便利批处理
  8. html内容转换中文乱码怎么办,HTML中文乱码怎么解决?
  9. 《影响力》顺从心理学6个使人顺从的策略
  10. Java 搭建srs流媒体服务器,并使用ffmpeg推流