天天看点

基于xmpp openfire smack开发之Android客户端开发[3]

在上两篇文章中,我们依次介绍openfire部署以及smack常用api的使用,这一节中我们着力介绍如何基于asmack开发一个android的客户端,本篇的重点在实践,讲解和原理环节,大家可以参考前两篇的文章

基于xmpp openfire smack开发之openfire介绍和部署[1]

基于xmpp openfire smack开发之smack类库介绍和使用[2]

基于xmpp openfire smack开发之Android客户端开发[3]

activity包下存放一些android页面交互相关的控制程序,还有一个些公共帮助类

db包为sqlite的工具类封装,这里做了一些自定义的改造,稍微仿spring的jdbctemplate结构,使用起来更加方便一点

manager包留下主要是一些管理组件,包括联系人管理,消息管理,提醒管理,离线消息管理,用户管理,xmpp连接管理

model包中都是一些对象模型,传输介质

service中存放一些android后台的核心服务,主要包括聊天服务,联系人服务,系统消息服务,重连接服务

task包中存放一些耗时的异步操作

util中存放一些常用的工具类

view中一些和android的ui相关的显示控件

基于xmpp openfire smack开发之Android客户端开发[3]

anim中存放一些动画元素的配置

layout是布局页面

menu是地步菜单布局页面

values中存放一些字符,颜色,样式,参数的配置信息

其中strings.xml中,保存的缺省配置为gtalk的服务器信息,大家如果有谷歌gtalk的账号可以直接登录,否则需要更改这里的配置才可以使用其他的xmpp服务器

[html] view

plaincopy

<!-- 缺省的服务器配置 -->   

  <integer name="xmpp_port">5222</integer>   

  <string name="xmpp_host">talk.google.com</string>   

  <string name="xmpp_service_name">gmail.com</string>  

  <bool name="is_remember">true</bool>  

  <bool name="is_autologin">false</bool>  

  <bool name="is_novisible">false</bool>   

androidmanifest.xml为android功能清单的配置文件,我们这里开放的权限并不多

    <!-- 访问internet -->  

<uses-permission android:name="android.permission.internet" />  

<!--- 访问网络状态 -->  

    <uses-permission android:name="android.permission.access_network_state" />  

    <!-- 往sdcard写入数据权限 -->  

    <uses-permission android:name="android.permission.write_external_storage"/>  

   <span style="white-space: pre">  </span><!-- 在sdcard中创建与删除文件权限 -->  

   <span style="white-space: pre">  </span><uses-permission android:name="android.permission.mount_unmount_filesystems"/>  

   <span style="white-space: pre">  </span><!-- 往sdcard写入数据权限 -->  

   <span style="white-space: pre">  </span><uses-permission android:name="android.permission.write_external_storage"/>  

1.activitysupport类

[java] view

package csdn.shimiso.eim.activity;  

import android.app.activity;  

import android.app.alertdialog;  

import android.app.notification;  

import android.app.notificationmanager;  

import android.app.pendingintent;  

import android.app.progressdialog;  

import android.content.context;  

import android.content.dialoginterface;  

import android.content.intent;  

import android.content.sharedpreferences;  

import android.location.locationmanager;  

import android.net.connectivitymanager;  

import android.net.networkinfo;  

import android.os.bundle;  

import android.os.environment;  

import android.provider.settings;  

import android.view.inputmethod.inputmethodmanager;  

import android.widget.toast;  

import csdn.shimiso.eim.r;  

import csdn.shimiso.eim.comm.constant;  

import csdn.shimiso.eim.model.loginconfig;  

import csdn.shimiso.eim.service.imchatservice;  

import csdn.shimiso.eim.service.imcontactservice;  

import csdn.shimiso.eim.service.imsystemmsgservice;  

import csdn.shimiso.eim.service.reconnectservice;  

/** 

 * actity 工具支持类 

 *  

 * @author shimiso 

 */  

public class activitysupport extends activity implements iactivitysupport {  

    protected context context = null;  

    protected sharedpreferences preferences;  

    protected eimapplication eimapplication;  

    protected progressdialog pg = null;  

    protected notificationmanager notificationmanager;  

    @override  

