`
pjwqq
  • 浏览: 81305 次
社区版块
存档分类
最新评论

最简Android推送客户端模型

阅读更多

     最简单的android推送client模型,特点:读写使用同一线程,逻辑非常简单;断线重连;心跳;发消息等。要求不高的基本可以凑合用了呵呵。

 

package com.example.nbctts;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.util.Iterator;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

import com.example.nbctts.model.ITask;
import com.example.nbctts.model.RcvMsg;
import com.example.nbctts.model.SendMsg;
import com.example.nbctts.model.Status;
import com.google.gson.Gson;

/*
 * 1.Timer控制任务投放节奏
 * 2.用单线程池控制任务线程顺序执行
 * 3.用socket.setSoSocketTime(timeout)及SocketTimeoutException控制阻塞读时间
 */
public class MainActivity extends Activity {

	EditText msgEdt;
	Button sendBtn;
	TextView serverTxt;

	protected final ExecutorService singleThreadExecutor = Executors
			.newSingleThreadExecutor();
	protected final BlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>();// 任务队列
	protected Socket socket = null;
	protected Socket rcvSocket = null;
	protected BufferedReader mReader;// BufferedWriter 用于推送消息
	protected BufferedWriter mWriter;// BufferedReader 用于接收消息
	protected Gson gson = new Gson();
	protected Timer timer = new Timer();

	/*
	 * 队列中是否已有该类型的任务
	 */
	private boolean isTaskExist(int msgType) {
		Iterator<Runnable> it = queue.iterator();
		while (it.hasNext()) {
			ITask task = (ITask) it.next();
			if (task.getID() == msgType) {
				return true;
			}
		}
		return false;
	}

	/*
	 * 添加到队列,除了发送消息任务以外,其它不重复添加到队列
	 */
	private void addQueue(Runnable task) {
		int id = ((ITask) task).getID();
		try {
			if (id == Status.MSG_H) {
				queue.put(task);
			} else {
				if (!isTaskExist(id)) {
					queue.put(task);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/*
	 * 线程消息处理,提交任务到待处理队列
	 */
	public Handler myHandler = new Handler() {
		@Override
		public void handleMessage(Message msg) {
			HandlerMsg m = (HandlerMsg) msg.obj;
			switch (msg.what) {
			case Status.CONN_H:
				serverTxt.append(m.content + "\n");
				// 连接不成功,自动重连
				if (!m.successFlag) {
					timer.schedule(new TimerTask() {
						@Override
						public void run() {
							addQueue(new connTask());
						}
					}, Status.getConnIntervel());
				}
				break;
			case Status.LOGIN_H:
				serverTxt.append(m.content + "\n");
				break;
			case Status.SVRMSG_H:
				serverTxt.append(m.content + "\n");
				break;
			case Status.HEARTBEAT_H:
				// 暂不处理
				break;
			case Status.MSG_H:
				// 暂不处理
			case Status.LOGOUT_H:
				// 暂不处理
				break;
			default:
				break;
			}
		}
	};

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		msgEdt = (EditText) findViewById(R.id.msgEdt);
		sendBtn = (Button) findViewById(R.id.sendBtn);
		serverTxt = (TextView) findViewById(R.id.serverTxt);

		// 启动任务处理线程
		new TaskThread().start();
		addQueue(new connTask());
		// 定时读推送消息/心跳,这里可以分开:)
		timer.schedule(new TimerTask() {
			@Override
			public void run() {
				addQueue(new RcvTask());
				addQueue(new HeartBeatTask());
			}
		}, 1000, Status.heartBeat);

		sendBtn.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				String str = msgEdt.getText().toString();
				serverTxt.append("client:" + str + "\n");
				addQueue(new sendTask(str));
			}
		});
	}

	/*
	 * 处理的消息
	 */
	class HandlerMsg {
		public HandlerMsg(boolean successFlag, String content) {
			this.successFlag = successFlag;
			this.content = content;
		}

		private boolean successFlag;
		private String content;
	}

	/*
	 * 任务处理线程
	 */
	class TaskThread extends Thread {
		@Override
		public void run() {
			while (true) {
				if (!queue.isEmpty()) {
					try {
						singleThreadExecutor.execute(queue.take());
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		}
	}

	/*
	 * 1.连接服务器任务
	 */
	class connTask implements Runnable, ITask {
		@Override
		public void run() {
			if (!Status.isConnected) {
				socket = new Socket();
				try {
					socket.setKeepAlive(true);
					socket.setSoTimeout(Status.readBlock);
					socket.connect(
							new InetSocketAddress("169.169.43.56", 9999),
							Status.connTimeout);
					mReader = new BufferedReader(new InputStreamReader(
							socket.getInputStream(), "utf-8"));
					mWriter = new BufferedWriter(new OutputStreamWriter(
							socket.getOutputStream(), "utf-8"));
					Status.isConnected = true;
					Status.reConNum = 0;
					Message msg = new Message();
					msg.what = Status.CONN_H;
					msg.obj = new HandlerMsg(true, "connTask:已连接到服务器");
					myHandler.sendMessage(msg);
					// 连接成功,则尝试登录
					queue.add(new loginTask());
				} catch (IOException e) {
					Status.isConnected = false;
					Status.isLogin = false;
					Status.reConNum++;
					Message msg = new Message();
					msg.what = Status.CONN_H;
					msg.obj = new HandlerMsg(false, "connTask:无法连接到服务器");
					myHandler.sendMessage(msg);
				}
			}
		}

		@Override
		public int getID() {
			return Status.CONN_H;
		}
	}

	/*
	 * 2.登录到服务器任务
	 */
	class loginTask implements Runnable, ITask {
		@Override
		public void run() {
			try {
				if (Status.isConnected) {
					SendMsg sm = new SendMsg();
					sm.setOpt("LOGIN");
					sm.setUser(Status.username);
					sm.setPassword(Status.password);
					String s = gson.toJson(sm, SendMsg.class);
					mWriter.write(s + "\n");
					mWriter.flush();
					// 服务器回复
					String rs = mReader.readLine().trim();
					RcvMsg rm = gson.fromJson(rs, RcvMsg.class);
					if (rm.getContent().equals("ok")) {
						Status.isLogin = true;
						Message msg = new Message();
						msg.what = Status.LOGIN_H;
						msg.obj = new HandlerMsg(true, "loginTask:已登录到服务器");
						myHandler.sendMessage(msg);
					} else {
						Status.isLogin = false;
						Message msg = new Message();
						msg.what = Status.LOGIN_H;
						msg.obj = new HandlerMsg(false, "loginTask:登录到服务器失败:"
								+ rm.getContent());
						myHandler.sendMessage(msg);
					}
				}
			} catch (SocketTimeoutException e) {
				e.printStackTrace();
			} catch (IOException e) {
				Status.isConnected = false;
				Status.isLogin = false;
				Message msg = new Message();
				msg.what = Status.CONN_H;
				msg.obj = new HandlerMsg(false, "loginTask:无法连接到服务器");
				myHandler.sendMessage(msg);
			}
		}

		@Override
		public int getID() {
			return Status.LOGIN_H;
		}
	}

	/*
	 * 3.接收服务器消息任务
	 */
	class RcvTask implements Runnable, ITask {
		@Override
		public void run() {
			if (Status.isConnected && Status.isLogin) {
				try {
					String line = "";
					while ((line = mReader.readLine()) != null) {					
						RcvMsg rm = gson.fromJson(line, RcvMsg.class);
						// 目前只接收推来的消息
						if (rm != null && rm.getOpt().equals("SVRMSG")) {
							Message msg = new Message();
							msg.what = Status.SVRMSG_H;
							msg.obj = new HandlerMsg(true, rm.getContent());
							myHandler.sendMessage(msg);
						}
					}
				} catch (SocketTimeoutException e) {
					e.printStackTrace();
				} catch (IOException e) {
					Status.isConnected = false;
					Message msg = new Message();
					msg.what = Status.CONN_H;
					msg.obj = new HandlerMsg(false, "RcvTask:无法连接到服务器");
					myHandler.sendMessage(msg);
				}
			}
		}

		@Override
		public int getID() {
			return Status.SVRMSG_H;
		}
	}

	/*
	 * 4.心跳
	 */
	class HeartBeatTask implements Runnable, ITask {
		@Override
		public void run() {
			if (Status.isConnected && Status.isLogin) {
				try {
					SendMsg sm = new SendMsg();
					sm.setOpt("HEARTBEAT");
					sm.setUser(Status.username);
					sm.setPassword(Status.password);
					String s = gson.toJson(sm, SendMsg.class);
					mWriter.write(s + "\n");
					mWriter.flush();
				} catch (IOException e) {
					Status.isConnected = false;
					Message msg = new Message();
					msg.what = Status.CONN_H;
					msg.obj = new HandlerMsg(false, "HeartBeatTask:无法连接到服务器");
					myHandler.sendMessage(msg);
				}
			}
		}

		@Override
		public int getID() {
			return Status.HEARTBEAT_H;
		}
	}

	/*
	 * 5.发送消息
	 */
	class sendTask implements Runnable, ITask {
		final String str;

		public sendTask(String str) {
			this.str = str;
		}

		@Override
		public void run() {
			if (Status.isConnected && Status.isLogin) {
				try {
					SendMsg sm = new SendMsg();
					sm.setOpt("MSG");
					sm.setUser(Status.username);
					sm.setPassword(Status.password);
					sm.setTargetUser("");// 暂时这样
					sm.setContent(str);
					String s = gson.toJson(sm, SendMsg.class);
					mWriter.write(s + "\n");
					mWriter.flush();
				} catch (IOException e) {
					Status.isConnected = false;
					Message msg = new Message();
					msg.what = Status.CONN_H;
					msg.obj = new HandlerMsg(false, "sendTask:无法连接到服务器");
					myHandler.sendMessage(msg);
				}
			} else {
				// 发送消息时如果未连接,马上重连
				Status.reConNum = 0;
				addQueue(new connTask());
			}
		}

		@Override
		public int getID() {
			return Status.MSG_H;
		}
	}

}

 

 

界面不贴,很简单一个输入框输消息内容,一个按钮发消息,一个文本框记录log及服务端推过来的消息,只是一个测试demo。

 

经测试:断线重连,连接后自动登录,心跳,发消息都没问题,就是接收服务端推送时有延时,这个没办法,毕竟是间隔读,其实也可以把间隔搞小一点。

一般推送对实时性要求不是很高吧,所以基本上可以用。

其实用BlockingQueue,搞成和asmack那样也可以,我这个也算种思路么,哈哈,记录之。

 

0
0
分享到:
评论

相关推荐

    netty 推送 android客户端

    Netty 是一个高性能、异步事件驱动的网络应用程序框架,常用于开发服务器和客户端的通信应用,如TCP、UDP和HTTP等协议。...在实际项目中,理解并熟练掌握这些知识点对于构建稳定高效的Android推送系统至关重要。

    mqtt协议实现 Android推送(服务端、客户端代码)

    本文将深入探讨如何使用MQTT协议在Android平台上实现推送服务,包括服务端和客户端的代码实现。 一、MQTT协议基础 1. **协议特点**:MQTT设计目标是低开销、低带宽和高可靠性,适用于移动设备和网络条件差的环境。...

    android聊天室客户端与服务端(PC)代码

    7. **推送通知**:为了实时接收新消息,可以集成Firebase Cloud Messaging (FCM) 提供的推送服务。 8. **数据库存储**:本地数据持久化通常使用SQLite数据库,用于存储用户会话、未读消息等信息。 **PC服务器端** ...

    mina及时推送客户端服务端实现

    在"mina及时推送客户端服务端实现"的项目中,我们将会探讨如何利用MINA来实现实时推送功能,并保持客户端和服务端的长连接。 1. **实时推送**:实时推送是现代应用中常见的一种需求,如消息通知、直播互动等。MINA...

    Android MQTT消息推送

    本文将深入探讨Android平台上实现MQTT消息推送的相关知识点。 ### MQTT协议简介 MQTT协议基于TCP/IP协议栈,采用发布/订阅模型。在这个模型中,客户端可以作为发布者发送消息,也可以作为订阅者接收消息。消息主题...

    Android 手机新闻客户端源码

    7. **通知和推送**:为了让用户及时获取新消息,新闻客户端通常会集成推送服务,如Firebase Cloud Messaging (FCM)。开发者需要了解如何配置和使用这些服务。 8. **UI设计和Material Design**:Android提倡使用...

    Android 仿QQ客户端及服务端源码

    5. **消息推送机制**:在仿QQ应用中,可能会使用到长轮询、WebSocket或者GCM/FCM(Google Cloud Messaging / Firebase Cloud Messaging)来实现实时消息推送。 6. **数据库操作**:SQLite是Android内置的轻量级...

    Android推送聊天

    综上所述,基于百度云推送实现的Android推送聊天涉及到多个技术环节,包括服务的集成、消息模型的设计、用户界面的构建以及性能优化等多个方面。开发者需要对Android系统、网络通信、安全机制以及用户体验有深入理解...

    android CSDN新闻客户端

    8. **推送通知**:为了让用户及时获取新内容,应用可能集成了推送服务,如Firebase Cloud Messaging(FCM)或其他第三方推送服务。 9. **测试与调试**:开发过程中,单元测试、集成测试和UI测试是必不可少的,JUnit...

    Android-一个符合GoogleMaterialDesign的Android校园新闻客户端

    5. **通知与推送**:可能有实现即时新闻推送的功能,这涉及到Firebase Cloud Messaging (FCM) 或其他推送服务的集成。 6. **用户界面**:设计和实现用户友好的交互,如滑动刷新、下拉加载更多等。 7. **权限管理**...

    基于Netty框架的Android内网推送demo

    总的来说,"基于Netty框架的Android内网推送demo"提供了一个基础的Android内网通信模型,开发者可以在此基础上根据具体需求进行扩展,实现更复杂的功能,例如多用户聊天、实时游戏同步等。通过学习和理解这个Demo,...

    Android代码-仿QQ客户端及服务端源码.zip

    4. Android推送服务:如Google的Firebase Cloud Messaging (FCM),用于实现实时消息推送,提高用户体验。 通过对这个仿QQ客户端及服务端源码的学习,开发者不仅能了解Android应用的基本架构,还能深入理解即时通讯...

    push(实现消息推送)

    在IT行业中,消息推送是一项关键的技术,...综上所述,"push(实现消息推送)"项目涵盖了服务器端推送服务的实现和Android客户端的集成,涉及到网络通信、推送协议、消息处理等多个方面,是移动应用开发中的重要技术。

    仿android网易新闻客户端完美实现

    8. **通知与推送**: 如果需要实现实时新闻更新通知,可以集成Firebase Cloud Messaging (FCM) 或其他推送服务。 9. **权限管理**: 根据Android权限模型,可能需要请求用户授予网络访问权限。 10. **UI优化**: 为了...

    MQTT方式实现Android推送服务器端

    在Android推送服务中,MQTT可以作为高效、可靠的数据推送机制,尤其适合电量和网络资源有限的设备。 在“MQTT方式实现Android推送服务器端”这个主题中,我们需要关注以下几个关键知识点: 1. **MQTT协议原理**:...

    安卓消息推送服务器端和客户端.rar

    总结,这个压缩包中的源码可以帮助开发者理解如何实现一个完整的Android消息推送系统,包括服务器端的构建和客户端的集成。通过学习并修改这些源码,开发者可以快速地在自己的应用中实现类似功能,提高用户体验。...

    Android-fpush-基于Nettyprotobuf实现的即时消息推送服务

    在"Android-fpush"项目中,服务器端主要负责接收消息、处理消息并推送给客户端。这通常包括以下几个关键步骤: 1. 客户端建立连接:客户端使用Netty客户端模块与服务器建立长连接。 2. 消息编码与解码:使用protobuf...

    Android mqtt协议 推送

    `AndroidPushNotifications.zip`可能包含了如何结合MQTT协议发送Android推送通知的示例。当收到MQTT消息时,应用可以触发系统级的通知,让用户知道新消息的到来。这通常涉及到使用`NotificationCompat.Builder`创建...

Global site tag (gtag.js) - Google Analytics