7.xmpp版即时聊天

即时聊天的解决方案

  • socket:
  • xmpp:xmpp+openfire+asmack
  • 环信

常见协议

比较安全,tcp上还加了俩层

简单聊一下socket

socket:套接字,连接需要ip端口,分为tcp和udp两种形式

常见的术语

  • xmpp:基于xml的可拓展协议.
  • jabber:xmpp的前身.
  • openfire:支持xmpp的开源服务器
  • smack.jar:对xmpp协议封装.方便开发的jar包.
  • spark.exe:基于xmpp的pc客户端;
  • asmack.jar:smack.jar的精简版.专门针对android端开发

xmpp的认识.

  • xmpp官网:http://xmpp.org/
  • XMPP(可扩展消息处理现场协议)是基于可扩展标记语言(XML)的协议,它用于即时消息(IM)以及在线现场探测。  XMPP的前身是Jabber,一个开源形式组织产生的网络即时通信协议。 

xmpp特点:

  1. 开放: XMPP协议是自由、开放、公开的,并且易于了解。 而且在客户端 、 服务器 、 组件 、 源码库等方面,都已经各自有多种实现。
  2. 标准: 互联网工程工作小组( IETF )已经将Jabber的核心XML流协议以XMPP之名,正式列为认可的实时通信及Presence技术。 而XMPP的技术规格已被定义在RFC 3920及RFC 3921 。 任何IM供应商在遵循XMPP协议下,都可与Google Talk实现连接。
  3. 证实可用: 第一个Jabber(现在XMPP)技术是Jeremie Miller在1998年开发的,现在已经相当稳定;数以百计的开发者为XMPP技术而努力。 今日的互联网上有数以万计的XMPP服务器运作着,并有数以百万计的人们使用XMPP实时传讯软件。
  4. 分散式: XMPP网络的架构和电子邮件十分相像;XMPP核心协议通信方式是先创建一个stream,XMPP以TCP传递XML数据流,没有中央主服务器。 任何人都可以运行自己的XMPP服务器,使个人及组织能够掌控他们的实时传讯体验。
  5. 安全: 任何XMPP协议的服务器可以独立于公众XMPP网络(例如在企业内部网络中),而使用SASL及TLS等技术的可靠安全性,已自带于核心XMPP技术规格中。
  6. 可扩展: XML 命名空间的威力可使任何人在核心协议的基础上建造定制化的功能;为了维持通透性,常见的扩展由XMPP标准基金会 。 弹性佳 XMPP除了可用在实时通信的应用程序,还能用在网络管理、内容供稿、协同工具、文件共享、游戏、远程系统监控等。
  7. 多样性: 用XMPP协议来建造及布署实时应用程序及服务的公司及开放源代码计划分布在各种领域;用XMPP技术开发软件,资源及支持的来源是多样的,使得使你不会陷于被“绑架”的困境。

相关的下载

asmack github:https://github.com/Flowdalic/asmack asmack下载地址1:http://asmack.freakempire.de/ asmack下载地址2:http://code.google.com/p/asmack/downloads/list openfire下载地址:http://www.igniterealtime.org/downloads/index.jsp smack使用指南:http://www.igniterealtime.org/builds/smack/docs/latest/documentation/index.html

openfire的安装

  1. 官网http://www.igniterealtime.org/
  2. 安装包的类型
    1. exe安装包-->点击exe根据提示安装
    2. zip包解压版-->解压放到指定目录就可以了.
  3. 首次运行的配置
    1. 配置语言-->中文简体
    2. 配置数据库形式-->内嵌数据库
    3. 配置服务器名称-->itheima
    4. 配置管理员账号密码-->admin admin。帐号就是这个,没有@xxx那些
  4. 创建用户
    1. admin admin
    2. hm1 111111

spark的安装-->xmpp客户端1

  • 直接下一步就可以完成
  • 运行
    • 1.配置服务器ip
    • 2.输入用户账号/密码

如意通的安装-->xmpp客户端2

pc端-服务器-pc端演示

smack常见api的查看.

xmpp版即使聊天的核心:其实就是熟悉asmack.jar里面的一些常见类.以及常见监听器;

工程搭建

  1. asmack.jar的下载,下载地址http://asmack.freakempire.de/
  2. 创建android工程.
  3. 添加jar包.添加依赖
  4. as关联源码.

引导页模块splashActivity

ThreadUtils的封装.

public class ThreadUtils {
    /**
     * 子线程执行task
     */
    public static void runInThread(Runnable task) {
        new Thread(task).start();
    }
    /**
     * 创建一个主线程中handler
     */
    public static Handler mHandler = new Handler();
    /**
     * UI线程执行task
     */
    public static void runInUIThread(Runnable task) {
        mHandler.post(task);
    }
}
public class  {
    /**
     * 可以在子线程中弹出toast
     *
     * @param context
     * @param text
     */
    public static void showToastSafe(final Context context, final String text) {
        ThreadUtils.runInUIThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(context, text, Toast.LENGTH_SHORT).show();
            }
        });
    }
}

