公司让我研究websocket,利用这个时间写了个仿微信的demo。

服务器端功能比较简单:转发给所有的client (类似与群聊)

android端功能:service后台接受消息;broadcastreceived监测网络连接断:断网时给出提示,重连时重新执行service中的websocket方法;接受到消息时如果activity没有在最前端发送notification通知用户。

要点:service将消息传递给activity使用的是activity中的全局handler

activity通service是否在屏幕最前时使用的binder对象,activity的onResum方法绑定service,onpause方法解绑service,来通知service是否需要保存消息并且发送notification。每次绑定后都查询一下service是否存着消息没有显示出来。

service中动态注册一个广播接收器来监听网络连接的状态

先看服务器端代码:

<pre name="code" class="java">/*** @author mace* @email 631534395@qq.com*/
public class ChatServer extends WebSocketServer {public ChatServer(int port) throws UnknownHostException {super(new InetSocketAddress(port));}public ChatServer(InetSocketAddress address) {super(address);}@Overridepublic void onOpen(WebSocket conn, ClientHandshake handshake) {sendToAll(conn.getRemoteSocketAddress().getAddress().getHostAddress()+ " 进入房间 !");System.out.println(conn.getRemoteSocketAddress().getAddress().getHostAddress()+ " 进入房间 !");}@Overridepublic void onClose(WebSocket conn, int code, String reason, boolean remote) {sendToAll(conn.getRemoteSocketAddress().getAddress().getHostAddress()+ " 离开房间 !");System.out.println(conn.getRemoteSocketAddress().getAddress().getHostAddress()+ " 离开房间 !");}@Overridepublic void onMessage(WebSocket conn, String message) {sendToAll("["+ conn.getRemoteSocketAddress().getAddress().getHostAddress()+ "]" + message);System.out.println("["+ conn.getRemoteSocketAddress().getAddress().getHostAddress()+ "]" + message);}@Overridepublic void onError(WebSocket conn, Exception e) {e.printStackTrace();if (conn != null) {System.out.println( String.valueOf(e));conn.close();}}// 发送给所有的聊天者private void sendToAll(String text) {Collection<WebSocket> conns = connections();synchronized (conns) {for (WebSocket client : conns) {client.send(text);}}}// 测试public static void main(String[] args) throws InterruptedException,IOException {int port = 8887;ChatServer server = new ChatServer(port);server.start();System.out.println("房间已开启,等待客户端接入,端口号: " + server.getPort());BufferedReader webSocketIn = new BufferedReader(new InputStreamReader(System.in));while (true) {String stringIn = webSocketIn.readLine();server.sendToAll(stringIn);}}
}

下面详解android端的代码

service:service在Application中start,从程序一启动就开始运行

