Asmack 聊天框架 使用(一)

联网有两种:
1,短连接(http连接):必须客户端发请求,服务器返回,连接断开,下一次再连接服务必须客户端先发请求。
2,长连接,实现服务器推送信息给客户端,客户端先连上服务器,连接不断开。客户端再发信息不用建立连接
1) Asmack 就是长连接框架,是做聊天应用的客户端的框架
2) Openfire服务器,类似于tomcat,tomcat是短连接,客户端请求,tomcat返回网页,openfire是长连接,把一个用户聊天说的话主动推送给所有人。

一,先将asmack-src源码文件里面的全部文件 拷贝到自己的项目 src里面,直接到工作空间里面覆盖
Asmack 聊天框架 使用(一)_第1张图片
二,建聊天服务器 用openfire_3_8_1

因为连接是只要打开应用程序,建立连接之后,就会一直连着。所以放在Application 中 做成全局变量


public class TApplication extends Application {
    static XMPPConnection xmppConnection;
    public static MultiUserChat multiUserchat;

    @Override
    public void onCreate() {
        super.onCreate();
        int threadId = (int) Thread.currentThread().getId();
        Log.i("openfire", Thread.currentThread().getId()
                + " application onCreate");
        // 设置服务器信息
        ConnectionConfiguration configuration = new ConnectionConfiguration(
                "服务器IP地址", 服务器端口号, "服务器的域");
        // 创立连接 
        xmppConnection = new XMPPConnection(configuration);
        // 连接openfire 服务器 
        new Thread() {
            public void run() {
                try {
                    Log.i("openfire", "new XMPPConnection")
                    // 2.4 让框架中的接口指向实现类
                    MyPacketListener myPacketListener = new MyPacketListener();
                    xmppConnection.addPacketListener(myPacketListener, null);
                    //连上连接
                    xmppConnection.connect();
                    Log.i("openfire", Thread.currentThread().getId() + " 连接成功");



                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } finally {
                    synchronized (TApplication.class) {
                        TApplication.class.notify();
                        Log.i("openfire", Thread.currentThread().getId()
                                + " 有人notify");

                    }
                }
            };
        }.start();
    }

    // 2.3 写实现类
    class MyPacketListener implements PacketListener {

