Android Service+Socket 联网交互
android中,联网操作有http连接和socket连接两大类。由于项目需要,我们采取的是Socket连接。鉴于平时连接频繁,因此把Socket连接放到Service里,需要从服务器端获取数据时,只要调用Service中相应方法即可。
Service大致结构是:
public class InternetService extends Service implements Runnable {
private Socket socket;
private BufferedReader reader;//
private PrintWriter writer;//
private Binder binder;
private Thread td;// 线程,获取服务器端发送来的消息
private String workStatus;// 当前工作状况,null表示正在处理,success表示处理成功,failure表示处理失败
private String currAction; //标记当前请求头信息,在获取服务器端反馈的数据后,进行验证,以免出现反馈信息和当前请求不一致问题。比如现在发送第二个请求,但服务器端此时才响应第一个请求
/**
* 向服务器发送请求
*
* @param action
*
*/
public void sendRequest(String action) {
try {
workStatus = null;
JSONObject json = new JSONObject();
json.put("action", action);
currAction=action;
sendMessage(json);
} catch (Exception ex) {
workStatus = Constant.TAG_FAILURE;
ex.printStackTrace();
}
}
/**
* 返回当前workStatus的值
* /
public StringgetWorkStatus()
{
return workStatus ;
}
/**
* 处理服务器端反馈的数据
*
* @param json
*
*/
private void dealUploadSuperviseTask(JSONObject json)
{
try{
workStatus=json.getString("result");
}catch(Exception ex)
{
ex.printStackTrace();
workStatus=Constant.TAG_FAILURE;
}
}
/**
* 退出程序时,关闭Socket连接
*/
public void closeConnection() {
JSONObject json = new JSONObject();// 向服务器端发送断开连接请求
try {
json.put("action", "exit");
sendMessage(json);// 向服务器端发送断开连接请求
Log.v("qlq", "the request is " + json.toString());
} catch (Exception ex) {
ex.printStackTrace();
}
}
/**
* 连接服务器
*/
private void connectService() {
try {
socket = new Socket();
SocketAddress socAddress = new InetSocketAddress(127.0.0,
8000));
socket.connect(socAddress, 3000);
reader = new BufferedReader(new InputStreamReader(
socket.getInputStream(), "GBK"));
writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(
socket.getOutputStream(), "GBK")), true);
} catch (SocketException ex) {
Log.v("QLQ", "socketException ");
ex.printStackTrace();
workStatus = Constant.TAG_CONNECTFAILURE;// 如果是网络连接出错了,则提示网络连接错误
return;
} catch (SocketTimeoutException ex) {
ex.printStackTrace();
workStatus = Constant.TAG_CONNECTFAILURE;// 如果是网络连接出错了,则提示网络连接错误
return;
} catch (Exception ex) {
ex.printStackTrace();
workStatus = Constant.TAG_CONNECTFAILURE;// 如果是网络连接出错了,则提示网络连接错误
return;
}
}
/**
* 向服务器发送传入的JSON数据信息
*
* @param json
*/
private void sendMessage(JSONObject json) {
if (!isNetworkConnected())// 如果当前网络连接不可用,直接提示网络连接不可用,并退出执行。
{
Log.v("QLQ", "workStatus is not connected!111");
workStatus = Constant.TAG_CONNECTFAILURE;
return;
}
if (socket == null)// 如果未连接到服务器,创建连接
connectService();
if (!InternetService.this.td.isAlive())// 如果当前线程没有处于存活状态,重启线程
(td = new Thread(InternetService.this)).start();
if (!socket.isConnected() || (socket.isClosed())) // isConnected()返回的是是否曾经连接过,isClosed()返回是否处于关闭状态,只有当isConnected()返回true,isClosed()返回false的时候,网络处于连接状态
{
Log.v("QLQ", "workStatus is not connected!111222");
for (int i = 0; i < 3 && workStatus == null; i++) {// 如果连接处于关闭状态,重试三次,如果连接正常了,跳出循环
socket = null;
connectService();
if (socket.isConnected() && (!socket.isClosed())) {
Log.v("QLQ", "workStatus is not connected!11333");
break;
}
}
if (!socket.isConnected() || (socket.isClosed()))// 如果此时连接还是不正常,提示错误,并跳出循环
{
workStatus = Constant.TAG_CONNECTFAILURE;
Log.v("QLQ", "workStatus is not connected!111444");
return;
}
}
if (!socket.isOutputShutdown()) {// 输入输出流是否关闭
try {
writer.println(json.toString());
} catch (Exception e) {
// TODO Auto-generated catch block
Log.v("QLQ", "workStatus is not connected!55555666666");
e.printStackTrace();
workStatus = Constant.TAG_FAILURE;
}
} else {
workStatus = Constant.TAG_CONNECTFAILURE;
}
}
/**
* 处理服务器端传来的消息,并通过action头信息判断,传递给相应处理方法
*
* @param str
*/
private void getMessage(String str) {
try {
JSONObject json = new JSONObject(str);
String action = json.getString("action");// 提取JSON的action信息,获取当前JSON响应的是哪个操作。
if(!currAction.equals(action))
return;
if (action.equals("getCategory")) {
dealUploadSuperviseTask(json);
}
} catch (Exception ex) {
ex.printStackTrace();
workStatus=Constant.TAG_FAILURE;
}
}
public class InterBinder extends Binder {
public InternetService getService() {
return InternetService.this;
}
}
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
binder = new InterBinder();
td = new Thread(InternetService.this);// 启动线程
td.start();
return binder;
}
@Override
public void onCreate() {
super.onCreate();
// connectService();
}
@Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.v("QLQ", "Service is on destroy");
}
@Override
public boolean onUnbind(Intent intent) {
Log.v("QLQ", "service on onUnbind");
return super.onUnbind(intent);
}
/**
* 循环,接收从服务器端传来的数据
*/
public void run() {
try {
while (true) {
Thread.sleep(500);// 休眠0.5s
if (socket != null && !socket.isClosed()) {// 如果socket没有被关闭
if (socket.isConnected()) {// 判断socket是否连接成功
if (!socket.isInputShutdown()) {
String content;
if ((content = reader.readLine()) != null) {
getMessage(content);
}
}
}
}
}
} catch (Exception ex) {
try {
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
workStatus = Constant.TAG_CONNECTFAILURE;// 如果出现异常,提示网络连接出现问题。
ex.printStackTrace();
}
}
}
在前台页面上,由于前台和后台要进行数据交互,因此需要使用bindService方法绑定服务。
InternetService innetService ;
public ServiceConnection internetServiceConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName arg0, IBinder service) {
innetService = ((InternetService.InterBinder) service).getService();
}
public void onServiceDisconnected(ComponentName arg0) {
innetService = null;
}
};
然后在onCreate里,执行
bindService(new Intent(BasicActivity.this, InternetService.class),
internetServiceConnection, Context.BIND_AUTO_CREATE);//BasicActivity是我自己为所有Activity定义的基类,这段代码也是写在BasicActivity里。
由于服务绑定后必须要解除,因此在onDestroy中应加上代码
unbindService(internetServiceConnection);
之所以定义workStatus,是为了让前台知道当前联网操作是否成功。
而定义currAction,则是为了标识好当前请求内容,由于服务器端反馈的信息上也有action头信息标识当前返回的数据对应哪种请求,所以,在发送请求时设置currAction,接收到服务器端反馈数据后,验证和currAction是否一致,如果不一致的话,就不作处理,表示“未等到希望的数据”,如果一致,才能执行下一步操作。这样可以防止数据匹配错误。
至于定义BasicActivity,则是因为软件中很多页面除了中间显示的内容外,头部按钮栏等都一致,此外还有很多共用的代码等,因此定义一个BasicActivity,作为他们的父类,减少代码量,这也是java多态的一种体现。
Android Service+Socket 联网交互的更多相关文章
- android Service中多线程交互
android 的service和activity是执行在UI主线程的. 在android线程中,仅仅有主线程即UI线程有自己的默认的消息队列.子线程须要创建自己的消息队列.并把消息发给队列,并循环起 ...
- android开发之使用Messenger实现service与activity交互
service与activity交互的方式有多种,这里说说使用Messenger来实现两者之间的交互. Service程序 public class MessengerService extends ...
- Android 之 Socket 通信
Android 之 Socket 通信 联系一下 Socket 编程,之后需要将一个 JavaEE 项目移植到 Android,暂时现尝试写一个简单的 DEMO,理解一下 Socket Server ...
- 【Android】详解Android Service
目录结构: contents structure [+] Service简单概述 Service在清单文件中的声明 Service启动服务 Service绑定服务 扩展Binder类 使用Messen ...
- android service 的各种用法(IPC、AIDL)
http://my.oschina.net/mopidick/blog/132325 最近在学android service,感觉终于把service的各种使用场景和用到的技术整理得比较明白了,受益颇 ...
- Android service介绍和启动方式
1.Android service的作用: service通常是用来处理一些耗时操作,或后台执行不提供用户交互界面的操作,例如:下载.播放音乐. 2.Android service的生命周期: ser ...
- Android中Socket大文件断点上传
原文:http://blog.csdn.net/shimiso/article/details/8529633 什么是Socket? 所谓Socket通常也称作“套接字”,用于描述IP地址和端口,是一 ...
- Android Service 详解
一个Service也是一种应用程序组件,它运行在后台以提供某种服务,通常不具有可见的用户界面.其它的应用程序组件可以启动一个 Service,即使在用户切换到另外一个应用程序后,这个Service还是 ...
- Android Service组件(1)
android service 和其他服务一样,并没有实际运行的界面,它运行在android 后台.一般通过service为应用程序提供服务(比如,从Internet下载文件,控制音乐播放器等).Se ...
随机推荐
- Python开发基础-Day25-28FTP项目(待补充)
optparse C:\Users\Mr.chai>python C:/Users/Mr.chai/Desktop/PythonProject/DAY/day27/LuffyFTP/client ...
- Codeforces 798D
这两天后缀数组整多了整点有意思的,随机算法. 题意给你两个数组,让你求一个排列使得这个排列对应的两个数组前n/2+1个数之和的二倍大于每个序列总和. 下面先贴下这题正解 二维贪心,按a从大到小排,把第 ...
- Codeforces 160 D. Edges in MST
\(>Codeforces \space 160 D. Edges in MST<\) 题目大意 : 给出一张带权无向图,求对于这张图上的每一条边,其是必然存在于每一种最小生成树中,还是至 ...
- [Codeforces 1060F] Shrinking Tree
Link: 传送门 Solution: 原来CF的官方题解也能鸽啊…… 详细题解 该题思路: 1.对于每个点删边方案数为$fac[n-1]$,总贡献为每种方案下满足的概率的和,接下来直接求贡献 2.每 ...
- WordPress插件会员简化1.58 -任意文件下载漏洞(附poc)
今天我们将讨论在WordPress插件WordPress插件与重点会员简化v1.58作为这个剧本的创作时间不打补丁的扶贫开发实践.脆弱脚本如下: CVE-ID:cve-2017-1002008 当然, ...
- bzoj 1468
大概思路:树点分治,重心树中每个重心维护一个总的平衡树,树中保存属于该重心的点到该重心的距离,然后对于去掉该重心后形成的子树分别再保存一份. 用这种方式实现的话,还可以支持修改与多次查询,每次操作都是 ...
- [转]ViewPager 详解(三)---PagerTabStrip与PagerTitleStrip添加标题栏的异同
目录(?)[-] 一PagerTitleStrip Class Overview XML布局文件 重写适配器的getPageTitle函数 变量 初始化 重写CharSequence getPag ...
- unix-软件安装
检查软件是否已经安装 rpm -qa|grep 软件标识名 在线安装软件 yum -y install 软件标识名
- 如果内容很长ueditor编辑辑器怎么出现滚动条
在开发网站的时候,有的页面需要加载ueditor编辑器,如果内容很长,默认设置的时候编辑器会根据内容拉长,而不是页面出现滚动条,如果拖动页面滚条,会比较麻烦,要拖动很长才能看到提交按钮. 如何才能让编 ...
- Pylons Controller里面Session.commit()总是出现rollback
Pylons Controller里面执行修改数据库表,总是不成功. 然后通过各种手段: 1.js打印返回值 2.不修改表单提交和修改表单提交,结果比较: 3.通过在Pylons Controller ...