SplashActivity

public class SplashActivity extends ActionBarActivity {
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_splash);
		// 停留3s,进入登录界面
		ThreadUtils.runInThread(new Runnable() {
			@Override
			public void run() {
				// 休眠3s
				SystemClock.sleep(3000);
				// 进入主界面
				Intent intent = new Intent(SplashActivity.this, LoginActivity.class);
				startActivity(intent);
				finish();
			}
		});
	}
}

登录模块LoginActivity

  1. 引入了ButterKnife.jar以及as的android-butterknife-zelezny插件
  2. ButterKnife:类似xutils中的viewUtils,可以注解的框架,图为关联源码,点右面
  3. 调用api登录

连接配置

// 设置常见的参数 config.setDebuggerEnabled(true);// 开启调试模式,可以看到传输的xml config.setSecurityMode(ConnectionConfiguration.SecurityMode.disabled);//明文传输

public class LoginActivity extends ActionBarActivity {
    public static final String HOST = "192.168.1.100";    // 主机ip
    public static final int PORT = 5222;            // 对应的端口号
    public static final String SERVICENAME = "itheima.com";
    private TextView mEtUserName;
    private TextView mEtPassWord;
    private Button mBtnLogin;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
        initView();
        initListener();
    }
    private void initListener() {
        mBtnLogin.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                final String userName = mEtUserName.getText().toString();
                final String passWord = mEtPassWord.getText().toString();
                // 判断用户名是否为空
                if (TextUtils.isEmpty(userName)) {// 用户名为空,系统自带的textview的属性,弹出悬浮窗提示
                    mEtUserName.setError("用户名不能为空");
                    return;
                }
                // 判断密码是否为空
                if (TextUtils.isEmpty(passWord)) {// 用户名为空
                    mEtPassWord.setError("密码不能为空");
                    return;
                }
                ThreadUtils.runInThread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            // 1.创建连接配置对象
                            ConnectionConfiguration config = new ConnectionConfiguration(HOST, PORT);
                            // 额外的配置(方面我们开发,上线的时候,可以改回来)
                            config.setSecurityMode(ConnectionConfiguration.SecurityMode.disabled);// 明文传输
                            config.setDebuggerEnabled(true);// 开启调试模式,方便我们查看具体发送的内容
                            // 2.开始创建连接对象
                            XMPPConnection conn = new XMPPConnection(config);
                            // 开始连接
                            conn.connect();
                            // 连接成功了
                            // 3.开始登录
                            conn.login(userName, passWord);
                            // 已经成功成功
                            ToastUtils.showToastSafe(LoginActivity.this, "登录成功");
                            finish();
                            // 跳到主界面
                            Intent intent = new Intent(LoginActivity.this, MainActivity.class);
                            startActivity(intent);
                            // 需要保存连接对象
                            IMService.conn = conn;
                            //启动IMService
                            Intent service = new Intent(LoginActivity.this, IMService.class);
                            startService(service);
                        } catch (XMPPException e) {
                            e.printStackTrace();
                            ToastUtils.showToastSafe(LoginActivity.this, "登录失败");
                        }
                    }
                });
            }
        });
    }
    private void initView() {
        mEtUserName = (TextView) findViewById(R.id.et_username);
        mEtPassWord = (TextView) findViewById(R.id.et_password);
        mBtnLogin = (Button) findViewById(R.id.btn_login);
    }
}

主页面MainActivity

ToolBarUtil

public class ToolBarUtil {
    private List<TextView> mTextViews = new ArrayList<TextView>();
    public void createToolBar(LinearLayout container, String[] toolBarTitleArr, int[] iconArr) {
        for (int i = 0; i < toolBarTitleArr.length; i++) {
            TextView tv = (TextView) View.inflate(container.getContext(), R.layout.inflate_toolbar_btn, null);
            tv.setText(toolBarTitleArr[i]);
            // 动态修改textView里面的drawableTop属性
            tv.setCompoundDrawablesWithIntrinsicBounds(0, iconArr[i], 0, 0);
            int width = 0;
            int height = LinearLayout.LayoutParams.MATCH_PARENT;
            LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(width, height);
            //设置weight属性
            params.weight = 1;
            container.addView(tv, params);
            //保存textView到集合中
            mTextViews.add(tv);
            //设置点击事件
            final int finalI = i;
            tv.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    //不同模块之间传值需要用接口回调
                    //3.需要传值的地方.用接口对象调用接口方法
                    mOnToolBarClickListener.onToolBarClick(finalI);
                }
            });
        }
    }
    public void changeColor(int position) {
        //还原所有的颜色
        for (TextView tv : mTextViews) {
            tv.setSelected(false);
        }
        mTextViews.get(position).setSelected(true);//通过设置selected属性,控制为选中效果
    }
    //1.创建接口和接口方法
    public  interface  OnToolBarClickListener{
        void onToolBarClick(int position);
    }
    //2.定义接口变量
    OnToolBarClickListener mOnToolBarClickListener;
    //4.暴露一个公共的方法
    public void setOnToolBarClickListener(OnToolBarClickListener onToolBarClickListener) {
        mOnToolBarClickListener = onToolBarClickListener;
    }
}

