websocket的使用
上一篇我写的是notifation通知的使用,这篇呢,介绍下websocket实现即时通讯
首先在这里说下websocket
WebSocket 是 HTML5 一种新的协议。它实现了浏览器与服务器全双工通信,能更好的节省服务器资源和带宽并达到实时通讯,它建立在 TCP 之上,同 HTTP 一样通过 TCP 来传输数据,但是它和 HTTP 最大不同是:
- WebSocket 是一种双向通信协议,在建立连接后,WebSocket 服务器和 Browser/Client Agent 都能主动的向对方发送或接收数据,就像 Socket 一样;
- WebSocket 需要类似 TCP 的客户端和服务器端通过握手连接,连接成功后才能相互通信。
- 如果想深入了解websocket机制和原理:http://www.ibm.com/developerworks/cn/java/j-lo-WebSocket/
废话不多说,以下步骤
1、添加网络权限,在通信的过程中我们都需要notifaction进行提示,所以还得加上notifaction所需权限
<!-- 网络权限 --> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.VIBRATE" /> <uses-permission android:name="android.permission.READ_PHONE_STATE" />
2、创建服务service,有人会问,为什么还需要服务,我想这个问题我可能不用过多的解释大家应该都明白
3、建立websocket连接,启动服务,startService的时候建立连接
配置Service文件内容
<service android:name=".chat.MyService" android:enabled="true" android:persistent="true"/>MyService.class
package com.zy.fire.ui.chat; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Service; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.os.Binder; import android.os.Bundle; import android.os.IBinder; import android.os.Message; import android.os.Vibrator; import android.support.v4.app.NotificationCompat; import android.util.Log; import com.zy.fire.ui.R; import org.java_websocket.WebSocketImpl; import org.java_websocket.client.WebSocketClient; import org.java_websocket.drafts.Draft_17; import org.java_websocket.handshake.ServerHandshake; import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; public class MyService extends Service { public static WebSocketClient client; private ConnectivityManager connectivityManager; private NetworkInfo info; private ArrayList<String> msgQueen = new ArrayList<String>(); private boolean isSaveInSrevice = true; private MyBinder mBinder = new MyBinder(); private boolean iscon = true;//用于在broadcast中判断是否是需要重新连接的 private NotificationManager manager; private NotificationCompat.Builder notifyBuilder; private Vibrator vibrator; @Override public void onCreate() { super.onCreate(); manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); IntentFilter mFilter = new IntentFilter(); mFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); registerReceiver(mReceiver, mFilter); } @Override public int onStartCommand(Intent intent, int flags, int startId) { String deviceID = SystemTool.phoneDeviceID(this); String address = "ws://192.168.3.5:8080/COMM/socket?" + "userId=123456ghjgjh789" + "&deviceNO=android_" + deviceID; try { WebSocketImpl.DEBUG = true; System.setProperty("java.net.preferIPv6Addresses", "false"); System.setProperty("java.net.preferIPv4Stack", "true"); client = new WebSocketClient(new URI(address), new Draft_17()) { @Override public void onOpen(final ServerHandshake serverHandshakeData) { iscon = true; if (!isSaveInSrevice) { Message msg = new Message(); msg.what = ChatClientActivity.ONOPEN; ChatClientActivity.uihandler.sendMessage(msg); } else { Log.e("wz", "没有打开activity是的Onopen+1"); } } @Override public void onMessage(final String message) { //接受到消息就发送震动 openVibrator(); //判断activity是否是在最前端,如果是就将消息直接传给activity,如果不是就保存在service中 //并且发送 if (!isSaveInSrevice) { Message msg = new Message(); msg.what = ChatClientActivity.ONMESSEGE; Bundle b = new Bundle(); b.putString("msg", message); msg.setData(b); ChatClientActivity.uihandler.sendMessage(msg); } else { msgQueen.add(message); //发送通知 sendNotification(); Log.e("wz", message); } } @Override public void onClose(final int code, final String reason, final boolean remote) { iscon = false; if (!isSaveInSrevice) { Message msg = new Message(); msg.what = ChatClientActivity.ONCLOSE; ChatClientActivity.uihandler.sendMessage(msg); } else { Log.e("wz", "没有activity时的" + " onClose"); } } @Override public void onError(final Exception e) { iscon = false; client.close(); Log.e("wz", String.valueOf(e)); } }; } catch (URISyntaxException e) { e.printStackTrace(); } client.connect(); return super.onStartCommand(intent, flags, startId); } private void openVibrator() { vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE); long[] pattern = {100, 400, 100, 400}; // 停止 开启 停止 开启 vibrator.vibrate(pattern, -1); //重复两次上面的pattern 如果只想震动一次,index设为-1 } @Override public boolean onUnbind(Intent intent) { mBinder.setIsSaveInSer(); return super.onUnbind(intent); } @Override public void onDestroy() { super.onDestroy(); Log.e("wz", "+++++++++++Srevice Destroy++++++++++"); } @Override public IBinder onBind(Intent intent) { return mBinder; } /** * 接受到网络重连的广播时重新执行startcommoned方法让client重连 */ private BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) { connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); info = connectivityManager.getActiveNetworkInfo(); if (info != null && info.isAvailable() && iscon == false) { //断网的时候client会被close (调用了onclose方法) Intent serviceIntent = new Intent(context, MyService.class); context.startService(serviceIntent); // client.connect(); //不能用client直接connect,具体原因期待有人指出,可能是classnotfind? Log.e("wz", "StartService"); } } } }; /** * 实现1.act到屏幕最前方时将保存在service中的msg向UI发送 * 2.act不再屏幕最前方时通知service保存消息 */ class MyBinder extends Binder { public void sendToUI() { Message msg = new Message(); msg.what = ChatClientActivity.ONMESSEGELIST; Bundle b = new Bundle(); ArrayList l = new ArrayList(); l.addAll(msgQueen); b.putParcelableArrayList("list", l); msg.setData(b); ChatClientActivity.uihandler.sendMessage(msg); isSaveInSrevice = false; msgQueen.clear(); manager.cancel(121); } public void setIsSaveInSer() { isSaveInSrevice = true; } } //发送notification private void sendNotification() { //点击的意图ACTION是跳转到Intent Log.e("wz", "sendNotification"); Intent resultIntent = new Intent(this, ChatClientActivity.class); resultIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, resultIntent, PendingIntent.FLAG_UPDATE_CURRENT); Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher); notifyBuilder = new NotificationCompat.Builder(this) /*设置large icon*/ .setLargeIcon(bitmap) /*设置small icon*/ .setSmallIcon(R.mipmap.ic_launcher) /*设置title*/ .setContentTitle("您收到了" + String.valueOf(msgQueen.size()) + "条消息") /*设置详细文本*/ .setContentText(msgQueen.get(msgQueen.size() - 1)) /*设置发出通知的时间为发出通知时的系统时间*/ .setWhen(System.currentTimeMillis()) /*设置发出通知时在status bar进行提醒*/ .setTicker("收到新消息") /*setOngoing(boolean)设为true,notification将无法通过左右滑动的方式清除 * 可用于添加常驻通知,必须调用cancle方法来清除 */ .setOngoing(false) /*设置点击后通知消失*/ .setAutoCancel(true) /*设置通知数量的显示类似于QQ那种,用于同志的合并*/ // .setNumber(3) /*点击跳转到MainActivity*/ .setContentIntent(pendingIntent); manager.notify(121, notifyBuilder.build()); } }
4、实现长连接
为啥还要长连接呢,可能有人会问,这是防止在一段时候后websocket断开,导致接受不到消息,和发送不出消息 ,大家可以使用下两种方法去实现
<1>service +Thread
<2>service+AlarmManager+Thread
参考:http://blog.youkuaiyun.com/mingzhnglei/article/details/53464001
5、如果需要开机启动服务
在applicaton类里初始化启动服务
Intent i = new Intent(this, MyService.class); this.startService(i);