    protected void oncreate(bundle savedinstancestate) {  

        super.oncreate(savedinstancestate);  

        context = this;  

        preferences = getsharedpreferences(constant.login_set, 0);  

        notificationmanager = (notificationmanager) getsystemservice(notification_service);  

        pg = new progressdialog(context);  

        eimapplication = (eimapplication) getapplication();  

        eimapplication.addactivity(this);  

    }  

    protected void onstart() {  

        super.onstart();  

    protected void onresume() {  

        super.onresume();  

    protected void onpause() {  

        super.onpause();  

    protected void onstop() {  

        super.onstop();  

    public void ondestroy() {  

        super.ondestroy();  

    public progressdialog getprogressdialog() {  

        return pg;  

    public void startservice() {  

        // 好友联系人服务  

        intent server = new intent(context, imcontactservice.class);  

        context.startservice(server);  

        // 聊天服务  

        intent chatserver = new intent(context, imchatservice.class);  

        context.startservice(chatserver);  

        // 自动恢复连接服务  

        intent reconnectservice = new intent(context, reconnectservice.class);  

        context.startservice(reconnectservice);  

        // 系统消息连接服务  

        intent imsystemmsgservice = new intent(context,  

                imsystemmsgservice.class);  

        context.startservice(imsystemmsgservice);  

    /** 

     *  

     * 销毁服务. 

     * @author shimiso 

     * @update 2012-5-16 下午12:16:08 

     */  

    public void stopservice() {  

        context.stopservice(server);  

        context.stopservice(chatserver);  

        context.stopservice(reconnectservice);  

        context.stopservice(imsystemmsgservice);  

    public void isexit() {  

        new alertdialog.builder(context).settitle("确定退出吗?")  

                .setneutralbutton("确定", new dialoginterface.onclicklistener() {  

                    @override  

                    public void onclick(dialoginterface dialog, int which) {  

                        stopservice();  

                        eimapplication.exit();  

                    }  

                })  

                .setnegativebutton("取消", new dialoginterface.onclicklistener() {  

                        dialog.cancel();  

                }).show();  

    public boolean hasinternetconnected() {  

        connectivitymanager manager = (connectivitymanager) context  

                .getsystemservice(context.connectivity_service);  

        if (manager != null) {  

            networkinfo network = manager.getactivenetworkinfo();  

            if (network != null && network.isconnectedorconnecting()) {  

                return true;  

            }  

        }  

        return false;  

    public boolean validateinternet() {  

        if (manager == null) {  

            openwirelessset();  

            return false;  

        } else {  

            networkinfo[] info = manager.getallnetworkinfo();  

            if (info != null) {  

                for (int i = 0; i < info.length; i++) {  

                    if (info[i].getstate() == networkinfo.state.connected) {  

                        return true;  

                }  

        openwirelessset();  

    public boolean haslocationgps() {  

        locationmanager manager = (locationmanager) context  

                .getsystemservice(context.location_service);  

        if (manager  

                .isproviderenabled(android.location.locationmanager.gps_provider)) {  

            return true;  

    public boolean haslocationnetwork() {  

                .isproviderenabled(android.location.locationmanager.network_provider)) {  

    public void checkmemorycard() {  

        if (!environment.media_mounted.equals(environment  

                .getexternalstoragestate())) {  

            new alertdialog.builder(context)  

                    .settitle(r.string.prompt)  

                    .setmessage("请检查内存卡")  

                    .setpositivebutton(r.string.menu_settings,  

                            new dialoginterface.onclicklistener() {  

                                @override  

                                public void onclick(dialoginterface dialog,  

                                        int which) {  

                                    dialog.cancel();  

                                    intent intent = new intent(  

                                            settings.action_settings);  

                                    context.startactivity(intent);  

                                }  

                            })  

                    .setnegativebutton("退出",  

                                    eimapplication.exit();  

                            }).create().show();  

    public void openwirelessset() {  

        alertdialog.builder dialogbuilder = new alertdialog.builder(context);  

        dialogbuilder  

                .settitle(r.string.prompt)  

                .setmessage(context.getstring(r.string.check_connection))  

                .setpositivebutton(r.string.menu_settings,  

                        new dialoginterface.onclicklistener() {  

                            @override  

                            public void onclick(dialoginterface dialog,  

                                    int which) {  

                                dialog.cancel();  

                                intent intent = new intent(  

                                        settings.action_wireless_settings);  

                                context.startactivity(intent);  

                            }  

                        })  

                .setnegativebutton(r.string.close,  

                                    int whichbutton) {  

                        });  

        dialogbuilder.show();  

     * 显示toast 

     * @param text 

     * @param longint 

     * @update 2012-6-28 下午3:46:18 

    public void showtoast(string text, int longint) {  

        toast.maketext(context, text, longint).show();  

    public void showtoast(string text) {  

        toast.maketext(context, text, toast.length_short).show();  

     * 关闭键盘事件 

     * @update 2012-7-4 下午2:34:34 

    public void closeinput() {  

        inputmethodmanager inputmethodmanager = (inputmethodmanager) getsystemservice(context.input_method_service);  

        if (inputmethodmanager != null && this.getcurrentfocus() != null) {  

            inputmethodmanager.hidesoftinputfromwindow(this.getcurrentfocus()  

                    .getwindowtoken(), inputmethodmanager.hide_not_always);  

     * 发出notification的method. 

     * @param iconid 

     *            图标 

     * @param contenttitle 

     *            标题 

     * @param contenttext 

     *            你内容 

     * @param activity 

     * @update 2012-5-14 下午12:01:55 

    public void setnotitype(int iconid, string contenttitle,  

            string contenttext, class activity, string from) {  

        /* 

         * 创建新的intent,作为点击notification留言条时, 会运行的activity 

         */  

        intent notifyintent = new intent(this, activity);  

        notifyintent.putextra("to", from);  

        // notifyintent.setflags(intent.flag_activity_new_task);  

        /* 创建pendingintent作为设置递延运行的activity */  

        pendingintent appintent = pendingintent.getactivity(this, 0,  

                notifyintent, 0);  

        /* 创建notication,并设置相关参数 */  

        notification mynoti = new notification();  

        // 点击自动消失  

        mynoti.flags = notification.flag_auto_cancel;  

        /* 设置statusbar显示的icon */  

        mynoti.icon = iconid;  

        /* 设置statusbar显示的文字信息 */  

        mynoti.tickertext = contenttitle;  

        /* 设置notification发生时同时发出默认声音 */  

        mynoti.defaults = notification.default_sound;  

        /* 设置notification留言条的参数 */  

        mynoti.setlatesteventinfo(this, contenttitle, contenttext, appintent);  

        /* 送出notification */  

        notificationmanager.notify(0, mynoti);  

    public context getcontext() {  

        return context;  

    public sharedpreferences getloginusersharedpre() {  

        return preferences;  

    public void saveloginconfig(loginconfig loginconfig) {  

        preferences.edit()  

                .putstring(constant.xmpp_host, loginconfig.getxmpphost())  

                .commit();  

                .putint(constant.xmpp_port, loginconfig.getxmppport()).commit();  

        preferences  

                .edit()  

                .putstring(constant.xmpp_seivice_name,  

                        loginconfig.getxmppservicename()).commit();  

                .putstring(constant.username, loginconfig.getusername())  

                .putstring(constant.password, loginconfig.getpassword())  

                .putboolean(constant.is_autologin, loginconfig.isautologin())  

                .putboolean(constant.is_novisible, loginconfig.isnovisible())  

                .putboolean(constant.is_remember, loginconfig.isremember())  

                .putboolean(constant.is_online, loginconfig.isonline())  

                .putboolean(constant.is_firststart, loginconfig.isfirststart())  

    public loginconfig getloginconfig() {  

        loginconfig loginconfig = new loginconfig();  

        string a = preferences.getstring(constant.xmpp_host, null);  

        string b = getresources().getstring(r.string.xmpp_host);  

        loginconfig.setxmpphost(preferences.getstring(constant.xmpp_host,  

                getresources().getstring(r.string.xmpp_host)));  

        loginconfig.setxmppport(preferences.getint(constant.xmpp_port,  

                getresources().getinteger(r.integer.xmpp_port)));  

        loginconfig.setusername(preferences.getstring(constant.username, null));  

        loginconfig.setpassword(preferences.getstring(constant.password, null));  

        loginconfig.setxmppservicename(preferences.getstring(  

                constant.xmpp_seivice_name,  

                getresources().getstring(r.string.xmpp_service_name)));  

        loginconfig.setautologin(preferences.getboolean(constant.is_autologin,  

                getresources().getboolean(r.bool.is_autologin)));  

        loginconfig.setnovisible(preferences.getboolean(constant.is_novisible,  

                getresources().getboolean(r.bool.is_novisible)));  

        loginconfig.setremember(preferences.getboolean(constant.is_remember,  

                getresources().getboolean(r.bool.is_remember)));  

        loginconfig.setfirststart(preferences.getboolean(  

                constant.is_firststart, true));  

        return loginconfig;  

    public boolean getuseronlinestate() {  

        // preferences = getsharedpreferences(constant.login_set,0);  

        return preferences.getboolean(constant.is_online, true);  

    public void setuseronlinestate(boolean isonline) {  

        preferences.edit().putboolean(constant.is_online, isonline).commit();  

    public eimapplication geteimapplication() {  

        return eimapplication;  

}  

大家写android程序会发现,不同的activity之间经常需要调用一些公共的资源,这里的资源不仅包括android自身的,还有我们自己的管理服务类,甚至相互之间传递一些参数,这里我仿照struts2的设计,提炼出一个activitysupport类,同时抽取一个接口,让所有的activity都集成这个类,因为有了接口,我们便可以采用回调模式,非常方便的传递数据和使用公共的资源,这种好处相信大家使用之后都能有深刻的体会,通过接口回调传递参数和相互调用的方式无疑是最优雅的,spring和hibernate源码中曾经大量使用这种结构。

2.sqlitetemplate类

package csdn.shimiso.eim.db;  

import java.util.arraylist;  

import java.util.list;  

import android.content.contentvalues;  

import android.database.cursor;  

import android.database.sqlite.sqlitedatabase;  

 * sqlite数据库模板工具类 

 * 该类提供了数据库操作常用的增删改查,以及各种复杂条件匹配,分页,排序等操作 

 * @see sqlitedatabase 

public class sqlitetemplate {  

     * default primary key 

    protected string mprimarykey = "_id";  

     * dbmanager 

    private dbmanager dbmanager;  

     * 是否为一个事务 

    private boolean istransaction = false;  

     * 数据库连接 

    private sqlitedatabase database = null;  

    private sqlitetemplate() {  

    private sqlitetemplate(dbmanager dbmanager, boolean istransaction) {  

        this.dbmanager = dbmanager;  

        this.istransaction = istransaction;  

     * istransaction 是否属于一个事务 注:一旦istransaction设为true 

     * 所有的sqlitetemplate方法都不会自动关闭资源,需在事务成功后手动关闭 

     * @return 

    public static sqlitetemplate getinstance(dbmanager dbmanager,  

            boolean istransaction) {  

        return new sqlitetemplate(dbmanager, istransaction);  

     * 执行一条sql语句 

     * @param name 

     * @param tel 

    public void execsql(string sql) {  

        try {  

            database = dbmanager.opendatabase();  

            database.execsql(sql);  

        } catch (exception e) {  

            e.printstacktrace();  

        } finally {  

            if (!istransaction) {  

                closedatabase(null);  

    public void execsql(string sql, object[] bindargs) {  

            database.execsql(sql, bindargs);  

     * 向数据库表中插入一条数据 

     * @param table 

     *            表名 

     * @param content 

     *            字段值 

    public long insert(string table, contentvalues content) {  

            // insert方法第一参数:数据库表名,第二个参数如果content为空时则向表中插入一个null,第三个参数为插入的内容  

            return database.insert(table, null, content);  

        return 0;  

     * 批量删除指定主键数据 

     * @param ids 

    public void deletebyids(string table, object... primarykeys) {  

            if (primarykeys.length > 0) {  

                stringbuilder sb = new stringbuilder();  

                for (@suppresswarnings("unused")  

                object id : primarykeys) {  

                    sb.append("?").append(",");  

                sb.deletecharat(sb.length() - 1);  

                database = dbmanager.opendatabase();  

                database.execsql("delete from " + table + " where "  

                        + mprimarykey + " in(" + sb + ")",  

                        (object[]) primarykeys);  

     * 根据某一个字段和值删除一行数据, 如 name="jack" 

     * @param field 

     * @param value 

     * @return 返回值大于0表示删除成功 

    public int deletebyfield(string table, string field, string value) {  

            return database.delete(table, field + "=?", new string[] { value });  

     * 根据条件删除数据 

     * @param whereclause 

     *            查询语句 参数采用? 

     * @param whereargs 

     *            参数值 

    public int deletebycondition(string table, string whereclause,  

            string[] whereargs) {  

            return database.delete(table, whereclause, whereargs);  

     * 根据主键删除一行数据 

     * @param id 

    public int deletebyid(string table, string id) {  

            return deletebyfield(table, mprimarykey, id);  

     * 根据主键更新一行数据 

     * @param values 

     * @return 返回值大于0表示更新成功 

    public int updatebyid(string table, string id, contentvalues values) {  

            return database.update(table, values, mprimarykey + "=?",  

                    new string[] { id });  

     * 更新数据 

    public int update(string table, contentvalues values, string whereclause,  

            return database.update(table, values, whereclause, whereargs);  

     * 根据主键查看某条数据是否存在 

    public boolean isexistsbyid(string table, string id) {  

            return isexistsbyfield(table, mprimarykey, id);  

        return null;  

     * 根据某字段/值查看某条数据是否存在 

     * @param status 

    public boolean isexistsbyfield(string table, string field, string value) {  

        stringbuilder sql = new stringbuilder();  

        sql.append("select count(*) from ").append(table).append(" where ")  

                .append(field).append(" =?");  

            return isexistsbysql(sql.tostring(), new string[] { value });  

     * 使用sql语句查看某条数据是否存在 

     * @param sql 

     * @param selectionargs 

    public boolean isexistsbysql(string sql, string[] selectionargs) {  

        cursor cursor = null;  

            cursor = database.rawquery(sql, selectionargs);  

            if (cursor.movetofirst()) {  

                return (cursor.getint(0) > 0);  

            } else {  

                return false;  

                closedatabase(cursor);  

     * 查询一条数据 

     * @param rowmapper 

     * @param args 

    public <t> t queryforobject(rowmapper<t> rowmapper, string sql,  

            string[] args) {  

        t object = null;  

            cursor = database.rawquery(sql, args);  

                object = rowmapper.maprow(cursor, cursor.getcount());  

        return object;  

     * 查询 

     * @param startresult 

     *            开始索引 注:第一条记录索引为0 

     * @param maxresult 

     *            步长 

    public <t> list<t> queryforlist(rowmapper<t> rowmapper, string sql,  

            string[] selectionargs) {  

        list<t> list = null;  

            list = new arraylist<t>();  

            while (cursor.movetonext()) {  

                list.add(rowmapper.maprow(cursor, cursor.getposition()));  

        return list;  

     * 分页查询 

            int startresult, int maxresult) {  

            cursor = database.rawquery(sql + " limit ?,?", new string[] {  

                    string.valueof(startresult), string.valueof(maxresult) });  

     * 获取记录数 

    public integer getcount(string sql, string[] args) {  

            cursor = database.rawquery("select count(*) from (" + sql + ")",  

                    args);  

            if (cursor.movetonext()) {  

                return cursor.getint(0);  

     *            检索的表 

     * @param columns 

     *            由需要返回列的列名所组成的字符串数组,传入null会返回所有的列。 

     * @param selection 

     *            查询条件子句,相当于select语句where关键字后面的部分,在条件子句允许使用占位符"?" 

     *            对应于selection语句中占位符的值,值在数组中的位置与占位符在语句中的位置必须一致,否则就会有异常 

     * @param groupby 

     *            对结果集进行分组的group by语句(不包括group by关键字)。传入null将不对结果集进行分组 

     * @param having 

     *            对查询后的结果集进行过滤,传入null则不过滤 

     * @param orderby 

     *            对结果集进行排序的order by语句(不包括order by关键字)。传入null将对结果集使用默认的排序 

     * @param limit 

     *            指定偏移量和获取的记录数,相当于select语句limit关键字后面的部分,如果为null则返回所有行 

    public <t> list<t> queryforlist(rowmapper<t> rowmapper, string table,  

            string[] columns, string selection, string[] selectionargs,  

            string groupby, string having, string orderby, string limit) {  

            cursor = database.query(table, columns, selection, selectionargs,  

                    groupby, having, orderby, limit);  

     * get primary key 

    public string getprimarykey() {  

        return mprimarykey;  

     * set primary key 

     * @param primarykey 

    public void setprimarykey(string primarykey) {  

        this.mprimarykey = primarykey;  

     * @param <t> 

    public interface rowmapper<t> {  

        /** 

         *  

         * @param cursor 

         *            游标 

         * @param index 

         *            下标索引 

         * @return 

        public t maprow(cursor cursor, int index);  

     * 关闭数据库 

    public void closedatabase(cursor cursor) {  

        if (null != database) {  

            database.close();  

        if (null != cursor) {  

            cursor.close();  

我们希望在android操作数据库是优雅的一种方式,这里不必关注事务,也不用担心分页,更不用为了封装传递对象烦恼,总之一切就像面向对象那样,简单,模板类的出现正是解决这个问题,虽然它看上去可能不是那么完美有待提高,这里我封装了很多sqlite常用的工具,大家可以借鉴使用。

3.xmppconnectionmanager管理类

package csdn.shimiso.eim.manager;  

import org.jivesoftware.smack.connection;  

import org.jivesoftware.smack.connectionconfiguration;  

import org.jivesoftware.smack.roster;  

import org.jivesoftware.smack.xmppconnection;  

import org.jivesoftware.smack.provider.providermanager;  

import org.jivesoftware.smackx.groupchatinvitation;  

import org.jivesoftware.smackx.privatedatamanager;  

import org.jivesoftware.smackx.packet.chatstateextension;  

import org.jivesoftware.smackx.packet.lastactivity;  

import org.jivesoftware.smackx.packet.offlinemessageinfo;  

import org.jivesoftware.smackx.packet.offlinemessagerequest;  

import org.jivesoftware.smackx.packet.sharedgroupsinfo;  

import org.jivesoftware.smackx.provider.dataformprovider;  

import org.jivesoftware.smackx.provider.delayinformationprovider;  

import org.jivesoftware.smackx.provider.discoverinfoprovider;  

import org.jivesoftware.smackx.provider.discoveritemsprovider;  

import org.jivesoftware.smackx.provider.mucadminprovider;  

import org.jivesoftware.smackx.provider.mucownerprovider;  

import org.jivesoftware.smackx.provider.mucuserprovider;  

import org.jivesoftware.smackx.provider.messageeventprovider;  

import org.jivesoftware.smackx.provider.multipleaddressesprovider;  

import org.jivesoftware.smackx.provider.rosterexchangeprovider;  

import org.jivesoftware.smackx.provider.streaminitiationprovider;  

import org.jivesoftware.smackx.provider.vcardprovider;  

import org.jivesoftware.smackx.provider.xhtmlextensionprovider;  

import org.jivesoftware.smackx.search.usersearch;  

 * xmpp服务器连接工具类. 

public class xmppconnectionmanager {  

    private xmppconnection connection;  

    private static connectionconfiguration connectionconfig;  

    private static xmppconnectionmanager xmppconnectionmanager;  

    private xmppconnectionmanager() {  

    public static xmppconnectionmanager getinstance() {  

        if (xmppconnectionmanager == null) {  

            xmppconnectionmanager = new xmppconnectionmanager();  

        return xmppconnectionmanager;  

    // init  

    public xmppconnection init(loginconfig loginconfig) {  

        connection.debug_enabled = false;  

        providermanager pm = providermanager.getinstance();  

        configure(pm);  

        connectionconfig = new connectionconfiguration(  

                loginconfig.getxmpphost(), loginconfig.getxmppport(),  

                loginconfig.getxmppservicename());  

        connectionconfig.setsaslauthenticationenabled(false);// 不使用sasl验证,设置为false  

        connectionconfig  

                .setsecuritymode(connectionconfiguration.securitymode.enabled);  

        // 允许自动连接  

        connectionconfig.setreconnectionallowed(false);  

        // 允许登陆成功后更新在线状态  

        connectionconfig.setsendpresence(true);  

        // 收到好友邀请后manual表示需要经过同意,accept_all表示不经同意自动为好友  

        roster.setdefaultsubscriptionmode(roster.subscriptionmode.manual);  

        connection = new xmppconnection(connectionconfig);  

        return connection;  

     * 返回一个有效的xmpp连接,如果无效则返回空. 

     * @update 2012-7-4 下午6:54:31 

    public xmppconnection getconnection() {  

        if (connection == null) {  

            throw new runtimeexception("请先初始化xmppconnection连接");  

     * 销毁xmpp连接. 

     * @update 2012-7-4 下午6:55:03 

    public void disconnect() {  

        if (connection != null) {  

            connection.disconnect();  

    public void configure(providermanager pm) {  

        // private data storage  

        pm.addiqprovider("query", "jabber:iq:private",  

                new privatedatamanager.privatedataiqprovider());  

        // time  

            pm.addiqprovider("query", "jabber:iq:time",  

                    class.forname("org.jivesoftware.smackx.packet.time"));  

        } catch (classnotfoundexception e) {  

        // xhtml  

        pm.addextensionprovider("html", "http://jabber.org/protocol/xhtml-im",  

                new xhtmlextensionprovider());  

        // roster exchange  

        pm.addextensionprovider("x", "jabber:x:roster",  

                new rosterexchangeprovider());  

        // message events  

        pm.addextensionprovider("x", "jabber:x:event",  

                new messageeventprovider());  

        // chat state  

        pm.addextensionprovider("active",  

                "http://jabber.org/protocol/chatstates",  

                new chatstateextension.provider());  

        pm.addextensionprovider("composing",  

        pm.addextensionprovider("paused",  

        pm.addextensionprovider("inactive",  

        pm.addextensionprovider("gone",  

        // filetransfer  

        pm.addiqprovider("si", "http://jabber.org/protocol/si",  

                new streaminitiationprovider());  

        // group chat invitations  

        pm.addextensionprovider("x", "jabber:x:conference",  

                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", "jabber:x:data", 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", "jabber:x:delay",  

                new delayinformationprovider());  

        // version  

            pm.addiqprovider("query", "jabber:iq:version",  

                    class.forname("org.jivesoftware.smackx.packet.version"));  

        // 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());  

这个类是xmpp连接的管理类,如果大家使用smack的api对这个应该不会陌生,asmack对xmpp连接的管理,与smack的差别不大,但是部分细微区别也有,我们在使用中如果遇到问题,还要多加注意,我们这里将其设计成单例,毕竟重复创建连接是个非常消耗的过程。

基于xmpp openfire smack开发之Android客户端开发[3]
基于xmpp openfire smack开发之Android客户端开发[3]
基于xmpp openfire smack开发之Android客户端开发[3]

很像qq吧,没错,这是2012年版本qq的安卓界面,只是界面元素一样,实现方式大不相同,下面简单列一下这个客户端实现的功能:

1.聊天

2.离线消息

3.添加,删除好友

4.添加,移动好友分组

5.设置昵称

6.监控好友状态

7.网络断开系统自动重连接

8.收到添加好友请求消息处理

9.收到系统广播消息处理

10.查看历史聊天记录

11.消息弹出提醒,和小气泡

....

因为时间关系不是很完美,主要用于学习研究,欢迎大家给我提bug和改进意见。

分数比较大,不是为了坑大家,是怕有伸手党出现,拿了源码出去招摇撞骗,请尊重作者原创!

http://download.csdn.net/detail/shimiso/6224163

参阅文献

openfirehttp://www.igniterealtime.org/

push-notificationhttp://www.push-notification.org/

claros chathttp://www.claros.org/

androidpnsourceforgehttp://sourceforge.net/projects/androidpn/

android消息推送解决方案http://www.cnblogs.com/hanyonglu/archive/2012/03/04/2378971.html

xmpp协议实现原理介绍 http://www.cnblogs.com/hanyonglu/archive/2012/03/04/2378956.html