</pre><pre code_snippet_id="1727119" snippet_file_name="blog_20160623_4_78510" name="code" class="java"><pre name="code" class="java">/*** @author mace* @email 631534395@qq.com*/
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;@Overridepublic void onCreate() {super.onCreate();manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);IntentFilter mFilter = new IntentFilter();mFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);registerReceiver(mReceiver, mFilter);}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {String address = "ws://192.168.31.184:8887";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()) {@Overridepublic void onOpen(final ServerHandshake serverHandshakeData) {iscon = true;if (!isSaveInSrevice) {Message msg = new Message();msg.what = ChatClientActivity.ONOPEN;ChatClientActivity.uihandler.sendMessage(msg);} else {Log.e("Mace", "没有打开activity是的Onopen+1");}}@Overridepublic 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("Mace", message);}}@Overridepublic 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("Mace", "没有activity时的" + " onClose");}}@Overridepublic void onError(final Exception e) {iscon = false;client.close();Log.e("Mace", 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}@Overridepublic boolean onUnbind(Intent intent) {mBinder.setIsSaveInSer();return super.onUnbind(intent);}@Overridepublic void onDestroy() {super.onDestroy();Log.e("Mace", "+++++++++++Srevice Destroy++++++++++");}@Overridepublic IBinder onBind(Intent intent) {return mBinder;}/*** 接受到网络重连的广播时重新执行startcommoned方法让client重连*/private BroadcastReceiver mReceiver = new BroadcastReceiver() {@Overridepublic 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("Mace", "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;}}//发送notificationprivate void sendNotification() {//点击的意图ACTION是跳转到IntentLog.e("Mace", "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.a);notifyBuilder = new NotificationCompat.Builder(this)/*设置large icon*/.setLargeIcon(bitmap)/*设置small icon*/.setSmallIcon(R.mipmap.a)/*设置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());}}

activity中代码:

/*** @author mace* @email 631534395@qq.com*/
public class ChatClientActivity extends AppCompatActivity implements OnClickListener {public static int ONMESSEGE = 1;public static int ONMESSEGELIST = 2;public static int ONCLOSE = -1;public static int ONOPEN = 0;private ScrollView svChat;private EditText etDetails;private EditText etName;private EditText etMessage;private Button btnSend;private TextView closetv;private long exitTime = 0;private MyService.MyBinder myBinder;private ServiceConnection connection = new ServiceConnection() {@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {myBinder = (MyService.MyBinder) service;myBinder.sendToUI();Log.e("Mace", "onServiceConnected");}@Overridepublic void onServiceDisconnected(ComponentName name) {}};public static MyHandler uihandler;//activity回到最前端时连接service进行通信@Overrideprotected void onResume() {super.onResume();Intent bindIntent = new Intent(this, MyService.class);bindService(bindIntent, connection, BIND_AUTO_CREATE);}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);uihandler = new MyHandler();setContentView(R.layout.activity_chat_client);svChat = (ScrollView) findViewById(R.id.svChat);etDetails = (EditText) findViewById(R.id.etDetails);etName = (EditText) findViewById(R.id.etName);etMessage = (EditText) findViewById(R.id.etMessage);btnSend = (Button) findViewById(R.id.btnSend);btnSend.setOnClickListener(this);closetv = (TextView) findViewById(R.id.onClose);}@Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.btnSend:try {if (MyService.client != null) {Log.e("Mace", "btnSend" + String.valueOf(Thread.currentThread().getId()));MyService.client.send(etName.getText().toString().trim() + "说:" + etMessage.getText().toString().trim());svChat.post(new Runnable() {@Overridepublic void run() {svChat.fullScroll(View.FOCUS_DOWN);etMessage.setText("");etMessage.requestFocus();}});}} catch (Exception e) {e.printStackTrace();}break;}}@Overrideprotected void onPause() {super.onPause();unbindService(connection);}public boolean onKeyDown(int keyCode, KeyEvent event) {if (keyCode == KeyEvent.KEYCODE_BACK) {exit();return false;}return super.onKeyDown(keyCode, event);}public void exit() {if ((System.currentTimeMillis() - exitTime) > 2000) {Toast.makeText(getApplicationContext(), "再按一次退出程序",Toast.LENGTH_SHORT).show();exitTime = System.currentTimeMillis();} else {finish();}}//接受service传来的内容,并相应的修改UIclass MyHandler extends Handler {@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);if (msg.what == ONMESSEGE) {addChatMessage(String.valueOf(msg.getData().get("msg")));} else if (msg.what == ONCLOSE) {setConClose();} else if (msg.what == ONOPEN) {setConOpen();} else if (msg.what == ONMESSEGELIST) {ArrayList msgList = msg.getData().getParcelableArrayList("list");String s = "";for (int i = 0; i < msgList.size(); i++) {s = (String) msgList.get(i);addChatMessage(s);}}}}//添加message进入对话框public void addChatMessage(String msg) {etDetails.append(msg + "\n");}//连接关闭时的界面public void setConClose() {btnSend.setEnabled(false);closetv.setVisibility(View.VISIBLE);}//连接可用时的界面public void setConOpen() {btnSend.setEnabled(true);closetv.setVisibility(View.GONE);}
}

manifest文件

<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="org.wlf.websocket"><!-- 网络权限 --><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" /><applicationandroid:name=".MyApplication"android:allowBackup="true"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:theme="@style/AppTheme"><activityandroid:name=".ChatClientActivity"android:windowSoftInputMode="stateHidden|adjustResize"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity><serviceandroid:name=".MyService"android:enabled="true"android:persistent="true"></service></application></manifest>

欢迎各路大神指出不足,大家共同提高 \(^o^)/

demo实例:

http://download.csdn.net/detail/mace_android/9558242

详解android高仿微信后台接受消息,发送通知,监测网络连接相关推荐

  1. Android 高仿微信 你可能要发送的图片

    微信发送图片有个功能,就是当你拍完照片,或者保存一个张照片的时候,你点击聊天框的"+"号,微信会有个提示,你可能要发送的图片,并且附上相应的图片.要实现这个功能,分两个步骤. 1, ...

  2. android+高仿视频录制,android高仿微信视频编辑页

    android高仿微信视频编辑页-视频多张图片提取 上一篇中介绍了有关视频提取图片的知识点,如果对这个不太了解 建议看下android提取视频多张图片和视频信息之前这篇. 这里实现的是仿微信的视频编辑 ...

  3. php支付密码控件,Android高仿微信支付密码输入控件实例代码

    这篇文章主要为大家详细介绍了Android高仿微信支付密码输入控件的具体实现代码,供大家参考,具体内容如下 像微信支付密码控件,在app中是一个多么司空见惯的功能.最近,项目需要这个功能,于是乎就实现 ...

  4. android高仿微信视频编辑页-视频多张图片提取

    android高仿微信视频编辑页-视频多张图片提取 上一篇中介绍了有关视频提取图片的知识点,如果对这个不太了解 建议看下android提取视频多张图片和视频信息之前这篇. 这里实现的是仿微信的视频编辑 ...

  5. android仿微信聊天功能,Android高仿微信聊天界面代码分享

    微信聊天现在非常火,是因其界面漂亮吗,哈哈,也许吧.微信每条消息都带有一个气泡,非常迷人,看起来感觉实现起来非常难,其实并不难.下面小编给大家分享实现代码. 先给大家展示下实现效果图: OK,下面我们 ...

  6. android 微信高仿,Android高仿微信聊天界面代码分享

    微信聊天现在非常火,是因其界面漂亮吗,哈哈,也许吧.微信每条消息都带有一个气泡,非常迷人,看起来感觉实现起来非常难,其实并不难.下面小编给大家分享实现代码. 先给大家展示下实现效果图: OK,下面我们 ...

  7. android com.mylhyl,Android 高仿微信朋友圈拍照上传功能

    模仿微信朋友圈发布动态,输入文字支持文字多少高度自增,有一个最小输入框高度,输入文字有限制,不过这些都很easy! 1. photopicker的使用 这是一个支持选择多张图片,点击图片放大,图片之间 ...

  8. android高仿微信聊天页面,Android 高仿微信语音聊天页面高斯模糊(毛玻璃效果)

    目前的应用市场上,使用毛玻璃效果的APP随处可见,比如用过微信语音聊天的人可以发现,语音聊天页面就使用了高斯模糊效果. 先看下效果图: 仔细观察上图,我们可以发现,背景图以用户头像为模板,对其进行了高 ...

  9. android仿微信充值布局,Android 高仿微信支付数字键盘功能

    现在很多app的支付.输入密码功能,都已经开始使用自定义数字键盘,不仅更加方便.其效果着实精致. 下面带着大家学习下,如何高仿微信的数字键盘,可以拿来直接用在自身的项目中. 先看下效果图: 1. 自定 ...

最新文章

  1. Android Studio第三十四期 - git企业级应用命令
  2. 服务器mysql在哪里_mysql的服务器在哪里
  3. Codeforces 500
  4. 平均值,方差计算(sss)
  5. UOJ #268 BZOJ 4732 [清华集训2016]数据交互 (树链剖分、线段树)
  6. java面向对象高级分层实例_实体类
  7. R学习-- 数组和矩阵
  8. 北京环球度假区:尚未发布票务信息,未面向公众销售任何门票
  9. list排序成员函数对string对象与char*对象排序的差别
  10. Mobile Widget——让开发移动应用就像做网页
  11. Python numpy中矩阵的用法总结
  12. 【jmeter安装】jmeter下载安装超详细简单步骤
  13. 基因表达式编程(GEP)自学 第【1】天 Python 实现
  14. 乱斗西游小白龙技能预设释放顺序
  15. 什么是操作系统?操作系统介绍
  16. 编译原理—语法制导翻译、S属性、L属性、自上而下、自下而上计算
  17. 通讯录二维码使英文变为中文
  18. 新三板上市条件有哪些
  19. 华为开发者联盟上架Android 安装包 包名重复问题
  20. Open-unmix测试demo

热门文章

  1. 基于三菱PLC的饮料售货机控制系统设计
  2. 论文解读|算子分裂算法中的安德森加速法
  3. 35岁的腾讯测试员退休?答:存够2千万回家买房
  4. testlink mysql_记一下TestLink遇到的连接数据方面的一个问题
  5. Java udp的使用和编写简单聊天小程序
  6. 如何解决excel打印预览不可用的问题
  7. Coding Stlye
  8. win10系统盘制作和 ubuntu 20 装机体验之旅: Nouveau 禁用、Cuda安装
  9. Part I 空气曲棍球 Chapter8(Building Simple Objects)
  10. 博科 5300 光纤交换机配置