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 联网交互的更多相关文章

  1. android Service中多线程交互

    android 的service和activity是执行在UI主线程的. 在android线程中,仅仅有主线程即UI线程有自己的默认的消息队列.子线程须要创建自己的消息队列.并把消息发给队列,并循环起 ...

  2. android开发之使用Messenger实现service与activity交互

    service与activity交互的方式有多种,这里说说使用Messenger来实现两者之间的交互. Service程序 public class MessengerService extends ...

  3. Android 之 Socket 通信

    Android 之 Socket 通信 联系一下 Socket 编程,之后需要将一个 JavaEE 项目移植到 Android,暂时现尝试写一个简单的 DEMO,理解一下 Socket Server ...

  4. 【Android】详解Android Service

    目录结构: contents structure [+] Service简单概述 Service在清单文件中的声明 Service启动服务 Service绑定服务 扩展Binder类 使用Messen ...

  5. android service 的各种用法(IPC、AIDL)

    http://my.oschina.net/mopidick/blog/132325 最近在学android service,感觉终于把service的各种使用场景和用到的技术整理得比较明白了,受益颇 ...

  6. Android service介绍和启动方式

    1.Android service的作用: service通常是用来处理一些耗时操作,或后台执行不提供用户交互界面的操作,例如:下载.播放音乐. 2.Android service的生命周期: ser ...

  7. Android中Socket大文件断点上传

    原文:http://blog.csdn.net/shimiso/article/details/8529633 什么是Socket? 所谓Socket通常也称作“套接字”,用于描述IP地址和端口,是一 ...

  8. Android Service 详解

    一个Service也是一种应用程序组件,它运行在后台以提供某种服务,通常不具有可见的用户界面.其它的应用程序组件可以启动一个 Service,即使在用户切换到另外一个应用程序后,这个Service还是 ...

  9. Android Service组件(1)

    android service 和其他服务一样,并没有实际运行的界面,它运行在android 后台.一般通过service为应用程序提供服务(比如,从Internet下载文件,控制音乐播放器等).Se ...

随机推荐

  1. Unity 2D游戏开发教程之为游戏场景添加多个地面

    Unity 2D游戏开发教程之为游戏场景添加多个地面 为游戏场景添加多个地面 显然,只有一个地面的游戏场景太小了,根本不够精灵四处活动的.那么,本节就来介绍一种简单的方法,可以为游戏场景添加多个地面. ...

  2. php获取当前域名、主机、URL、端口、参数、网址、路径、代理等【转】

    <?php //获取域名或主机地址 echo $_SERVER['HTTP_HOST']."<br />"; //获取网页地址 echo $_SERVER['PH ...

  3. C和指针之学习笔记(5)

    第10章 使用结构和指针 单链表 typedef struct NODE { struct NODE *link; int value; } Node; 插入到一个有序单链表: #include< ...

  4. [BZOJ4825][HNOI2017]单旋(线段树+Splay)

    4825: [Hnoi2017]单旋 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 667  Solved: 342[Submit][Status][ ...

  5. 【四边形不等式】POJ1160[IOI2000]-Post Office

    [题目大意] v个村庄p个邮局,邮局在村庄里,给出村庄的位置,求每个村庄到最近邮局距离之和的最小值. [思路] 四边形不等式,虽然我并不会证明:( dp[i][j]表示前i个村庄建j个邮局的最小值,w ...

  6. Shell脚本:“syntax error:unexpected end of file”

    这种错误只能说是坑,如果没有见到过,很可能就要摔里头.解决问题是重要的,但弄明白问题的来源,往往更为重要. 所以要先扯一下,换行和回车的历史遗留问题. 在计算机出现之前,有个玩意叫电传打字机.每秒钟可 ...

  7. bzoj 1012 BST 支持插入,区间最大

    水... /************************************************************** Problem: 1012 User: idy002 Lang ...

  8. IOS http 请求

    asihttprequest 为第三方数据请求,一下为get  和post 两种请求. Get: NSString *loginName=@"Tony"; NSString *pw ...

  9. keystone 命令简要说明

    catalog: keystone catalog 可以显示所有已有的service keystone catalog --service service-type 显示某个service信息 end ...

  10. iOS学习之sqlite的创建数据库,表,插入查看数据

    目录(?)[-] 新建项目sqliteDemo添加使用sqlite的库libsqlite3dylib sqlite 的方法 获取沙盒目录并创建或打开数据库 创建数据表 插入数据 查询数据库并打印数据 ...