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

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

1.源码结构介绍


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

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

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

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

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

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

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

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


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.演示效果



很像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. mybatisplus的坑 insert标签insert into select无参数问题的解决
  2. 箭头函数的基础使用
  3. python起点网月票榜字体反爬案例
  4. NPM 和webpack 的基础使用
  5. Python list sort方法的具体使用
  6. 【阿里云镜像】使用阿里巴巴DNS镜像源——DNS配置教程
  7. Android开发实践 数据存储 学习、应用、总结
  8. 享受Android应用程序的Java技术盛宴
  9. 编写高效的Android代码

随机推荐

  1. Android四种保存数据的方法
  2. Android(安卓)Service总结05 之IntentSer
  3. 2021.1.24
  4. 结构体的初级认识
  5. C语言函数的递归(上)
  6. 学习打卡1-24
  7. 记录我发现的第一个关于 Google 的 Bug
  8. 从零学Android(十三)、Android中的数据存储
  9. [置顶] 【小超_Android】2014年框架类源
  10. Android测试框架对比