http://blog.csdn.net/shimiso/article/details/11225873

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

1.源码结构介绍

Android之基于xmpp openfire smack开发之Android客户端开发[3]_第1张图片

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

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

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

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

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

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

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

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

Android之基于xmpp openfire smack开发之Android客户端开发[3]_第2张图片

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

layout是布局页面

menu是地步菜单布局页面

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

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

<!-- 缺省的服务器配置 -->     <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"/>  

2.核心类介绍

1.ActivitySupport类
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);      }        @Override      protected void onStart() {          super.onStart();      }        @Override      protected void onResume() {          super.onResume();      }        @Override      protected void onPause() {          super.onPause();      }        @Override      protected void onStop() {          super.onStop();      }        @Override      public void onDestroy() {          super.onDestroy();      }        @Override      public ProgressDialog getProgressDialog() {          return pg;      }        @Override      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      */      @Override      public void stopService() {          // 好友联系人服务          Intent server = new Intent(context, IMContactService.class);          context.stopService(server);          // 聊天服务          Intent chatServer = new Intent(context, IMChatService.class);          context.stopService(chatServer);            // 自动恢复连接服务          Intent reConnectService = new Intent(context, ReConnectService.class);          context.stopService(reConnectService);            // 系统消息连接服务          Intent imSystemMsgService = new Intent(context,                  IMSystemMsgService.class);          context.stopService(imSystemMsgService);      }        @Override      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() {                      @Override                      public void onClick(DialogInterface dialog, int which) {                          dialog.cancel();                      }                  }).show();      }        @Override      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;      }        @Override      public boolean validateInternet() {          ConnectivityManager manager = (ConnectivityManager) context                  .getSystemService(context.CONNECTIVITY_SERVICE);          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();          return false;      }        @Override      public boolean hasLocationGPS() {          LocationManager manager = (LocationManager) context                  .getSystemService(context.LOCATION_SERVICE);          if (manager                  .isProviderEnabled(android.location.LocationManager.GPS_PROVIDER)) {              return true;          } else {              return false;          }      }        @Override      public boolean hasLocationNetWork() {          LocationManager manager = (LocationManager) context                  .getSystemService(context.LOCATION_SERVICE);          if (manager                  .isProviderEnabled(android.location.LocationManager.NETWORK_PROVIDER)) {              return true;          } else {              return false;          }      }        @Override      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("退出",                              new DialogInterface.OnClickListener() {                                  @Override                                  public void onClick(DialogInterface dialog,                                          int which) {                                      dialog.cancel();                                      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,                          new DialogInterface.OnClickListener() {                              @Override                              public void onClick(DialogInterface dialog,                                      int whichButton) {                                  dialog.cancel();                              }                          });          dialogBuilder.show();      }        /**      *       * 显示toast      *       * @param text      * @param longint      * @author shimiso      * @update 2012-6-28 下午3:46:18      */      public void showToast(String text, int longint) {          Toast.makeText(context, text, longint).show();      }        @Override      public void showToast(String text) {          Toast.makeText(context, text, Toast.LENGTH_SHORT).show();      }        /**      *       * 关闭键盘事件      *       * @author shimiso      * @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      * @author shimiso      * @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);      }        @Override      public Context getContext() {          return context;      }        @Override      public SharedPreferences getLoginUserSharedPre() {          return preferences;      }        @Override      public void saveLoginConfig(LoginConfig loginConfig) {          preferences.edit()                  .putString(Constant.XMPP_HOST, loginConfig.getXmppHost())                  .commit();          preferences.edit()                  .putInt(Constant.XMPP_PORT, loginConfig.getXmppPort()).commit();          preferences                  .edit()                  .putString(Constant.XMPP_SEIVICE_NAME,                          loginConfig.getXmppServiceName()).commit();          preferences.edit()                  .putString(Constant.USERNAME, loginConfig.getUsername())                  .commit();          preferences.edit()                  .putString(Constant.PASSWORD, loginConfig.getPassword())                  .commit();          preferences.edit()                  .putBoolean(Constant.IS_AUTOLOGIN, loginConfig.isAutoLogin())                  .commit();          preferences.edit()                  .putBoolean(Constant.IS_NOVISIBLE, loginConfig.isNovisible())                  .commit();          preferences.edit()                  .putBoolean(Constant.IS_REMEMBER, loginConfig.isRemember())                  .commit();          preferences.edit()                  .putBoolean(Constant.IS_ONLINE, loginConfig.isOnline())                  .commit();          preferences.edit()                  .putBoolean(Constant.IS_FIRSTSTART, loginConfig.isFirstStart())                  .commit();      }        @Override      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;      }        @Override      public boolean getUserOnlineState() {          // preferences = getSharedPreferences(Constant.LOGIN_SET,0);          return preferences.getBoolean(Constant.IS_ONLINE, true);      }        @Override      public void setUserOnlineState(boolean isOnline) {          // preferences = getSharedPreferences(Constant.LOGIN_SET,0);          preferences.edit().putBoolean(Constant.IS_ONLINE, isOnline).commit();        }        @Override      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);              }          }      }        /**      * 执行一条sql语句      *       * @param name      * @param tel      */      public void execSQL(String sql, Object[] bindArgs) {          try {              dataBase = dBManager.openDatabase();              dataBase.execSQL(sql, bindArgs);          } catch (Exception e) {              e.printStackTrace();          } finally {              if (!isTransaction) {                  closeDatabase(null);              }          }      }        /**      * 向数据库表中插入一条数据      *       * @param table      *            表名      * @param content      *            字段值      */      public long insert(String table, ContentValues content) {          try {              dataBase = dBManager.openDatabase();              // insert方法第一参数:数据库表名,第二个参数如果CONTENT为空时则向表中插入一个NULL,第三个参数为插入的内容              return dataBase.insert(table, null, content);          } catch (Exception e) {              e.printStackTrace();          } finally {              if (!isTransaction) {                  closeDatabase(null);              }          }          return 0;      }        /**      * 批量删除指定主键数据      *       * @param ids      */      public void deleteByIds(String table, Object... primaryKeys) {          try {              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);              }          } catch (Exception e) {              e.printStackTrace();          } finally {              if (!isTransaction) {                  closeDatabase(null);              }          }      }        /**      * 根据某一个字段和值删除一行数据, 如 name="jack"      *       * @param table      * @param field      * @param value      * @return 返回值大于0表示删除成功      */      public int deleteByField(String table, String field, String value) {          try {              dataBase = dBManager.openDatabase();              return dataBase.delete(table, field + "=?", new String[] { value });          } catch (Exception e) {              e.printStackTrace();          } finally {              if (!isTransaction) {                  closeDatabase(null);              }          }          return 0;      }        /**      * 根据条件删除数据      *       * @param table      *            表名      * @param whereClause      *            查询语句 参数采用?      * @param whereArgs      *            参数值      * @return 返回值大于0表示删除成功      */      public int deleteByCondition(String table, String whereClause,              String[] whereArgs) {          try {              dataBase = dBManager.openDatabase();              return dataBase.delete(table, whereClause, whereArgs);          } catch (Exception e) {              e.printStackTrace();          } finally {              if (!isTransaction) {                  closeDatabase(null);              }          }          return 0;      }        /**      * 根据主键删除一行数据      *       * @param table      * @param id      * @return 返回值大于0表示删除成功      */      public int deleteById(String table, String id) {          try {              dataBase = dBManager.openDatabase();              return deleteByField(table, mPrimaryKey, id);          } catch (Exception e) {              e.printStackTrace();          } finally {              if (!isTransaction) {                  closeDatabase(null);              }          }          return 0;      }        /**      * 根据主键更新一行数据      *       * @param table      * @param id      * @param values      * @return 返回值大于0表示更新成功      */      public int updateById(String table, String id, ContentValues values) {          try {              dataBase = dBManager.openDatabase();              return dataBase.update(table, values, mPrimaryKey + "=?",                      new String[] { id });          } catch (Exception e) {              e.printStackTrace();          } finally {              if (!isTransaction) {                  closeDatabase(null);              }          }          return 0;      }        /**      * 更新数据      *       * @param table      * @param values      * @param whereClause      * @param whereArgs      * @return 返回值大于0表示更新成功      */      public int update(String table, ContentValues values, String whereClause,              String[] whereArgs) {          try {              dataBase = dBManager.openDatabase();              return dataBase.update(table, values, whereClause, whereArgs);          } catch (Exception e) {              e.printStackTrace();          } finally {              if (!isTransaction) {                  closeDatabase(null);              }          }          return 0;      }        /**      * 根据主键查看某条数据是否存在      *       * @param table      * @param id      * @return      */      public Boolean isExistsById(String table, String id) {          try {              dataBase = dBManager.openDatabase();              return isExistsByField(table, mPrimaryKey, id);          } catch (Exception e) {              e.printStackTrace();          } finally {              if (!isTransaction) {                  closeDatabase(null);              }          }          return null;      }        /**      * 根据某字段/值查看某条数据是否存在      *       * @param status      * @return      */      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(" =?");          try {              dataBase = dBManager.openDatabase();              return isExistsBySQL(sql.toString(), new String[] { value });          } catch (Exception e) {              e.printStackTrace();          } finally {              if (!isTransaction) {                  closeDatabase(null);              }          }          return null;      }        /**      * 使用SQL语句查看某条数据是否存在      *       * @param sql      * @param selectionArgs      * @return      */      public Boolean isExistsBySQL(String sql, String[] selectionArgs) {          Cursor cursor = null;          try {              dataBase = dBManager.openDatabase();              cursor = dataBase.rawQuery(sql, selectionArgs);              if (cursor.moveToFirst()) {                  return (cursor.getInt(0) > 0);              } else {                  return false;              }          } catch (Exception e) {              e.printStackTrace();          } finally {              if (!isTransaction) {                  closeDatabase(cursor);              }          }          return null;      }        /**      * 查询一条数据      *       * @param rowMapper      * @param sql      * @param args      * @return      */      public <T> T queryForObject(RowMapper<T> rowMapper, String sql,              String[] args) {          Cursor cursor = null;          T object = null;          try {              dataBase = dBManager.openDatabase();              cursor = dataBase.rawQuery(sql, args);              if (cursor.moveToFirst()) {                  object = rowMapper.mapRow(cursor, cursor.getCount());              }          } finally {              if (!isTransaction) {                  closeDatabase(cursor);              }          }          return object;        }        /**      * 查询      *       * @param rowMapper      * @param sql      * @param startResult      *            开始索引 注:第一条记录索引为0      * @param maxResult      *            步长      * @return      */      public <T> List<T> queryForList(RowMapper<T> rowMapper, String sql,              String[] selectionArgs) {          Cursor cursor = null;          List<T> list = null;          try {              dataBase = dBManager.openDatabase();              cursor = dataBase.rawQuery(sql, selectionArgs);              list = new ArrayList<T>();              while (cursor.moveToNext()) {                  list.add(rowMapper.mapRow(cursor, cursor.getPosition()));              }          } finally {              if (!isTransaction) {                  closeDatabase(cursor);              }          }          return list;      }        /**      * 分页查询      *       * @param rowMapper      * @param sql      * @param startResult      *            开始索引 注:第一条记录索引为0      * @param maxResult      *            步长      * @return      */      public <T> List<T> queryForList(RowMapper<T> rowMapper, String sql,              int startResult, int maxResult) {          Cursor cursor = null;          List<T> list = null;          try {              dataBase = dBManager.openDatabase();              cursor = dataBase.rawQuery(sql + " limit ?,?", new String[] {                      String.valueOf(startResult), String.valueOf(maxResult) });              list = new ArrayList<T>();              while (cursor.moveToNext()) {                  list.add(rowMapper.mapRow(cursor, cursor.getPosition()));              }          } finally {              if (!isTransaction) {                  closeDatabase(cursor);              }          }          return list;      }        /**      * 获取记录数      *       * @return      */      public Integer getCount(String sql, String[] args) {          Cursor cursor = null;          try {              dataBase = dBManager.openDatabase();              cursor = dataBase.rawQuery("select count(*) from (" + sql + ")",                      args);              if (cursor.moveToNext()) {                  return cursor.getInt(0);              }          } catch (Exception e) {              e.printStackTrace();          } finally {              if (!isTransaction) {                  closeDatabase(cursor);              }          }          return 0;      }        /**      * 分页查询      *       * @param rowMapper      * @param table      *            检索的表      * @param columns      *            由需要返回列的列名所组成的字符串数组,传入null会返回所有的列。      * @param selection      *            查询条件子句,相当于select语句where关键字后面的部分,在条件子句允许使用占位符"?"      * @param selectionArgs      *            对应于selection语句中占位符的值,值在数组中的位置与占位符在语句中的位置必须一致,否则就会有异常      * @param groupBy      *            对结果集进行分组的group by语句(不包括GROUP BY关键字)。传入null将不对结果集进行分组      * @param having      *            对查询后的结果集进行过滤,传入null则不过滤      * @param orderBy      *            对结果集进行排序的order by语句(不包括ORDER BY关键字)。传入null将对结果集使用默认的排序      * @param limit      *            指定偏移量和获取的记录数,相当于select语句limit关键字后面的部分,如果为null则返回所有行      * @return      */      public <T> List<T> queryForList(RowMapper<T> rowMapper, String table,              String[] columns, String selection, String[] selectionArgs,              String groupBy, String having, String orderBy, String limit) {          List<T> list = null;          Cursor cursor = null;          try {              dataBase = dBManager.openDatabase();              cursor = dataBase.query(table, columns, selection, selectionArgs,                      groupBy, having, orderBy, limit);              list = new ArrayList<T>();              while (cursor.moveToNext()) {                  list.add(rowMapper.mapRow(cursor, cursor.getPosition()));              }          } finally {              if (!isTransaction) {                  closeDatabase(cursor);              }          }          return list;      }        /**      * Get Primary Key      *       * @return      */      public String getPrimaryKey() {          return mPrimaryKey;      }        /**      * Set Primary Key      *       * @param primaryKey      */      public void setPrimaryKey(String primaryKey) {          this.mPrimaryKey = primaryKey;      }        /**      *       * @author shimiso      *       * @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;    import csdn.shimiso.eim.model.LoginConfig;    /**  *   * XMPP服务器连接工具类.  *   * @author shimiso  */  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连接,如果无效则返回空.      *       * @return      * @author shimiso      * @update 2012-7-4 下午6:54:31      */      public XMPPConnection getConnection() {          if (connection == null) {              throw new RuntimeException("请先初始化XMPPConnection连接");          }          return connection;      }        /**      *       * 销毁xmpp连接.      *       * @author shimiso      * @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          try {              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",                  "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());            // 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          try {              pm.addIQProvider("query", "jabber:iq:version",                      Class.forName("org.jivesoftware.smackx.packet.Version"));          } catch (ClassNotFoundException e) {          }          // 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的差别不大,但是部分细微区别也有,我们在使用中如果遇到问题,还要多加注意,我们这里将其设计成单例,毕竟重复创建连接是个非常消耗的过程。

3.演示效果

Android之基于xmpp openfire smack开发之Android客户端开发[3]_第3张图片
Android之基于xmpp openfire smack开发之Android客户端开发[3]_第4张图片
很像QQ吧,没错,这是2012年版本qq的安卓界面,只是界面元素一样,实现方式大不相同,下面简单列一下这个客户端实现的功能: 1.聊天 2.离线消息 3.添加,删除好友 4.添加,移动好友分组 5.设置昵称 6.监控好友状态 7.网络断开系统自动重连接 8.收到添加好友请求消息处理 9.收到系统广播消息处理 10.查看历史聊天记录 11.消息弹出提醒,和小气泡 .... 因为时间关系不是很完美,主要用于学习研究,欢迎大家给我提bug和改进意见。

4.源码下载

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










更多相关文章

  1. android 连接远程数据库
  2. Android[中级教程]第八章 Json数据的处理
  3. (转)Android从服务器端获取数据的几种方法
  4. 【Android Training - 04】保存数据 [ Lesson 2 - 保存文件]
  5. Android adb forward转发TCP端口连接数据
  6. Android:SNS客户端开发四:数据库操作(二)
  7. Android之MVP模式实现登录和网络数据加载

随机推荐

  1. android ndk开发SIGSEGV错误
  2. Android应用程序线程消息循环模型分析
  3. Android框架的深度分析1
  4. Android(安卓)Sqlite数据库查询或删除N天
  5. Android 之 uses-permission
  6. android webkit JavaScript 不能处理onke
  7. Android应用程序资源——Animation动画资
  8. Android.mk——makefile分析
  9. Android中invalidate()和postInvalidate(
  10. QQ音乐Android客户端Web页面通用性能优化