首先安装配置好Openfire服务器,这个不多说,参考基于xmpp openfire smack开发之openfire介绍和部署[1]。创建一个账号rjh,密码123.
首先我们要了解Service的生命周期:Android 中的 Service 全面总结。
核心Service类:
public class Connect2Service extends Service {
LoginConfig loginconfig;
XMPPConnection connection;
NotificationManager nManager;
Notification notification;
private PendingIntent pIntent;
ProgressDialog pd;
private ContacterReceiver receiver = null;
private boolean loginSuccess = false;
public SimpleBinder sBinder;
@Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
sBinder = new SimpleBinder();
}
@Override
public void onDestroy() {
// TODO Auto-generated method stub
if (receiver != null) {
unregisterReceiver(receiver);
}
stopSelf();
super.onDestroy();
}
@Override
public void onLowMemory() {
// TODO Auto-generated method stub
// super.onLowMemory();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// TODO Auto-generated method stub
nManager = (NotificationManager) this
.getSystemService(NOTIFICATION_SERVICE);
initNotification();
loginconfig = new LoginConfig();
loginconfig.setXmppHost("192.168.2.139");
loginconfig.setXmppPort(9090);
loginconfig.setXmppServiceName("www.booway.raojianhui.com");
loginconfig.setUsername("rjh1");
loginconfig.setPassword("123");
loginconfig.setNovisible(false);
/*
* pd = new ProgressDialog(Connect2Service.this); pd.setTitle("请稍等");
* pd.setMessage("正在登录..."); pd.show();
*/
new MyThread().start();
return super.onStartCommand(intent, flags, startId);
}
/**
* 在 Local Service 中我们直接继承 Binder 而不是 IBinder,因为 Binder 实现了 IBinder
* 接口,这样我们可以少做很多工作。
*
* @author newcj
*/
public class SimpleBinder extends Binder {
/**
* 获取 Service 实例
*
* @return
*/
public Connect2Service getService() {
return Connect2Service.this;
}
public int add(int a, int b) {
return a + b;
}
public boolean getLoginResult() {
return loginSuccess;
}
}
@Override
public IBinder onBind(Intent intent) {
// 返回 SimpleBinder 对象
return sBinder;
}
public class MyThread extends Thread {
public void run() {
// while (!Thread.currentThread().isInterrupted()) {
Message msg = new Message();
msg.what = login(loginconfig);
mHandler.sendMessage(msg);
/*
* try { Thread.sleep(1000); } catch (InterruptedException e) {
* e.printStackTrace(); }
*/
// }
}
}
private void initNotification() {
// 显示时间
long when = System.currentTimeMillis();
notification = new Notification();
notification.icon = R.drawable.ic_launcher;// 设置通知的图标
// notification.tickerText = tickerText; // 显示在状态栏中的文字
notification.when = when; // 设置来通知时的时间
// notification.sound =
// Uri.parse("android.resource://com.sun.alex/raw/dida"); // 自定义声音
// notification.flags = Notification.FLAG_NO_CLEAR; //
// 点击清除按钮时就会清除消息通知,但是点击通知栏的通知时不会消失
// notification.flags = Notification.FLAG_ONGOING_EVENT; //
// 点击清除按钮不会清除消息通知,可以用来表示在正在运行
notification.flags |= Notification.FLAG_AUTO_CANCEL; // 点击清除按钮或点击通知后会自动消失
// notification.flags |= Notification.FLAG_INSISTENT; //
// 一直进行,比如音乐一直播放,知道用户响应
notification.defaults = Notification.DEFAULT_SOUND; // 调用系统自带声音
// notification.defaults = Notification.DEFAULT_VIBRATE;// 设置默认震动
// notification.defaults = Notification.DEFAULT_ALL; // 设置铃声震动
// notification.defaults = Notification.DEFAULT_ALL; // 把所有的属性设置成默认
}
Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// pd.dismiss();
switch (msg.what) {
case Constant.LOGIN_SECCESS: // 登录成功
Toast.makeText(Connect2Service.this, "登陆成功", Toast.LENGTH_SHORT)
.show();
// 系统消息连接服务
Intent imSystemMsgService = new Intent(Connect2Service.this,
XMPPService.class);
Connect2Service.this.startService(imSystemMsgService);
// 初始化广播
receiver = new ContacterReceiver();
// 注册广播接收器
IntentFilter filter = new IntentFilter();
// 好友请求
filter.addAction(Constant.ROSTER_SUBSCRIPTION);
filter.addAction(Constant.NEW_MESSAGE_ACTION);
filter.addAction(Constant.ACTION_SYS_MSG);
filter.addAction(Constant.ACTION_RECONNECT_STATE);
registerReceiver(receiver, filter);
break;
case Constant.LOGIN_ERROR_ACCOUNT_PASS:// 账户或者密码错误
Toast.makeText(Connect2Service.this, "账户或者密码错误",
Toast.LENGTH_SHORT).show();
break;
case Constant.SERVER_UNAVAILABLE:// 服务器连接失败
Toast.makeText(Connect2Service.this, "服务器连接失败",
Toast.LENGTH_SHORT).show();
break;
case Constant.LOGIN_ERROR:// 未知异常
Toast.makeText(Connect2Service.this, "未知异常", Toast.LENGTH_SHORT)
.show();
break;
default:
break;
}
super.handleMessage(msg);
}
};
// 登录
private Integer login(LoginConfig loginConfig) {
XmppConnectionManager.getInstance().init(loginConfig);
String username = loginConfig.getUsername();
String password = loginConfig.getPassword();
try {
connection = XmppConnectionManager.getInstance().getConnection();
connection.connect();
connection.login(username, password); // 登录
// OfflineMsgManager.getInstance(activitySupport).dealOfflineMsg(connection);//处理离线消息
connection.sendPacket(new Presence(Presence.Type.available));
if (loginConfig.isNovisible()) {// 隐身登录
Presence presence = new Presence(Presence.Type.unavailable);
Collection<RosterEntry> rosters = connection.getRoster()
.getEntries();
for (RosterEntry rosterEntry : rosters) {
presence.setTo(rosterEntry.getUser());
connection.sendPacket(presence);
}
}
loginConfig.setUsername(username);
loginConfig.setPassword(password);
loginConfig.setOnline(true);
return Constant.LOGIN_SECCESS;
} catch (Exception xee) {
if (xee instanceof XMPPException) {
XMPPException xe = (XMPPException) xee;
final XMPPError error = xe.getXMPPError();
int errorCode = 0;
if (error != null) {
errorCode = error.getCode();
}
if (errorCode == 401) {
return Constant.LOGIN_ERROR_ACCOUNT_PASS;
} else if (errorCode == 403) {
return Constant.LOGIN_ERROR_ACCOUNT_PASS;
} else {
return Constant.SERVER_UNAVAILABLE;
}
} else {
return Constant.LOGIN_ERROR;
}
}
}
private class ContacterReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (Constant.ROSTER_SUBSCRIPTION.equals(action)) {
// adapter.notifyDataSetChanged();
} else if (Constant.NEW_MESSAGE_ACTION.equals(action)) {
// 添加小气泡
// adapter.notifyDataSetChanged();
} else if (Constant.ACTION_RECONNECT_STATE.equals(action)) {
// boolean isSuccess = intent.getBooleanExtra(
// Constant.RECONNECT_STATE, false);
// handReConnect(isSuccess);
} else if (Constant.ACTION_SYS_MSG.equals(action)) {
// adapter.notifyDataSetChanged();
/*
* Notice no = new Notice(); // no =
* intent.getParcelableExtra("notice"); no = (Notice)
* intent.getSerializableExtra("notice"); if(no != null){ //
* tv.setText(no.getContent()); } notification.tickerText =
* no.getContent(); // 单击通知后会跳转到NotificationResult类 intent = new
* Intent(Connect2Service.this, MainActivity.class); //
* 获取PendingIntent,点击时发送该Intent pIntent =
* PendingIntent.getActivity(Connect2Service.this, 0, intent,
* 0); // 设置通知的标题和内容
* notification.setLatestEventInfo(Connect2Service.this, "标题",
* "内容", pIntent); // 发出通知 nManager.notify(0, notification);
*/
}
}
}
}
XMPPService.java:
public class XMPPService extends Service {
private Context context;
PacketCollector myCollector = null;
/* 声明对象变量 */
private NotificationManager myNotiManager;
private PendingIntent pIntent;
SoundPool sp; // 声明SoundPool的引用
HashMap<Integer, Integer> hm; // 声明一个HashMap来存放声音文件
int currStreamId;// 当前正播放的streamId
@Override
public void onCreate() {
context = this;
super.onCreate();
initSysTemMsgManager();
nManager = (NotificationManager) this
.getSystemService(NOTIFICATION_SERVICE);
initNotification();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onDestroy() {
XmppConnectionManager.getInstance().getConnection()
.removePacketListener(pListener);
super.onDestroy();
}
private void initSysTemMsgManager() {
initSoundPool();
XMPPConnection con = XmppConnectionManager.getInstance()
.getConnection();
con.addPacketListener(pListener, new MessageTypeFilter(
Message.Type.normal));
}
// 来消息监听
PacketListener pListener = new PacketListener() {
@Override
public void processPacket(Packet packetz) {
Message message = (Message) packetz;
if (message.getType() == Type.normal) {
// NoticeManager noticeManager = NoticeManager
// .getInstance(context);
Notice notice = new Notice();
// playSound(1, 0); //播放音效
notice.setTitle("系统消息");
notice.setNoticeType(Notice.SYS_MSG);
notice.setFrom(packetz.getFrom());
notice.setContent(message.getBody());
notice.setNoticeTime(DateUtil.date2Str(Calendar.getInstance(),
Constant.MS_FORMART));
notice.setFrom(packetz.getFrom());
notice.setTo(packetz.getTo());
notice.setStatus(Notice.UNREAD);
// long noticeId = noticeManager.saveNotice(notice);
// if (noticeId != -1) {
Intent intent = new Intent();
intent.setAction(Constant.ACTION_SYS_MSG);
// notice.setId(String.valueOf(noticeId));
intent.putExtra("notice", notice);
sendBroadcast(intent);
notification.tickerText = message.getBody();
// 单击通知后会跳转到NotificationResult类
intent = new Intent(XMPPService.this, MainActivity.class);
// 获取PendingIntent,点击时发送该Intent
pIntent = PendingIntent.getActivity(XMPPService.this, 0,
intent, 0);
// 设置通知的标题和内容
notification.setLatestEventInfo(XMPPService.this, "标题",
message.getBody(), pIntent);
// 发出通知
nManager.notify(1, notification);
// }
}
}
};
// 初始化声音池的方法
public void initSoundPool() {
sp = new SoundPool(4, AudioManager.STREAM_MUSIC, 0); // 创建SoundPool对象
hm = new HashMap<Integer, Integer>(); // 创建HashMap对象
// hm.put(1, sp.load(this, R.raw.musictest, 1)); //
// 加载声音文件musictest并且设置为1号声音放入hm中
}
// 播放声音的方法
public void playSound(int sound, int loop) { // 获取AudioManager引用
AudioManager am = (AudioManager) this
.getSystemService(Context.AUDIO_SERVICE);
// 获取当前音量
float streamVolumeCurrent = am
.getStreamVolume(AudioManager.STREAM_MUSIC);
// 获取系统最大音量
float streamVolumeMax = am
.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
// 计算得到播放音量
float volume = streamVolumeCurrent / streamVolumeMax;
// 调用SoundPool的play方法来播放声音文件
currStreamId = sp.play(hm.get(sound), volume, volume, 1, loop, 1.0f);
}
/**
*
* 发出Notification的method.
*
* @param iconId
* 图标
* @param contentTitle
* 标题
* @param contentText
* 你内容
* @param activity
* @author shimiso
* @update 2012-5-14 下午12:01:55
*/
private void setNotiType(int iconId, String contentTitle,
String contentText, Class activity) {
/*
* 创建新的Intent,作为点击Notification留言条时, 会运行的Activity
*/
Intent notifyIntent = new Intent(this, activity);
notifyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
/* 创建PendingIntent作为设置递延运行的Activity */
PendingIntent appIntent = PendingIntent.getActivity(this, 0,
notifyIntent, 0);
/* 创建Notication,并设置相关参数 */
Notification myNoti = new Notification();
/* 设置statusbar显示的icon */
myNoti.icon = iconId;
/* 设置statusbar显示的文字信息 */
myNoti.tickerText = contentTitle;
/* 设置notification发生时同时发出默认声音 */
myNoti.defaults = Notification.DEFAULT_SOUND;
/* 设置Notification留言条的参数 */
myNoti.setLatestEventInfo(this, contentTitle, contentText, appIntent);
/* 送出Notification */
myNotiManager.notify(0, myNoti);
}
NotificationManager nManager;
Notification notification;
private void initNotification() {
// 显示时间
long when = System.currentTimeMillis();
notification = new Notification();
notification.icon = R.drawable.ic_launcher;// 设置通知的图标
// notification.tickerText = tickerText; // 显示在状态栏中的文字
notification.when = when; // 设置来通知时的时间
// notification.sound =
// Uri.parse("android.resource://com.sun.alex/raw/dida"); // 自定义声音
// notification.flags = Notification.FLAG_NO_CLEAR; //
// 点击清除按钮时就会清除消息通知,但是点击通知栏的通知时不会消失
// notification.flags = Notification.FLAG_ONGOING_EVENT; //
// 点击清除按钮不会清除消息通知,可以用来表示在正在运行
notification.flags |= Notification.FLAG_AUTO_CANCEL; // 点击清除按钮或点击通知后会自动消失
// notification.flags |= Notification.FLAG_INSISTENT; //
// 一直进行,比如音乐一直播放,知道用户响应
notification.defaults = Notification.DEFAULT_SOUND; // 调用系统自带声音
// notification.defaults = Notification.DEFAULT_VIBRATE;// 设置默认震动
// notification.defaults = Notification.DEFAULT_ALL; // 设置铃声震动
// notification.defaults = Notification.DEFAULT_ALL; // 把所有的属性设置成默认
}
}
Demo下载地址:http://download.csdn.net/detail/u013800519/8695921