【达内课程】asmack框架(下)

让聊天显示在屏幕上

过程分析
在这里插入图片描述

获取聊天内容

MyApplication

public class MyApplication extends Application {
    ......
    @Override
    public void onCreate() {
        super.onCreate();
        //连接服务器,起一个线程
        new Thread() {
            @Override
            public void run() {
                try {
                    ......

                    //让框架的接口指向实现类
                    MyPacketListener listener = new MyPacketListener();
                    xmppConnection.addPacketListener(listener,null);
                } catch (XMPPException e) {
                    e.printStackTrace();
                }
            }
        }.start();
    }

    class MyPacketListener implements PacketListener{
        @Override
        public void processPacket(Packet packet) {
            //packet包,openfire发过来的数据包
            //判断是不是聊天内容
            if(packet instanceof Message){
                Message msg = (Message)packet;
                String from = msg.getFrom();
                String body = msg.getBody();
                Log.i("MyPacketListener","from:"+from+",body:"+body);
            }
        }
    }
}

当在屏幕上发送
在这里插入图片描述
查看打印日志
在这里插入图片描述

显示在屏幕

MainActivity中写一个接收器,当收到广播后,LinearLayout将动态添加内容

public class MainActivity extends AppCompatActivity {
    ......
    LinearLayout linearLayout;
    ShowMessageReceiver showMessageReceiver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
		......

        scrollView = findViewById(R.id.scroll_view);
        linearLayout = findViewById(R.id.ll_content);
        //注册接收器
        showMessageReceiver = new ShowMessageReceiver();
        registerReceiver(showMessageReceiver,new IntentFilter("showMessage"));
    }

    @Override
    protected void onDestroy() {
        //注销接收器
        this.unregisterReceiver(showMessageReceiver);
        super.onDestroy();
    }

	......

    class  ShowMessageReceiver extends BroadcastReceiver{

        @Override
        public void onReceive(Context context, Intent intent) {
            String from = intent.getStringExtra("from");
            String body = intent.getStringExtra("body");
            TextView textView = new TextView(context);
            textView.setText(from+":"+body);
            linearLayout.addView(textView);
        }
    }
}

MyApplication中获取内容后,发送广播

class MyPacketListener implements PacketListener{
        @Override
        public void processPacket(Packet packet) {
            if(packet instanceof Message){
               ......

                //发广播给接收器
                Intent intent = new Intent("showMessage");
                intent.putExtra("from",from);
                intent.putExtra("body",body);
                sendBroadcast(intent);
            }
        }
    }

在这里插入图片描述

发送图片

我们向服务器发的信息,实际上是xml
在MyApplication中的MyPacketListener里打印看一下

Log.i("MyPacketListener",packet.toXML());
<message 
	id="J06zI-5" 
	to="spark@127.0.0.1/Smack" 
	from="729@conference.127.0.0.1/Errol_King" 
	type="groupchat">
		<body>少用塑料袋</body>
		<stanza-id xmlns="urn:xmpp:sid:0"></stanza-id>
</message>

我们在assets文件夹放一个“study.jpg”图片

在布局上加一个发送图片的按钮,点击执行sendImage()来发送图片
MainActivity中主要代码:

public class MainActivity extends AppCompatActivity {
    ......
    Button buttonImg;
    ......

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
		......
        buttonImg = findViewById(R.id.send_img);
        buttonImg.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                sendImg();
            }
        });
    }

	......

    private void sendImg() {
        try {
            //读取assets下的图片
            AssetManager manager = getAssets();
            InputStream inputStream = manager.open("study.jpg");
            int size = inputStream.available();
            byte[] data = new byte[size];
            inputStream.read(data);
            //图片转成文字
            //base64:跨语言的编码方式
            String str = Base64.encodeToString(data,Base64.DEFAULT);
            //发送时加tag标记表示数据类型
            str = "<image>"+str;
            //发送
            MyApplication.multiUserChat.sendMessage(str);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (XMPPException e) {
            e.printStackTrace();
        }
    }

    class  ShowMessageReceiver extends BroadcastReceiver{

        @Override
        public void onReceive(Context context, Intent intent) {
            String from = intent.getStringExtra("from");
            String body = intent.getStringExtra("body");
            //根据tag判断数据的类型
            if(body != null && body.startsWith("<text>")){
                body = body.substring("<text>".length());
                TextView textView = new TextView(context);
                textView.setText(from+":"+body);
                linearLayout.addView(textView);
            }
            if(body != null && body.startsWith("<image>")){
                //把前边的<Image>去掉
                body = body.substring("<image>".length());
                //把字符串转为byte[]
                byte[] data = Base64.decode(body,Base64.DEFAULT);
                //创建bitmap
                Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
                //创建ImageView
                ImageView imageView = new ImageView(context);
                imageView.setImageBitmap(bitmap);
                //把ImageView放到LinearLayout
                linearLayout.addView(imageView);
            }
        }
    }
}

在这里插入图片描述

ScrollView向上移动

在这里插入图片描述
MainActivity关键代码

class  ShowMessageReceiver extends BroadcastReceiver{

