最近很多同学在做基于oenfire服务器,asmack开源框架的即时通讯应用,当中,多多少少碰到了一些问题。在解决问题的过程中,我发现很多同学的做法是错误的,所以我决定写下一篇博客告知正在为这些问题烦恼的同学。
首先,奉献一个Log类,大家以后不用在烦恼每次都要去写TAG了,这个类用到了单例模式的饿汉式,有心的同学可以改成完美式:
public class LogUtil {
private final static String tag = "[你想取啥名,就取啥名]";
public static int logLevel = Log.VERBOSE;
//public static int logLevel = Log.ERROR;
//private static boolean logFlag = true;
private static LogUtil logger = new LogUtil();;
public static LogUtil getLogger() {
return logger;
}
private LogUtil() {
}
private String getFunctionName() {
StackTraceElement[] sts = Thread.currentThread().getStackTrace();
if (sts == null) {
return null;
}
for (StackTraceElement st : sts) {
if (st.isNativeMethod()) {
continue;
}
if (st.getClassName().equals(Thread.class.getName())) {
continue;
}
if (st.getClassName().equals(this.getClass().getName())) {
continue;
}
return "[ " + Thread.currentThread().getName() + ": "
+ st.getFileName() + ":" + st.getLineNumber() + " ]";
}
return null;
}
public void i(Object str) {
if (!AppConfig.DEBUG)
return;
if (logLevel <= Log.INFO) {
String name = getFunctionName();
if (name != null) {
Log.i(tag, name + " - " + str);
} else {
Log.i(tag, str.toString());
}
}
}
public void v(Object str) {
if (!AppConfig.DEBUG)
return;
if (logLevel <= Log.VERBOSE) {
String name = getFunctionName();
if (name != null) {
Log.v(tag, name + " - " + str);
} else {
Log.v(tag, str.toString());
}
}
}
public void w(Object str) {
if (!AppConfig.DEBUG)
return;
if (logLevel <= Log.WARN) {
String name = getFunctionName();
if (name != null) {
Log.w(tag, name + " - " + str);
} else {
Log.w(tag, str.toString());
}
}
}
public void e(Object str) {
if (!AppConfig.DEBUG)
return;
if (logLevel <= Log.ERROR) {
String name = getFunctionName();
if (name != null) {
Log.e(tag, name + " - " + str);
} else {
Log.e(tag, str.toString());
}
}
}
public void e(Exception ex) {
if (!AppConfig.DEBUG)
return;
if (logLevel <= Log.ERROR) {
Log.e(tag, "error", ex);
}
}
public void d(Object str) {
if (!AppConfig.DEBUG)
return;
if (logLevel <= Log.DEBUG) {
String name = getFunctionName();
if (name != null) {
Log.d(tag, name + " - " + str);
} else {
Log.d(tag, str.toString());
}
}
}
}
接着我们需要一个单例类来管理XMPPConnection,这次用的好像是懒汉式,为什么会使用单例呢,原因是你不想你的应用中出现多个XMPPConnection对象吧,当中出现红色X的时候可能是因为转义的问题,那个X代表的是(":"+ x + ":")
public class XmppConnManager {
public static int SERVER_PORT = 5222;//服务端口 可以在openfire上设置
public static String SERVER_HOST = "42.121.17.115";//你openfire服务器所在的ip
public static String SERVER_NAME = "helloworld";//设置openfire时的服务器名
private static XMPPConnection connection = null;
private static XmppConnManager connManager = null;
public static XmppConnManager getInstance(){
if(connManager == null){
connManager = new XmppConnManager();
}
return connManager;
}
private void openConnection() {
try {
if (null == connection || !connection.isAuthenticated()) {
XMPPConnection.DEBUG_ENABLED = true;//开启DEBUG模式
//配置连接
/* ConnectionConfiguration config = new ConnectionConfiguration(
SERVER_HOST, SERVER_PORT,
SERVER_NAME);*/
ConnectionConfiguration config = new ConnectionConfiguration(
SERVER_HOST, SERVER_PORT);
config.setReconnectionAllowed(true);
config.setSendPresence(false);
/* config.setSASLAuthenticationEnabled(false);
config.setSecurityMode(SecurityMode.disabled);
config.setCompressionEnabled(false);*/
connection = new XMPPConnection(config);
connection.connect();//连接到服务器
//配置各种Provider
configureConnection(ProviderManager.getInstance());
}
} catch (XMPPException xe) {
xe.printStackTrace();
}
}
/**
* 创建连接
*/
public XMPPConnection getConnection() {
if (connection == null) {
openConnection();
}
return connection;
}
/**
* 关闭连接
*/
public void closeConnection() {
if(connection!=null){
connection.disconnect();
connection = null;
LogUtil.getLogger().e("執行closeConnection操作");
}
}
/**
* xmpp配置
*/
private void configureConnection(ProviderManager pm) {
// Private Data Storage
pm.addIQProvider("query", "jabber:iq:private",new PrivateDataManager.PrivateDataIQProvider());
// Time
try {
pm.addIQProvider("query", "jabber:iq:time",Class.forName("org.jivesoftware.smackx.packet.Time"));
} catch (Exception e) {
e.printStackTrace();
}
// Roster Exchange
pm.addExtensionProvider("x", "jabberroster",new RosterExchangeProvider());
// Message Events
pm.addExtensionProvider("x", "jabberevent",new MessageEventProvider());
// Chat State
pm.addExtensionProvider("active","http://jabber.org/protocol/chatstates",new ChatStateExtension.Provider());
pm.addExtensionProvider("composing","http://jabber.org/protocol/chatstates",new ChatStateExtension.Provider());
pm.addExtensionProvider("paused","http://jabber.org/protocol/chatstates",new ChatStateExtension.Provider());
pm.addExtensionProvider("inactive","http://jabber.org/protocol/chatstates",new ChatStateExtension.Provider());
pm.addExtensionProvider("gone","http://jabber.org/protocol/chatstates",new ChatStateExtension.Provider());
// XHTML
pm.addExtensionProvider("html", "http://jabber.org/protocol/xhtml-im",new XHTMLExtensionProvider());
// Group Chat Invitations
pm.addExtensionProvider("x", "jabberconference",new GroupChatInvitation.Provider());
// Service Discovery # Items //解析房间列表
pm.addIQProvider("query", "http://jabber.org/protocol/disco#items",new DiscoverItemsProvider());
// Service Discovery # Info //某一个房间的信息
pm.addIQProvider("query", "http://jabber.org/protocol/disco#info",new DiscoverInfoProvider());
// Data Forms
pm.addExtensionProvider("x", "jabberdata", new DataFormProvider());
// MUC User
pm.addExtensionProvider("x", "http://jabber.org/protocol/muc#user",new MUCUserProvider());
// MUC Admin
pm.addIQProvider("query", "http://jabber.org/protocol/muc#admin",new MUCAdminProvider());
// MUC Owner
pm.addIQProvider("query", "http://jabber.org/protocol/muc#owner",new MUCOwnerProvider());
// Delayed Delivery
pm.addExtensionProvider("x", "jabberdelay",new DelayInformationProvider());
// Version
try {
pm.addIQProvider("query", "jabber:iq:version",Class.forName("org.jivesoftware.smackx.packet.Version"));
} catch (ClassNotFoundException e) {
// Not sure what's happening here.
}
// VCard
pm.addIQProvider("vCard", "vcard-temp", new VCardProvider());
// Offline Message Requests
pm.addIQProvider("offline", "http://jabber.org/protocol/offline",new OfflineMessageRequest.Provider());
// Offline Message Indicator
pm.addExtensionProvider("offline","http://jabber.org/protocol/offline",new OfflineMessageInfo.Provider());
// Last Activity
pm.addIQProvider("query", "jabber:iq:last", new LastActivity.Provider());
// User Search
pm.addIQProvider("query", "jabber:iq:search", new UserSearch.Provider());
// SharedGroupsInfo
pm.addIQProvider("sharedgroup","http://www.jivesoftware.org/protocol/sharedgroup",new SharedGroupsInfo.Provider());
// JEP-33: Extended Stanza Addressing
pm.addExtensionProvider("addresses","http://jabber.org/protocol/address",new MultipleAddressesProvider());
pm.addIQProvider("si", "http://jabber.org/protocol/si",new StreamInitiationProvider());
pm.addIQProvider("query", "jabber:iq:privacy", new PrivacyProvider());
pm.addIQProvider("command", "http://jabber.org/protocol/commands",new AdHocCommandDataProvider());
pm.addExtensionProvider("malformed-action","http://jabber.org/protocol/commands",new AdHocCommandDataProvider.MalformedActionError());
pm.addExtensionProvider("bad-locale","http://jabber.org/protocol/commands",new AdHocCommandDataProvider.BadLocaleError());
pm.addExtensionProvider("bad-payload","http://jabber.org/protocol/commands",new AdHocCommandDataProvider.BadPayloadError());
pm.addExtensionProvider("bad-sessionid","http://jabber.org/protocol/commands",new AdHocCommandDataProvider.BadSessionIDError());
pm.addExtensionProvider("session-expired","http://jabber.org/protocol/commands",new AdHocCommandDataProvider.SessionExpiredError());
}
}
接下来要写一个服务类来监听XMPPConnecttion:
public class MessageService extends Service {
private LogUtil log = LogUtil.getLogger();
private ChatManager cm;
private OfflineMessageManager offlineManager;
public static XMPPConnection con = null;
static{
try{
Class.forName("org.jivesoftware.smack.ReconnectionManager");
}catch(Exception e){
e.printStackTrace();
}
}
@Override
public IBinder onBind(Intent arg0) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
}
@SuppressWarnings("deprecation")
@Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
new Thread(new Runnable() {
@Override
public void run() {
if(NetWorkUtil.netState(MessageService.this)!=false) {
con = XmppConnManager.getInstance().getConnection();
con.addConnectionListener(new ConnectionListener(){
@Override
public void connectionClosed() {
log.e("来自连接监听,conn正常关闭");
}
@Override
public void connectionClosedOnError(Exception arg0) {
//这里就是网络不正常或者被挤掉断线激发的事件
if(arg0.getMessage().contains("conflict")){ //被挤掉线
/* log.e("来自连接监听,conn非正常关闭");
log.e("非正常关闭异常:"+arg0.getMessage());
log.e(con.isConnected());*/
//关闭连接,由于是被人挤下线,可能是用户自己,所以关闭连接,让用户重新登录是一个比较好的选择
XmppConnManager.getInstance().closeConnection();
//接下来你可以通过发送一个广播,提示用户被挤下线,重连很简单,就是重新登录
}else if(arg0.getMessage().contains("Connection timed out")){//连接超时
// 不做任何操作,会实现自动重连
}
}
@Override
public void reconnectingIn(int arg0) {
//重新连接的动作正在进行的动作,里面的参数arg0是一个倒计时的数字,如果连接失败的次数增多,数字会越来越大,开始的时候是9
log.e("来自连接监听,conn重连中..."+arg0);
}
@Override
public void reconnectionFailed(Exception arg0) {
//重新连接失败
log.e("来自连接监听,conn失败:"+arg0.getMessage());
}
@Override
public void reconnectionSuccessful() {
//当网络断线了,重新连接上服务器触发的事件
log.e("来自连接监听,conn重连成功");
}
});
}).start();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// TODO Auto-generated method stub
return super.onStartCommand(intent, flags, startId);
}
}
声明:eoe文章著作权属于作者,受法律保护,转载时请务必以超链接形式附带如下信息
原文作者: 我是燃烧的彗星
原文地址: http://my.eoe.cn/699035/archive/4818.html
-------转载者有话说:无线测试中的网络切换是个很坑爹的事情