        @Override
        public void processPacket(Packet packet) {
            try {
                // packet 数据包,服务器返回的数据
                String objectInfo = packet.toString();
                String data = packet.toXML();
                Log.i("服务器发过来的数据", objectInfo);
                Log.i("服务器发过来的数据", data);

                // 判断数据是不是message
                if (packet instanceof Message) {

                    Message msg = (Message) packet;
                    // 调用activity显示数据
                    MainActivity.instance.showMessage(msg);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

        }

    }
}

在Activity中


public class MainActivity extends Activity {
EditText etBody;
public static LinearLayout linearLayout;
public static MainActivity instance;

ScrollView scrollView;
Handler handler =new Handler();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        instance=this;
        setContentView(R.layout.activity_main);
        //初始化控件
        etBody=(EditText) findViewById(R.id.etBody);
        scrollView=(ScrollView) findViewById(R.id.scrollView1);
        linearLayout=(LinearLayout) findViewById(R.id.linearLayout);
    }
    //发送图片
    public void sendImage(View v){
        try {
            //读取sdcard卡跟目录
            String sdcard_root=Environment.getExternalStorageDirectory().getAbsolutePath();
            String filePath=sdcard_root+"/logo4.png";
            FileInputStream fileInputStream=new FileInputStream(filePath);
            //从文件中读到的是byte[]
            //数据大小
            int size=fileInputStream.available();
            byte[] data=new byte[size];
            fileInputStream.read(data);
            //把byte[]变成Sing 
            //String string=new String(data);
            //对方是android收到后 string.getBytes()-->bitmap
            //对方是iphone,用base64
            //base64在iphone上也能用
            //把byte[]变成字符串
            String string=Base64.encodeToString(data, Base64.DEFAULT);
            //字符串前边加个标记 iamge
            string="image"+string;
            //发送
            TApplication.multiUserchat.sendMessage(string);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    // 发送文本 文字
    public void sendText(View v)
    {
        try {
            String body=etBody.getText().toString();
            //发内容前加标记tag,告诉收到的人这个信息是text
            body="text"+body;
            //发给openfire,openfire会把内容发给所有人
            TApplication.multiUserchat.sendMessage(body);

            //显示在我的屏幕上
            //TextView tv=new TextView(this);
            //tv.setText(body);
            //linearLayout.addView(tv);
        } catch (XMPPException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }
    // 把服务器发给我的信息 显示在屏幕上
    public void showMessage(Message msg)
    {

        // 得到from ,body
        //from 是昵称
        final String from = msg.getFrom();
        final String body = msg.getBody();
        if (body == null) {
            return;
        }
        if (MainActivity.instance != null) {
            //在主线程更新UI
            MainActivity.instance.runOnUiThread(new Runnable() {

                @Override
                public void run() {
                    try {
                        // 运行在主线程
                        // textView
                        int threadId = (int) Thread.currentThread().getId();
                        // 判断收到的是文本还是图
                        if (body.startsWith("image")) {
                            // 收到的图,实际收到的是用base64编码出来的string
                            // 去掉前面image
                            String image = body.substring(5);
                            byte[] data = Base64.decode(image,Base64.DEFAULT);
                            // byte[]-->bitmap;
                            Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0,data.length);

                            ImageView imageView = new ImageView(MainActivity.instance);
                            imageView.setImageBitmap(bitmap);
                            MainActivity.instance.linearLayout.addView(imageView);
                        } else if (body.startsWith("text")) {
                        //判断是文字
                            TextView tv = new TextView(MainActivity.instance);
                            // 去掉前面加的text
                            tv.setText(from + ":"+ body.substring(4));

                            // linearLayout
                            MainActivity.linearLayout.addView(tv);
                        }
                        //自动向上移
                        //最后一行不显示,解决方案 sleep(延迟)之后再向上移
                        // 因为在主线程 需要把所有的消息都放到消息队列,这个过程需要点时间。
                        //所以需要延迟一些时间,然后让线程计算linearLayout高度,再移动到最后一条消息的位置
                        Log.i("执行顺序", Thread.currentThread().getId()+" 1");
                        handler.postDelayed(new Runnable() {

                            @Override
                            public void run() {
                                Log.i("执行顺序", Thread.currentThread().getId()+" 2");
                                //向上移动,得linearLayout高度
                                scrollView.fullScroll(ScrollView.FOCUS_DOWN);
                                }
                        }, 0);//在samsung s4真机上,时间不能是0 
                        Log.i("执行顺序", Thread.currentThread().getId()+" 3");
                        // 执行顺序是1 3 2
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            });

        }

    }

}

LogActivity 是负责登录的业务 ,在这个业务里面,TApplication 建立连接跟 登录业务不是一个线程
这就产生了 有先有后的次序,有可能登录的线程比建立连接的线程更快,就产生了登录失败的结果。
为了避免出现这种情况, 就需要用到 wait() 与 Notify() 等待 与通知方法。不能用延迟的方法
postDelayed(),因为用户可能要输入用户名与密码,这已经跟建立连接的线程产生时间差了,就不需要再延迟了。
所以现在用到了 如果建立连接不成功,就先等待,等通知的方法。


public class LoginActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    //登录需要启工作线程,
        new Thread() {
            public void run() {
                try {
                    // 登录服务器
                    Log.i("openfire", Thread.currentThread().getId() + " 开始登录 "
                            + TApplication.xmppConnection);
                    // 开始登录前要判断连接是否成功
                    if (TApplication.xmppConnection.isConnected() == false) {
                        // 不成功,等
                        synchronized (TApplication.class) {
                            Log.i("openfire", Thread.currentThread().getId()+ " 开始wait");

                            TApplication.class.wait();
                        }
                    }

                    Log.i("openfire", Thread.currentThread().getId()+ " 有人notify,继续执行login");

                    TApplication.xmppConnection.login("UserName", "pwd");
                    boolean isSuccess = TApplication.xmppConnection.isAuthenticated();
                    //如果打印下边的这句话 true 登录成功 
                    Log.i("openfire", "登录结果" + isSuccess);

                    // 进到群Multi多
                    String room = "房间号@conference.服务器域";
                    multiUserchat = new MultiUserChat(TApplication.xmppConnection, room);
                    multiUserchat.join("昵称");
                    //测试
                    // multiUserchat.sendMessage("能看到我从android发的内容吗");
                    // 登录成功之后 需要从登录界面转到发送消息界面
                    LoginActivity.this.runOnUiThread(new Runnable() {

                        @Override
                        public void run() {
                            startActivity(new Intent(LoginActivity.this,MainActivity.class));
                        }
                    });
                } catch (Exception e) {
                    e.printStackTrace();
                }
            };
        }.start();
        super.onCreate(savedInstanceState);
        setContentView(R.layout.login);
    }

}

你可能感兴趣的:(框架,asmack)