        @Override
        public void onReceive(Context context, Intent intent) {
            ......
            //scrollview向上移动
            //最后的内容得不到,解决方法是,等一会儿再取值
            Handler handler = new Handler();
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    //因为ScrollView已经显示出来了,所以调用getHeight()来直接获取高度
                    int scrollViewHeight  = scrollView.getHeight();
                    int linearLayoutHeight = linearLayout.getHeight();
                    Log.d("向上移","scrollViewHeight:"+scrollViewHeight+",linearLayoutHeight"+linearLayoutHeight);
                    if(linearLayoutHeight > scrollViewHeight){
                        int y = linearLayoutHeight - scrollViewHeight;
                        scrollView.scrollTo(0,y);
                    }
                }
            },10);
        }
    }

在这里插入图片描述

多线程

创建LoginBiz,用来处理登录,把MyApplication中的3、4步拿过来

public class LoginBiz {
    public void login(final LoginActivity activity){
        new Thread(){
            @Override
            public void run() {
                try {
                    //3.登录
                    MyApplication.xmppConnection.login("spark","123456");
                    //4.加入群聊
                    String room = "729@conference.127.0.0.1";
                    MyApplication.multiUserChat = new MultiUserChat(MyApplication.xmppConnection,room);
                    MyApplication.multiUserChat.join("Errol_King");

                } catch (XMPPException e) {
                    e.printStackTrace();
                }
            }
        }.start();
    };
}

创建LoginActivity

public class LoginActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        LoginBiz loginBiz = new LoginBiz();
        loginBiz.login(this);
    }
}

布局activity_login.xml 暂不写

修改AndroidManifest,修改启动页,同时注册MainActivity

 <activity android:name=".LoginActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".MainActivity"/>

同时MyApplication中,要把创建ConnectionConfiguration拿到new Thread上面,由于之前创建和LoginBiz是两个线程,防止使用时为null

public class MyApplication extends Application {
    ......
    @Override
    public void onCreate() {
        super.onCreate();
        //由于MyApplication和LoginBiz是两个线程,为了防止LoginBiz使用xmppConnection时为null,把初始化拿到创建线程外
        //1.设置服务器信息
        ConnectionConfiguration configuration = new ConnectionConfiguration("10.0.2.2", 5222, "Spark");
        //2.连接上服务器
        xmppConnection = new XMPPConnection(configuration);

        //连接服务器,起一个线程
        new Thread() {
            @Override
            public void run() {
                try {
                    xmppConnection.connect();
                    Log.d("多线程","");
                    //让框架的接口指向实现类
                    MyPacketListener listener = new MyPacketListener();
                    xmppConnection.addPacketListener(listener,null);
                } catch (XMPPException e) {
                    e.printStackTrace();
                }
            }
        }.start();
    }
}

还有一个问题就是
在这里插入图片描述
当LoginBiz中的login执行时,另一个线程的connect可能还没成功(服务器还没连接成功),为了解决这个问题,加一个锁

public class MyApplication extends Application {
  	......
    //对象锁
    public static Object objLock = new Object();

    @Override
    public void onCreate() {
        super.onCreate();
        ......

        //连接服务器,起一个线程
        new Thread() {
            @Override
            public void run() {
                try {
                    xmppConnection.connect();

                    //让框架的接口指向实现类
                    MyPacketListener listener = new MyPacketListener();
                    xmppConnection.addPacketListener(listener,null);
                } catch (XMPPException e) {
                    e.printStackTrace();
                } finally {
                    //连上后,notify
                    synchronized (objLock){
                        objLock.notify();
                        Log.d("多线程","连接成功,"+getId()+",发出了notify");
                    }
                }
            }
        }.start();
    }
    ......
}

LoginBiz

public class LoginBiz {
    public void login(final LoginActivity activity){
        new Thread(){
            @Override
            public void run() {
                try {
                    //登录的时候判断连接线程是否连接成功
                    if(!MyApplication.xmppConnection.isConnected()){
                        //没连上
                        synchronized (MyApplication.objLock){
                            Log.d("多线程",getId()+"没连上,开始等待");
                            //等
                            MyApplication.objLock.wait();
                        }
                    }
                    //3.登录
                    Log.d("多线程",getId()+"已经有人notify,不再等,可以执行登录了");
                    MyApplication.xmppConnection.login("spark","123456");
                    ......

                } catch (XMPPException e) {
                    e.printStackTrace();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }.start();
    };
}

在这里插入图片描述

值得注意的是wait()后的代码是不执行的

登录成功后跳转

LoginActivity中增加跳转方法

public class LoginActivity extends Activity {
	......
    public void handleResult(){
        startActivity(new Intent(this,MainActivity.class));
    }
}

LoginBiz中

public class LoginBiz {
    public void login(final LoginActivity activity){
        new Thread(){
            @Override
            public void run() {
                try {
                    ......
                } catch (XMPPException e) {
                    e.printStackTrace();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    activity.handleResult();
                }
            }
        }.start();
    };
}

源码下载

https://download.csdn.net/download/u010356768/11457897

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值