MainActivity

public class MainActivity extends ActionBarActivity {
	@InjectView(R.id.main_tv_title)
	TextView				mMainTvTitle;
	@InjectView(R.id.main_viewpager)
	ViewPager				mMainViewpager;
	@InjectView(R.id.main_bottom)
	LinearLayout			mMainBottom;
	// xutils viewutils 注解方式去找控件
	// viewutils httpUitls dbutils bitmaputils
	//
	private List<Fragment>	mFragments	= new ArrayList<Fragment>();
	private ToolBarUtil		mToolBarUtil;
	private String[]		mToolBarTitleArr;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		ButterKnife.inject(this);
		initData();
		initListener();
	}
	private void initListener() {
		mMainViewpager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
			@Override
			public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
			}
			@Override
			public void onPageSelected(int position) {
				// 修改颜色
				mToolBarUtil.changeColor(position);
				// 修改title
				mMainTvTitle.setText(mToolBarTitleArr[position]);
			}
			@Override
			public void onPageScrollStateChanged(int state) {
			}
		});
		mToolBarUtil.setOnToolBarClickListener(new ToolBarUtil.OnToolBarClickListener() {
			@Override
			public void onToolBarClick(int position) {
				mMainViewpager.setCurrentItem(position);
			}
		});
	}
	private void initData() {
		// viewPager-->view-->pagerAdapter
		// viewPager-->fragment-->fragmentPagerAdapter-->fragment数量比较少
		// viewPager-->fragment-->fragmentStatePagerAdapter
		// 添加fragment到集合中
		mFragments.add(new SessionFragment());
		mFragments.add(new ContactsFragment());
		mMainViewpager.setAdapter(new MyPagerAdapter(getSupportFragmentManager()));
		// 底部按钮
		mToolBarUtil = new ToolBarUtil();
		// 文字内容
		mToolBarTitleArr = new String[] { "会话", "联系人" };
		// 图标内容
		int[] iconArr = { R.drawable.selector_meassage, R.drawable.selector_selfinfo };
		mToolBarUtil.createToolBar(mMainBottom, mToolBarTitleArr, iconArr);
		// 设置默认选中会话
		mToolBarUtil.changeColor(0);
	}
	class MyPagerAdapter extends FragmentPagerAdapter {
		public MyPagerAdapter(FragmentManager fm) {
			super(fm);
		}
		@Override
		public Fragment getItem(int position) {
			return mFragments.get(position);
		}
		@Override
		public int getCount() {
			return 2;
		}
	}
}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏向治洪

android 网络通信框架volly

1. 什么是Volley 在这之前,我们在程序中需要和网络通信的时候,大体使用的东西莫过于AsyncTaskLoader,HttpURLConnection...

2035
来自专栏美团技术团队

Toast与Snackbar的那点事

4716
来自专栏移动开发

FragmentPagerAdapter 滑动过后界面不显示的解决方案

最近工作中UI给出如图设计,心想这个结合viewpager,fragment,FragmentPagerAdapter就能构建出来.

3593
来自专栏非著名程序员

浅析Otto框架,并与EventBus对比

? 前两天在公众号里发了一篇有关EventBus的文章《玩转EventBus,详解其使用》,有读者和开发者反馈说没有OTTO好用。确实是,各有优缺点吧,那今天...

2545
来自专栏小鄧子的技术博客专栏

【译】Android技术栈,1#架构

本文是如何开发一款具有扩展性,维护性和测试性的Android应用专题的第一篇。本专题将会涉及到一些设计模式和类库的使用方式,减少Android Develope...

1103
来自专栏Android机动车

实用的 Android 开源库整理

在Android的开发过程中,每个开发者或多或少的都使用过第三方的开源库,使用第三方的开源库可以给开发者节省大量的精力和时间,进而更好的关注应用本身的业务逻辑。

901
来自专栏Android先生

Android App优化之提升你的App启动速度之实例挑战

以之前写的Github App:https://github.com/mingjunli/GithubApp为例.

1243
来自专栏刘望舒

lifecycle-mvp,像前端那样组合式写页面

2974
来自专栏7号代码

Android应用界面开发——BroadcastReceiver(实现基于Service的音乐播放器)

BroadcastReceiver用于接收程序(开发者开发的程序和系统程序)发出的Broadcast Intent,程序启动BroadcastReceiver需...

1362
来自专栏技术墨客

Spring核心——IOC功能扩展点 原

上一篇文章介绍了非侵入式的框架的概念以及IOC的功能扩展点之一——BeanPostProcessor,我们接下来的内容继续说明IoC更多的扩展方法。

992

扫码关注云+社区

领取腾讯云代金券