zoukankan      html  css  js  c++  java
  • Android

    前几天学习了 Android 下 Socket 编程,由于个人是刚开始学习 Android 相应的知识。所以特意将学习中的代码与过程,写成 BLOG,如:http://blog.csdn.net/91program/article/details/39177401
    学习 Socket 编程是有目的的,需要完成在手机与 PC 之间的通讯。通讯的内容是将手机上播放的 MP3 信息,通过 Socket 传输到 PC 端。
    在参考网上相关 Socket 的文章后,基本上完成了 Socket 功能。所以就继续学习 Android 下音乐播放器的实现。在实现音乐播放器过程中,发现由于音乐播放器至少要有播放列表和正在播放两个 Activity,这样问题就来了:
    (1). Socket 只是在第一个 Activity 中实现了,当这个 Activity 活动时没有问题。但此 Activity 非活动时,不能处理 Socket。
    (2). 当反复进入第一个 Activity 时,会出现 Socket 初始化报错的问题。出现这样的错误,是由于 Sokcet 的初始化放在第一个 Activity 的 onCreate 中。

    由于在做音乐播放器时使用了 Service,所以想到用 Serivce 来处理 Socket 应该没有问题。但是否有其它的方法呢?由于个人是刚刚接触 Android 编程,就不能确定这个问题了!
    在 CSDN Android 论坛提问,帖子:http://bbs.csdn.net/topics/390884423。得到的答案是:(1) Serivce; (2) 也可以更改activity的启动方式,让串口不重复创建。显然,第二种方法还没有接触过。采用第一种 Serivce 来实现更可靠一些。

    首先,实现 Socket Service。

    package com.jia.leozhengfirstapp;
    
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.UnsupportedEncodingException;
    import java.net.ServerSocket;
    import java.net.Socket;
    
    
    import android.app.Service;
    import android.content.BroadcastReceiver;
    import android.content.Context;
    import android.content.Intent;
    import android.content.IntentFilter;
    import android.os.IBinder;
    import android.util.Log;
    
    
    public class SocketService extends Service {
    
    
      private Socket clientSocket = null;
      private ServerSocket mServerSocket = null;
    
    
      private SocketAcceptThread socketAcceptThread = null;
      private SocketReceiveThread socketReceiveThread = null;
    
    
      private SocketReceiver socketReceiver;
    
    
      public static final String SOCKER_ACTION = "com.jia.Socket.Control";
      public static final String SOCKER_RCV = "com.jia.Socket.ReceiveStr";
    
    
      private boolean stop = true;
    
    
      @Override
      public IBinder onBind(Intent intent) {
        // TODO Auto-generated method stub
        return null;
      }
       @Override
      public void onCreate() {
              super.onCreate();
              Log.d("service", "socket service created");
              socketReceiver = new SocketReceiver();
              IntentFilter filter = new IntentFilter();
              filter.addAction(SOCKER_ACTION);
              registerReceiver(socketReceiver, filter);
    
    
              socketAcceptThread = new SocketAcceptThread();
                // 开启 Socket 监听线程
                socketAcceptThread.start();
       }
    
    
      @Override
      public void onStart(Intent intent, int startId) {
         Log.d("service", "socket service start");
    
    
      }
    
    
      @Override
      public void onDestroy() {
      Log.d("service", "socket service destroy!");
    
    
      }
    
    
      public class SocketReceiver extends BroadcastReceiver {
    
    
        @Override
        public void onReceive(Context context, Intent intent) {
          String action = intent.getAction();
                if(action.equals(SOCKER_ACTION)) {
                  String sub_action = intent.getExtras().getString("ACTION");
                  if(sub_action.equals("reconnect")) {
                    Log.d("service", "socket service: reconnect.");
    
    
                     socketAcceptThread = new SocketAcceptThread();
                      // 开启 Socket 监听线程
                      socketAcceptThread.start();
                  }
                }
        }
      }
    
    
      private class SocketAcceptThread extends Thread
      {
           @Override
           public void run()
           {
             Log.d("service", "socket service - SocketAcceptThread::run");
               try {
                   // 实例化ServerSocket对象并设置端口号为 12589
                   mServerSocket = new ServerSocket(12589);
               } catch (IOException e) {
                   // TODO Auto-generated catch block
                   e.printStackTrace();
               }
    
    
               try {
                   // 等待客户端的连接(阻塞)
                   clientSocket = mServerSocket.accept();
               } catch (IOException e) {
                   // TODO Auto-generated catch block
                   e.printStackTrace();
               }
    
    
               socketReceiveThread = new SocketReceiveThread(clientSocket);
               stop = false;
               // 开启接收线程
               socketReceiveThread.start();
    
    
                 Intent sendIntent = new Intent(SOCKER_RCV);
                 sendIntent.putExtra("action", "ClientIP");
                 sendIntent.putExtra("content", clientSocket.getInetAddress().getHostAddress());
                 // 发送广播,将被Activity组件中的BroadcastReceiver接收到
                 sendBroadcast(sendIntent);
           }
       }
    
    
       private class SocketReceiveThread extends Thread
       {
           private InputStream mInputStream = null;
           private byte[] buf;
           private String str = null;
           Socket sUsed;
    
    
           SocketReceiveThread(Socket s)
           {
             Log.d("service", "socket service - SocketReceiveThread");
               try {
                   // 获得输入流
                   this.mInputStream = s.getInputStream();
                   sUsed = s;
               } catch (IOException e) {
                   // TODO Auto-generated catch block
                   e.printStackTrace();
               }
           }
    
    
           @Override
           public void run()
           {
             Log.d("service", "socket service - SocketReceiveThread::run");
               while((!stop) && (!mServerSocket.isClosed()))
               {
                   this.buf = new byte[2048];
    
    
                   // 读取输入的数据(阻塞读)
                   try {
                       this.mInputStream.read(buf);
                   } catch (IOException e1) {
                       // TODO Auto-generated catch block
                       e1.printStackTrace();
                   }
    
    
                   // 字符编码转换
                   try {
                       this.str = new String(this.buf, "GB2312").trim();
                   } catch (UnsupportedEncodingException e) {
                       // TODO Auto-generated catch block
                       e.printStackTrace();
                   }
    
    
                   Intent sendIntent = new Intent(SOCKER_RCV);
                   sendIntent.putExtra("action", "RcvStr");
                   sendIntent.putExtra("content", this.str);
                   // 发送广播,将被Activity组件中的BroadcastReceiver接收到
                   sendBroadcast(sendIntent);
               }
           }
       }
    }
    

     在每个 Activity 中处理 SOCKER_RCV action,以响应 Socket 状态的变化和接收到数据。
    Service 与 Activity 之间通讯需要使用到广播: Broadcast。
    (1) 在 Activity 中定义全局的变量,如下:

    1 public static final String SOCKER_ACTION = "com.jia.Socket.Control";
    2 public static final String SOCKER_RCV = "com.jia.Socket.ReceiveStr";
    3 
    4 SocketReceiver socketReceiver

    (2) 在 Activity 的 onCreate 中注册广播和启动 Socket Service,如下:

    1 socketReceiver = new SocketReceiver();
    2 IntentFilter socketIntentFilter = new IntentFilter();
    3 socketIntentFilter.addAction(SOCKER_RCV);
    4 registerReceiver(socketReceiver,socketIntentFilter);
    5 
    6 Intent socketIntent = new Intent();
    7 socketIntent.setClass(MainActivity.this, SocketService.class);
    8 startService(socketIntent);       // 启动  Socket 服务

    (3) SocketReceiver 是继承自 BroadcastReceiver 的类,实现如下:

     1 public class SocketReceiver extends BroadcastReceiver {
     2 
     3 
     4   @Override
     5   public void onReceive(Context context, Intent intent) {
     6     // TODO Auto-generated method stub
     7     String action = intent.getAction();
     8           if(action.equals(SOCKER_RCV)) {
     9             String url = intent.getExtras().getString("action");
    10             if(url.equals("ClientIP")) {
    11               String strIP = intent.getExtras().getString("content");
    12             }
    13             else if(url.equals("RcvStr")) {
    14               String strContent = intent.getExtras().getString("content");
    15             }
    16             else if(url.equals("Disconnect")) {
    17               String strContent = intent.getExtras().getString("content");
    18             }
    19         }
    20     }
    21 }

    (4) Socket 功能实现后,测试时发现客户端(也就是 PC 端)断开时手机端未检测到 Socket 连接断开。
    以前使用 WinCE 时,Socket(TCP) 断开时,无论是客户端、还是服务器都可以检测到 TCP 断开的事件,并处理。但 Android 下的 Socket 编程机制竟然没有这个东东。
    一,测试时发现当 PC 端断开后,手机端的服务程序在执行到下面的代码段时不会阻塞,且函数的返回值是: -1。
    二,在网上查找发现这个问题是 Android 下 Socket 都有的问题,可以通过发心跳包来处理。
    所以将下面这段代码:

     1 // 读取输入的数据(阻塞读)
     2 try {
     3     this.mInputStream.read(buf);
     4 } catch (IOException e1) {
     5     // TODO Auto-generated catch block
     6     e1.printStackTrace();
     7 }
     8 修改为如下的代码:
     9 try {
    10     int length = this.mInputStream.read(buf);
    11     if(-1 == length) {
    12       try {
    13         sUsed.sendUrgentData(0xff);
    14       }
    15       catch(Exception ex) {
    16         // 链接已断开
    17         Log.v("service", "disconnect!!!");
    18         stop = true;
    19         if(null != mServerSocket) {
    20           mServerSocket.close();
    21         }
    22 
    23 
    24         Intent sendIntent = new Intent(SOCKER_RCV);
    25         sendIntent.putExtra("action", "Disconnect");
    26         sendIntent.putExtra("content", "read is -1 & Urgent Exception!");
    27         sendBroadcast(sendIntent);
    28 
    29 
    30         continue;
    31       }
    32     }
    33 } catch (IOException e1) {
    34     // TODO Auto-generated catch block
    35     e1.printStackTrace();
    36 }
  • 相关阅读:
    python 中 repr() 与str() 区别
    python高级特性 知识 架构总结
    python 递归 之加特技 汉诺塔
    python 递归 反转字符串
    git 的使用
    vim 常用命令
    ubuntu下零基础建站之python基础环境搭建
    Oracle 分组统计,抽取每组前十
    SQL Server2008知识点总结
    java 连接sql server2008配置
  • 原文地址:https://www.cnblogs.com/91program/p/5190839.html
Copyright © 2011-2022 走看看