客户端代码分析
DemoAppActivity
程序以DemoAppActivity启动,在DemoAppActivity的onCreate时,创建一个ServiceManager对象,并将自身作为Context传递给ServiceManager对象,之后调用ServiceManager对象的startService,代码如下:
// Start the service
ServiceManager serviceManager = new ServiceManager(this);
serviceManager.setNotificationIcon(R.drawable.notification);
serviceManager.startService();
ServiceManager
ServiceManager是一个简单的类,主要功能就是从文件读取配置参数,将配置参数导入SharedPreferences,启动和停止NotificationService服务。
ServiceManager的构造函数中进行读取参数和导入参数的操作。
ServiceManager:: startService启动NotificationService服务:public void startService() {
Thread serviceThread = new Thread(new Runnable() {
@Override
public void run() {
Intent intent = NotificationService.getIntent();
context.startService(intent);//context就是DemoAppActivity对象
}
});
serviceThread.start();
}
ServiceManager:: stopService停止NotificationService服务:
public void stopService() {
Intent intent = NotificationService.getIntent();
context.stopService(intent);
}
NotificationService
对象构造时创建四个对象:NotificationReceiver、ConnectivityReceiver、PhoneStateChangeListener、ExecutorService(单线程线程池对象)、TaskSubmitter和TaskTracker。
TaskSubmitter对象负责将从Runnable继承的线程任务提交给ExecutorService对象。
NotificationService:: onCreate创建一个XmppManager对象,然后通过TaskSubmitter对象提交一个线程任务: taskSubmitter.submit(new Runnable() {
public void run() {
NotificationService.this.start();
}
});
NotificationService::
onDestroy调用stop函数:
@Override
public void onDestroy() {
Log.d(LOGTAG, "onDestroy()...");
stop();
}
NotificationService::
start中注册广播接收器NotificationReceiver对象和ConnectivityReceiver对象,然后调用XmppManager对象的connect函数。
private void start() {
Log.d(LOGTAG, "start()...");
registerNotificationReceiver();
registerConnectivityReceiver();
// Intent intent = getIntent();
// startService(intent);
xmppManager.connect();
}
NotificationReceiver
对象接收以下类型广播:
filter.addAction(Constants.ACTION_SHOW_NOTIFICATION);
ConnectivityReceiver
对象接收以下类型广播:
filter.addAction(android.net.ConnectivityManager.CONNECTIVITY_ACTION);
NotificationService ::
registerConnectivityReceiver函数中开始监听手机状态变化:
telephonyManager.listen(phoneStateListener,
PhoneStateListener.LISTEN_DATA_CONNECTION_STATE);
NotificationService::
stop中注销广播接收器NotificationReceiver对象和ConnectivityReceiver对象,然后调用XmppManager对象的disconnect函数,最后停止ExecutorService单线程线程池对象。
private void stop() {
Log.d(LOGTAG, "stop()...");
unregisterNotificationReceiver();
unregisterConnectivityReceiver();
xmppManager.disconnect();
executorService.shutdown();
}
NotificationService::
connect函数通过TaskSubmitter对象提交一个调用XmppManager对象的connect函数的线程任务。
NotificationService:: disconnect函数通过TaskSubmitter对象提交一个调用XmppManager对象的disconnect函数的线程任务。
PhoneStateChangeListener
PhoneStateChangeListener对象监听手机的状态改变广播,它收到DATA_CONNECTED广播后调用NotificationService对象的connect函数。
TaskSubmitter
TaskSubmitter对象负责将从Runnable继承的线程任务提交给ExecutorService对象:
@SuppressWarnings("unchecked")
public Future submit(Runnable task) {
Future result = null;
if (!notificationService.getExecutorService().isTerminated()
&& !notificationService.getExecutorService().isShutdown()
&& task != null) {
result = notificationService.getExecutorService().submit(task);
}
return result;
}
TaskTracker
TaskTracker对象负责为NotificationService对象的待运行的线程任务计数。
ConnectivityReceiver
ConnectivityReceiver在收到android.net.ConnectivityManager.CONNECTIVITY_ACTION广播后,判断网络是否连接,连接了则调用NotificationService对象的connect函数,否则调用NotificationService对象的disconnect函数。
NotificationReceiver
NotificationReceiver对象收到Constants.ACTION_SHOW_NOTIFICATION广播后,从Intent参数中解析出参数,创建一个Notifier对象,并调用其notify函数:
if (Constants.ACTION_SHOW_NOTIFICATION.equals(action)) {
String notificationId = intent
.getStringExtra(Constants.NOTIFICATION_ID);
String notificationApiKey = intent
.getStringExtra(Constants.NOTIFICATION_API_KEY);
String notificationTitle = intent
.getStringExtra(Constants.NOTIFICATION_TITLE);
String notificationMessage = intent
.getStringExtra(Constants.NOTIFICATION_MESSAGE);
String notificationUri = intent
.getStringExtra(Constants.NOTIFICATION_URI);
Log.d(LOGTAG, "notificationId=" + notificationId);
Log.d(LOGTAG, "notificationApiKey=" + notificationApiKey);
Log.d(LOGTAG, "notificationTitle=" + notificationTitle);
Log.d(LOGTAG, "notificationMessage=" + notificationMessage);
Log.d(LOGTAG, "notificationUri=" + notificationUri);
Notifier notifier = new Notifier(context);
notifier.notify(notificationId, notificationApiKey,
notificationTitle, notificationMessage, notificationUri);
}
Notifier
Notifier对象负责通知状态栏显示收到的消息。
XmppManager
XmppManager在构造函数中创建PersistentConnectionListenerxmpp连接监视对象和NotificationPacketListener返回包监视对象。
App启动即调用XmppManager对象的connect函数。该函数依次启动三个线程任务:ConnectTask、RegisterTask、LoginTask,之后便进入接收消息的状态。
XmppManager对象使用org.jivesoftware.smack.XMPPConnection对象和xmpp服务器保持连接。
ConnectTask用于连接服务器,连接成功后,org.jivesoftware.smack.XMPPConnection对象的isConnected方法返回true。
RegisterTask用于发送包含用户名和密码的注册包给服务器,在服务器注册一个用户。
ConnectTask
1)用服务器IP和端口创建org.jivesoftware.smack.ConnectionConfiguration连接配置对象:
ConnectionConfiguration connConfig = new ConnectionConfiguration(
xmppHost, xmppPort);
// connConfig.setSecurityMode(SecurityMode.disabled);
connConfig.setSecurityMode(SecurityMode.required);
connConfig.setSASLAuthenticationEnabled(false);
connConfig.setCompressionEnabled(false);
2)用连接配置对象创建org.jivesoftware.smack.XMPPConnection对象:
XMPPConnection connection = new XMPPConnection(connConfig);
xmppManager.setConnection(connection);
3)
连接服务器:
connection.connect();
Log.i(LOGTAG, "XMPP connected successfully");
// packet provider
ProviderManager.getInstance().addIQProvider("notification",
"androidpn:iq:notification",
new NotificationIQProvider());
RegisterTask
1)创建一个Registration注册包对象:
Registration registration = new Registration();
2)创建一个PacketFilter对象:
PacketFilter packetFilter = new AndFilter(new PacketIDFilter(
registration.getPacketID()), new PacketTypeFilter(
IQ.class));
3)创建一个PacketListener返回包监听对象:
PacketListener packetListener = new PacketListener() {
public void processPacket(Packet packet) {
Log.d("RegisterTask.PacketListener",
"processPacket().....");
Log.d("RegisterTask.PacketListener", "packet="
+ packet.toXML());
if (packet instanceof IQ) {
IQ response = (IQ) packet;
if (response.getType() == IQ.Type.ERROR) {
if (!response.getError().toString().contains(
"409")) {
Log.e(LOGTAG,
"Unknown error while registering XMPP account! "
+ response.getError()
.getCondition());
}
} else if (response.getType() == IQ.Type.RESULT) {
xmppManager.setUsername(newUsername);
xmppManager.setPassword(newPassword);
Log.d(LOGTAG, "username=" + newUsername);
Log.d(LOGTAG, "password=" + newPassword);
Editor editor = sharedPrefs.edit();
editor.putString(Constants.XMPP_USERNAME,
newUsername);
editor.putString(Constants.XMPP_PASSWORD,
newPassword);
editor.commit();
Log
.i(LOGTAG,
"Account registered successfully");
xmppManager.runTask();
}
}
}
};
4)
将监听对象设置到
org.jivesoftware.smack.XMPPConnection
连接对象中:
connection.addPacketListener(packetListener, packetFilter);
5)
将用户名和密码设置到
Registration
注册包对象中:
Registration.setType(IQ.Type.SET);
// registration.setTo(xmppHost);
// Map<String, String> attributes = new HashMap<String, String>();
// attributes.put("username", rUsername);
// attributes.put("password", rPassword);
// registration.setAttributes(attributes);
registration.addAttribute("username", newUsername);
registration.addAttribute("password", newPassword);
6)
发送注册包:
connection.sendPacket(registration);
LoginTask
1)调用org.jivesoftware.smack.XMPPConnection对象的login函数登陆服务器:
xmppManager.getConnection().login(
xmppManager.getUsername(),
xmppManager.getPassword(), XMPP_RESOURCE_NAME);
2)将xmpp连接监听对象设置到org.jivesoftware.smack.XMPPConnection对象:
if (xmppManager.getConnectionListener() != null) {
xmppManager.getConnection().addConnectionListener(
xmppManager.getConnectionListener());
}
3)
将返回包监听对象设置到
org.jivesoftware.smack.XMPPConnection
对象:
// packet filter
PacketFilter packetFilter = new PacketTypeFilter(
NotificationIQ.class);
// packet listener
PacketListener packetListener = xmppManager
.getNotificationPacketListener();
connection.addPacketListener(packetListener, packetFilter);
4)如果login产生异常,则重新运行RegisterTask和LoginTask来重新在服务器注册用户名和登陆服务器获取授权。
PersistentConnectionListener
PersistentConnectionListener类从org.jivesoftware.smack.ConnectionListener继承而来,几个主要重载函数:connectionClosed、connectionClosedOnError、reconnectingIn、reconnectionFailed、reconnectionSuccessful。
Androidpn只重载了connectionClosedOnError:
@Override
public void connectionClosedOnError(Exception e) {
Log.d(LOGTAG, "connectionClosedOnError()...");
if (xmppManager.getConnection() != null
&& xmppManager.getConnection().isConnected()) {
xmppManager.getConnection().disconnect();
}
xmppManager.startReconnectionThread();
}
NotificationPacketListener
NotificationPacketListener从org.jivesoftware.smack.PacketListener继承而来,主要实现processPacket函数用于处理xmpp返回包:
@Override
public void processPacket(Packet packet) {
Log.d(LOGTAG, "NotificationPacketListener.processPacket()...");
Log.d(LOGTAG, "packet.toXML()=" + packet.toXML());
if (packet instanceof NotificationIQ) {
NotificationIQ notification = (NotificationIQ) packet;
if (notification.getChildElementXML().contains(
"androidpn:iq:notification")) {
String notificationId = notification.getId();
String notificationApiKey = notification.getApiKey();
String notificationTitle = notification.getTitle();
String notificationMessage = notification.getMessage();
// String notificationTicker = notification.getTicker();
String notificationUri = notification.getUri();
Intent intent = new Intent(Constants.ACTION_SHOW_NOTIFICATION);
intent.putExtra(Constants.NOTIFICATION_ID, notificationId);
intent.putExtra(Constants.NOTIFICATION_API_KEY,
notificationApiKey);
intent
.putExtra(Constants.NOTIFICATION_TITLE,
notificationTitle);
intent.putExtra(Constants.NOTIFICATION_MESSAGE,
notificationMessage);
intent.putExtra(Constants.NOTIFICATION_URI, notificationUri);
// intent.setData(Uri.parse((new StringBuilder(
// "notif://notification.androidpn.org/")).append(
// notificationApiKey).append("/").append(
// System.currentTimeMillis()).toString()));
xmppManager.getContext().sendBroadcast(intent);
}
}
}